From c38024e692445622098ef6f453529648f7c792a1 Mon Sep 17 00:00:00 2001 From: Jordan Knott Date: Sun, 19 Apr 2020 22:02:55 -0500 Subject: [PATCH] feature: add ability to assign tasks --- api/graph/generated.go | 2002 +++++++++++++---- api/graph/graph.go | 6 + api/graph/models_gen.go | 54 +- api/graph/schema.graphqls | 83 +- api/graph/schema.resolvers.go | 168 +- ...sql => 0002_add-user_account-table.up.sql} | 3 +- .../0009_add-task-assigned-table.up.sql | 6 + .../0010_add-description-to-task-table.up.sql | 1 + .../0011_add-label-color-table.up.sql | 5 + .../0012-add-task-label-table.up.sql | 6 + .../0013_add-due-date-to-task-table.up.sql | 1 + ...4_add-owner-column-to-project-table.up.sql | 1 + api/pg/label_color.sql.go | 21 + api/pg/models.go | 37 +- api/pg/pg.go | 9 + api/pg/project.sql.go | 20 +- api/pg/querier.go | 7 + api/pg/task.sql.go | 64 +- api/pg/task_assigned.sql.go | 66 + api/pg/task_label.sql.go | 66 + api/pg/user_accounts.sql.go | 30 +- api/query/label_color.sql | 2 + api/query/project.sql | 2 +- api/query/task.sql | 6 + api/query/task_assigned.sql | 6 + api/query/task_label.sql | 6 + api/query/user_accounts.sql | 4 +- api/router/auth.go | 27 +- api/router/middleware.go | 9 +- api/router/models.go | 4 + web/package.json | 2 + web/src/App/BaseStyles.ts | 1 + web/src/App/Navbar.tsx | 7 +- web/src/App/Routes.tsx | 14 +- web/src/App/TopNavbar.tsx | 35 +- web/src/App/context.ts | 9 + web/src/App/index.tsx | 40 +- web/src/Auth/index.tsx | 10 +- web/src/Projects/Project/Details/index.tsx | 110 + web/src/Projects/Project/index.tsx | 115 +- web/src/Projects/index.tsx | 52 +- web/src/citadel.d.ts | 11 + .../DropdownMenu/DropdownMenu.stories.tsx | 3 +- .../shared/components/DropdownMenu/index.tsx | 5 +- .../DueDateManager/DueDateManager.stories.tsx | 2 +- web/src/shared/components/Login/index.tsx | 2 +- .../PopupMenu/PopupMenu.stories.tsx | 12 +- .../components/ProjectGridItem/Styles.ts | 12 +- .../TaskDetails/TaskDetails.stories.tsx | 2 +- .../shared/components/TaskDetails/index.tsx | 13 +- .../TopNavbar/TopNavbar.stories.tsx | 10 +- web/src/shared/components/TopNavbar/index.tsx | 11 +- web/src/shared/generated/graphql.tsx | 387 +++- web/src/shared/graphql/assignTask.graphqls | 10 + web/src/shared/graphql/findProject.graphqls | 10 + web/src/shared/graphql/findTask.graphqls | 20 + web/src/shared/graphql/getProjects.graphqls | 10 +- web/src/shared/graphql/me.graphqls | 9 + .../graphql/updateTaskDescription.graphqls | 5 + web/yarn.lock | 10 + 60 files changed, 2871 insertions(+), 790 deletions(-) rename api/migrations/{0002_add-users-table.up.sql => 0002_add-user_account-table.up.sql} (79%) create mode 100644 api/migrations/0009_add-task-assigned-table.up.sql create mode 100644 api/migrations/0010_add-description-to-task-table.up.sql create mode 100644 api/migrations/0011_add-label-color-table.up.sql create mode 100644 api/migrations/0012-add-task-label-table.up.sql create mode 100644 api/migrations/0013_add-due-date-to-task-table.up.sql create mode 100644 api/migrations/0014_add-owner-column-to-project-table.up.sql create mode 100644 api/pg/label_color.sql.go create mode 100644 api/pg/task_assigned.sql.go create mode 100644 api/pg/task_label.sql.go create mode 100644 api/query/label_color.sql create mode 100644 api/query/task_assigned.sql create mode 100644 api/query/task_label.sql create mode 100644 web/src/App/context.ts create mode 100644 web/src/Projects/Project/Details/index.tsx create mode 100644 web/src/shared/graphql/assignTask.graphqls create mode 100644 web/src/shared/graphql/findTask.graphqls create mode 100644 web/src/shared/graphql/me.graphqls create mode 100644 web/src/shared/graphql/updateTaskDescription.graphqls diff --git a/api/graph/generated.go b/api/graph/generated.go index ba66368..b7f8689 100644 --- a/api/graph/generated.go +++ b/api/graph/generated.go @@ -38,12 +38,12 @@ type Config struct { type ResolverRoot interface { Mutation() MutationResolver - Organization() OrganizationResolver Project() ProjectResolver Query() QueryResolver Task() TaskResolver TaskGroup() TaskGroupResolver - Team() TeamResolver + TaskLabel() TaskLabelResolver + UserAccount() UserAccountResolver } type DirectiveRoot struct { @@ -61,7 +61,8 @@ type ComplexityRoot struct { } Mutation struct { - CreateOrganization func(childComplexity int, input NewOrganization) int + AddTaskLabel func(childComplexity int, input *AddTaskLabelInput) int + AssignTask func(childComplexity int, input *AssignTaskInput) int CreateProject func(childComplexity int, input NewProject) int CreateRefreshToken func(childComplexity int, input NewRefreshToken) int CreateTask func(childComplexity int, input NewTask) int @@ -71,34 +72,43 @@ type ComplexityRoot struct { DeleteTask func(childComplexity int, input DeleteTaskInput) int DeleteTaskGroup func(childComplexity int, input DeleteTaskGroupInput) int LogoutUser func(childComplexity int, input LogoutUser) int + RemoveTaskLabel func(childComplexity int, input *RemoveTaskLabelInput) int + UpdateTaskDescription func(childComplexity int, input UpdateTaskDescriptionInput) int UpdateTaskGroupLocation func(childComplexity int, input NewTaskGroupLocation) int UpdateTaskLocation func(childComplexity int, input NewTaskLocation) int UpdateTaskName func(childComplexity int, input UpdateTaskName) int } - Organization struct { - CreatedAt func(childComplexity int) int - Name func(childComplexity int) int - OrganizationID func(childComplexity int) int - Teams func(childComplexity int) int + ProfileIcon struct { + Initials func(childComplexity int) int + URL func(childComplexity int) int } Project struct { CreatedAt func(childComplexity int) int + Members func(childComplexity int) int Name func(childComplexity int) int + Owner func(childComplexity int) int ProjectID func(childComplexity int) int TaskGroups func(childComplexity int) int - TeamID func(childComplexity int) int + Team func(childComplexity int) int + } + + ProjectMember struct { + FirstName func(childComplexity int) int + LastName func(childComplexity int) int + ProfileIcon func(childComplexity int) int + UserID func(childComplexity int) int } Query struct { - FindProject func(childComplexity int, input FindProject) int - FindUser func(childComplexity int, input FindUser) int - Organizations func(childComplexity int) int - Projects func(childComplexity int, input *ProjectsFilter) int - TaskGroups func(childComplexity int) int - Teams func(childComplexity int) int - Users func(childComplexity int) int + FindProject func(childComplexity int, input FindProject) int + FindTask func(childComplexity int, input FindTask) int + FindUser func(childComplexity int, input FindUser) int + Me func(childComplexity int) int + Projects func(childComplexity int, input *ProjectsFilter) int + TaskGroups func(childComplexity int) int + Users func(childComplexity int) int } RefreshToken struct { @@ -109,11 +119,14 @@ type ComplexityRoot struct { } Task struct { - CreatedAt func(childComplexity int) int - Name func(childComplexity int) int - Position func(childComplexity int) int - TaskGroup func(childComplexity int) int - TaskID func(childComplexity int) int + Assigned func(childComplexity int) int + CreatedAt func(childComplexity int) int + Description func(childComplexity int) int + Labels func(childComplexity int) int + Name func(childComplexity int) int + Position func(childComplexity int) int + TaskGroup func(childComplexity int) int + TaskID func(childComplexity int) int } TaskGroup struct { @@ -125,17 +138,24 @@ type ComplexityRoot struct { Tasks func(childComplexity int) int } + TaskLabel struct { + ColorHex func(childComplexity int) int + LabelColorID func(childComplexity int) int + TaskLabelID func(childComplexity int) int + } + Team struct { CreatedAt func(childComplexity int) int Name func(childComplexity int) int - Projects func(childComplexity int) int TeamID func(childComplexity int) int } UserAccount struct { CreatedAt func(childComplexity int) int - DisplayName func(childComplexity int) int Email func(childComplexity int) int + FirstName func(childComplexity int) int + LastName func(childComplexity int) int + ProfileIcon func(childComplexity int) int UserID func(childComplexity int) int Username func(childComplexity int) int } @@ -144,45 +164,53 @@ type ComplexityRoot struct { type MutationResolver interface { CreateRefreshToken(ctx context.Context, input NewRefreshToken) (*pg.RefreshToken, error) CreateUserAccount(ctx context.Context, input NewUserAccount) (*pg.UserAccount, error) - CreateOrganization(ctx context.Context, input NewOrganization) (*pg.Organization, error) CreateTeam(ctx context.Context, input NewTeam) (*pg.Team, error) CreateProject(ctx context.Context, input NewProject) (*pg.Project, error) CreateTaskGroup(ctx context.Context, input NewTaskGroup) (*pg.TaskGroup, error) UpdateTaskGroupLocation(ctx context.Context, input NewTaskGroupLocation) (*pg.TaskGroup, error) DeleteTaskGroup(ctx context.Context, input DeleteTaskGroupInput) (*DeleteTaskGroupPayload, error) + AddTaskLabel(ctx context.Context, input *AddTaskLabelInput) (*pg.Task, error) + RemoveTaskLabel(ctx context.Context, input *RemoveTaskLabelInput) (*pg.Task, error) CreateTask(ctx context.Context, input NewTask) (*pg.Task, error) + UpdateTaskDescription(ctx context.Context, input UpdateTaskDescriptionInput) (*pg.Task, error) UpdateTaskLocation(ctx context.Context, input NewTaskLocation) (*pg.Task, error) UpdateTaskName(ctx context.Context, input UpdateTaskName) (*pg.Task, error) DeleteTask(ctx context.Context, input DeleteTaskInput) (*DeleteTaskPayload, error) + AssignTask(ctx context.Context, input *AssignTaskInput) (*pg.Task, error) LogoutUser(ctx context.Context, input LogoutUser) (bool, error) } -type OrganizationResolver interface { - Teams(ctx context.Context, obj *pg.Organization) ([]pg.Team, error) -} type ProjectResolver interface { - TeamID(ctx context.Context, obj *pg.Project) (string, error) - + Team(ctx context.Context, obj *pg.Project) (*pg.Team, error) + Owner(ctx context.Context, obj *pg.Project) (*ProjectMember, error) TaskGroups(ctx context.Context, obj *pg.Project) ([]pg.TaskGroup, error) + Members(ctx context.Context, obj *pg.Project) ([]ProjectMember, error) } type QueryResolver interface { - Organizations(ctx context.Context) ([]pg.Organization, error) Users(ctx context.Context) ([]pg.UserAccount, error) FindUser(ctx context.Context, input FindUser) (*pg.UserAccount, error) FindProject(ctx context.Context, input FindProject) (*pg.Project, error) - Teams(ctx context.Context) ([]pg.Team, error) + FindTask(ctx context.Context, input FindTask) (*pg.Task, error) Projects(ctx context.Context, input *ProjectsFilter) ([]pg.Project, error) TaskGroups(ctx context.Context) ([]pg.TaskGroup, error) + Me(ctx context.Context) (*pg.UserAccount, error) } type TaskResolver interface { TaskGroup(ctx context.Context, obj *pg.Task) (*pg.TaskGroup, error) + + Description(ctx context.Context, obj *pg.Task) (*string, error) + Assigned(ctx context.Context, obj *pg.Task) ([]ProjectMember, error) + Labels(ctx context.Context, obj *pg.Task) ([]pg.TaskLabel, error) } type TaskGroupResolver interface { ProjectID(ctx context.Context, obj *pg.TaskGroup) (string, error) Tasks(ctx context.Context, obj *pg.TaskGroup) ([]pg.Task, error) } -type TeamResolver interface { - Projects(ctx context.Context, obj *pg.Team) ([]pg.Project, error) +type TaskLabelResolver interface { + ColorHex(ctx context.Context, obj *pg.TaskLabel) (string, error) +} +type UserAccountResolver interface { + ProfileIcon(ctx context.Context, obj *pg.UserAccount) (*ProfileIcon, error) } type executableSchema struct { @@ -228,17 +256,29 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.DeleteTaskPayload.TaskID(childComplexity), true - case "Mutation.createOrganization": - if e.complexity.Mutation.CreateOrganization == nil { + case "Mutation.addTaskLabel": + if e.complexity.Mutation.AddTaskLabel == nil { break } - args, err := ec.field_Mutation_createOrganization_args(context.TODO(), rawArgs) + args, err := ec.field_Mutation_addTaskLabel_args(context.TODO(), rawArgs) if err != nil { return 0, false } - return e.complexity.Mutation.CreateOrganization(childComplexity, args["input"].(NewOrganization)), true + return e.complexity.Mutation.AddTaskLabel(childComplexity, args["input"].(*AddTaskLabelInput)), true + + case "Mutation.assignTask": + if e.complexity.Mutation.AssignTask == nil { + break + } + + args, err := ec.field_Mutation_assignTask_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Mutation.AssignTask(childComplexity, args["input"].(*AssignTaskInput)), true case "Mutation.createProject": if e.complexity.Mutation.CreateProject == nil { @@ -348,6 +388,30 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.Mutation.LogoutUser(childComplexity, args["input"].(LogoutUser)), true + case "Mutation.removeTaskLabel": + if e.complexity.Mutation.RemoveTaskLabel == nil { + break + } + + args, err := ec.field_Mutation_removeTaskLabel_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Mutation.RemoveTaskLabel(childComplexity, args["input"].(*RemoveTaskLabelInput)), true + + case "Mutation.updateTaskDescription": + if e.complexity.Mutation.UpdateTaskDescription == nil { + break + } + + args, err := ec.field_Mutation_updateTaskDescription_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Mutation.UpdateTaskDescription(childComplexity, args["input"].(UpdateTaskDescriptionInput)), true + case "Mutation.updateTaskGroupLocation": if e.complexity.Mutation.UpdateTaskGroupLocation == nil { break @@ -384,33 +448,19 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.Mutation.UpdateTaskName(childComplexity, args["input"].(UpdateTaskName)), true - case "Organization.createdAt": - if e.complexity.Organization.CreatedAt == nil { + case "ProfileIcon.initials": + if e.complexity.ProfileIcon.Initials == nil { break } - return e.complexity.Organization.CreatedAt(childComplexity), true + return e.complexity.ProfileIcon.Initials(childComplexity), true - case "Organization.name": - if e.complexity.Organization.Name == nil { + case "ProfileIcon.url": + if e.complexity.ProfileIcon.URL == nil { break } - return e.complexity.Organization.Name(childComplexity), true - - case "Organization.organizationID": - if e.complexity.Organization.OrganizationID == nil { - break - } - - return e.complexity.Organization.OrganizationID(childComplexity), true - - case "Organization.teams": - if e.complexity.Organization.Teams == nil { - break - } - - return e.complexity.Organization.Teams(childComplexity), true + return e.complexity.ProfileIcon.URL(childComplexity), true case "Project.createdAt": if e.complexity.Project.CreatedAt == nil { @@ -419,6 +469,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.Project.CreatedAt(childComplexity), true + case "Project.members": + if e.complexity.Project.Members == nil { + break + } + + return e.complexity.Project.Members(childComplexity), true + case "Project.name": if e.complexity.Project.Name == nil { break @@ -426,6 +483,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.Project.Name(childComplexity), true + case "Project.owner": + if e.complexity.Project.Owner == nil { + break + } + + return e.complexity.Project.Owner(childComplexity), true + case "Project.projectID": if e.complexity.Project.ProjectID == nil { break @@ -440,12 +504,40 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.Project.TaskGroups(childComplexity), true - case "Project.teamID": - if e.complexity.Project.TeamID == nil { + case "Project.team": + if e.complexity.Project.Team == nil { break } - return e.complexity.Project.TeamID(childComplexity), true + return e.complexity.Project.Team(childComplexity), true + + case "ProjectMember.firstName": + if e.complexity.ProjectMember.FirstName == nil { + break + } + + return e.complexity.ProjectMember.FirstName(childComplexity), true + + case "ProjectMember.lastName": + if e.complexity.ProjectMember.LastName == nil { + break + } + + return e.complexity.ProjectMember.LastName(childComplexity), true + + case "ProjectMember.profileIcon": + if e.complexity.ProjectMember.ProfileIcon == nil { + break + } + + 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": if e.complexity.Query.FindProject == nil { @@ -459,6 +551,18 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.Query.FindProject(childComplexity, args["input"].(FindProject)), true + case "Query.findTask": + if e.complexity.Query.FindTask == nil { + break + } + + args, err := ec.field_Query_findTask_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Query.FindTask(childComplexity, args["input"].(FindTask)), true + case "Query.findUser": if e.complexity.Query.FindUser == nil { break @@ -471,12 +575,12 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.Query.FindUser(childComplexity, args["input"].(FindUser)), true - case "Query.organizations": - if e.complexity.Query.Organizations == nil { + case "Query.me": + if e.complexity.Query.Me == nil { break } - return e.complexity.Query.Organizations(childComplexity), true + return e.complexity.Query.Me(childComplexity), true case "Query.projects": if e.complexity.Query.Projects == nil { @@ -497,13 +601,6 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.Query.TaskGroups(childComplexity), true - case "Query.teams": - if e.complexity.Query.Teams == nil { - break - } - - return e.complexity.Query.Teams(childComplexity), true - case "Query.users": if e.complexity.Query.Users == nil { break @@ -539,6 +636,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.RefreshToken.UserID(childComplexity), true + case "Task.assigned": + if e.complexity.Task.Assigned == nil { + break + } + + return e.complexity.Task.Assigned(childComplexity), true + case "Task.createdAt": if e.complexity.Task.CreatedAt == nil { break @@ -546,6 +650,20 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.Task.CreatedAt(childComplexity), true + case "Task.description": + if e.complexity.Task.Description == nil { + break + } + + return e.complexity.Task.Description(childComplexity), true + + case "Task.labels": + if e.complexity.Task.Labels == nil { + break + } + + return e.complexity.Task.Labels(childComplexity), true + case "Task.name": if e.complexity.Task.Name == nil { break @@ -616,6 +734,27 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.TaskGroup.Tasks(childComplexity), true + case "TaskLabel.colorHex": + if e.complexity.TaskLabel.ColorHex == nil { + break + } + + return e.complexity.TaskLabel.ColorHex(childComplexity), true + + case "TaskLabel.labelColorID": + if e.complexity.TaskLabel.LabelColorID == nil { + break + } + + return e.complexity.TaskLabel.LabelColorID(childComplexity), true + + case "TaskLabel.taskLabelID": + if e.complexity.TaskLabel.TaskLabelID == nil { + break + } + + return e.complexity.TaskLabel.TaskLabelID(childComplexity), true + case "Team.createdAt": if e.complexity.Team.CreatedAt == nil { break @@ -630,13 +769,6 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.Team.Name(childComplexity), true - case "Team.projects": - if e.complexity.Team.Projects == nil { - break - } - - return e.complexity.Team.Projects(childComplexity), true - case "Team.teamID": if e.complexity.Team.TeamID == nil { break @@ -651,13 +783,6 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.UserAccount.CreatedAt(childComplexity), true - case "UserAccount.displayName": - if e.complexity.UserAccount.DisplayName == nil { - break - } - - return e.complexity.UserAccount.DisplayName(childComplexity), true - case "UserAccount.email": if e.complexity.UserAccount.Email == nil { break @@ -665,6 +790,27 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.UserAccount.Email(childComplexity), true + case "UserAccount.firstName": + if e.complexity.UserAccount.FirstName == nil { + break + } + + return e.complexity.UserAccount.FirstName(childComplexity), true + + case "UserAccount.lastName": + if e.complexity.UserAccount.LastName == nil { + break + } + + return e.complexity.UserAccount.LastName(childComplexity), true + + case "UserAccount.profileIcon": + if e.complexity.UserAccount.ProfileIcon == nil { + break + } + + return e.complexity.UserAccount.ProfileIcon(childComplexity), true + case "UserAccount.userID": if e.complexity.UserAccount.UserID == nil { break @@ -744,9 +890,26 @@ func (ec *executionContext) introspectType(name string) (*introspection.Type, er var sources = []*ast.Source{ &ast.Source{Name: "graph/schema.graphqls", Input: `scalar Time - scalar UUID +type TaskLabel { + taskLabelID: ID! + labelColorID: UUID! + colorHex: String! +} + +type ProfileIcon { + url: String + initials: String +} + +type ProjectMember { + userID: ID! + firstName: String! + lastName: String! + profileIcon: ProfileIcon! +} + type RefreshToken { tokenId: ID! userId: UUID! @@ -758,30 +921,26 @@ type UserAccount { userID: ID! email: String! createdAt: Time! - displayName: String! + firstName: String! + lastName: String! username: String! -} - -type Organization { - organizationID: ID! - createdAt: Time! - name: String! - teams: [Team!]! + profileIcon: ProfileIcon! } type Team { teamID: ID! createdAt: Time! name: String! - projects: [Project!]! } type Project { projectID: ID! - teamID: String! createdAt: Time! name: String! + team: Team! + owner: ProjectMember! taskGroups: [TaskGroup!]! + members: [ProjectMember!]! } type TaskGroup { @@ -799,6 +958,9 @@ type Task { createdAt: Time! name: String! position: Float! + description: String + assigned: [ProjectMember!]! + labels: [TaskLabel!]! } input ProjectsFilter { @@ -813,14 +975,18 @@ input FindProject { projectId: String! } +input FindTask { + taskID: UUID! +} + type Query { - organizations: [Organization!]! users: [UserAccount!]! findUser(input: FindUser!): UserAccount! findProject(input: FindProject!): Project! - teams: [Team!]! + findTask(input: FindTask!): Task! projects(input: ProjectsFilter): [Project!]! taskGroups: [TaskGroup!]! + me: UserAccount! } input NewRefreshToken { @@ -830,7 +996,8 @@ input NewRefreshToken { input NewUserAccount { username: String! email: String! - displayName: String! + firstName: String! + lastName: String! password: String! } @@ -840,7 +1007,8 @@ input NewTeam { } input NewProject { - teamID: String! + userID: UUID! + teamID: UUID! name: String! } @@ -850,10 +1018,6 @@ input NewTaskGroup { position: Float! } -input NewOrganization { - name: String! -} - input LogoutUser { userID: String! } @@ -896,13 +1060,31 @@ type DeleteTaskGroupPayload { taskGroup: TaskGroup! } +input AssignTaskInput { + taskID: UUID! + userID: UUID! +} + +input UpdateTaskDescriptionInput { + taskID: UUID! + description: String! +} + +input AddTaskLabelInput { + taskID: UUID! + labelColorID: UUID! +} + +input RemoveTaskLabelInput { + taskID: UUID! + taskLabelID: UUID! +} + type Mutation { createRefreshToken(input: NewRefreshToken!): RefreshToken! createUserAccount(input: NewUserAccount!): UserAccount! - createOrganization(input: NewOrganization!): Organization! - createTeam(input: NewTeam!): Team! createProject(input: NewProject!): Project! @@ -911,10 +1093,15 @@ type Mutation { updateTaskGroupLocation(input: NewTaskGroupLocation!): TaskGroup! deleteTaskGroup(input: DeleteTaskGroupInput!): DeleteTaskGroupPayload! + addTaskLabel(input: AddTaskLabelInput): Task! + removeTaskLabel(input: RemoveTaskLabelInput): Task! + createTask(input: NewTask!): Task! + updateTaskDescription(input: UpdateTaskDescriptionInput!): Task! updateTaskLocation(input: NewTaskLocation!): Task! updateTaskName(input: UpdateTaskName!): Task! deleteTask(input: DeleteTaskInput!): DeleteTaskPayload! + assignTask(input: AssignTaskInput): Task! logoutUser(input: LogoutUser!): Boolean! } @@ -926,12 +1113,26 @@ var parsedSchema = gqlparser.MustLoadSchema(sources...) // region ***************************** args.gotpl ***************************** -func (ec *executionContext) field_Mutation_createOrganization_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { +func (ec *executionContext) field_Mutation_addTaskLabel_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { var err error args := map[string]interface{}{} - var arg0 NewOrganization + var arg0 *AddTaskLabelInput if tmp, ok := rawArgs["input"]; ok { - arg0, err = ec.unmarshalNNewOrganization2githubᚗcomᚋjordanknottᚋprojectᚑcitadelᚋapiᚋgraphᚐNewOrganization(ctx, tmp) + arg0, err = ec.unmarshalOAddTaskLabelInput2ᚖgithubᚗcomᚋjordanknottᚋprojectᚑcitadelᚋapiᚋgraphᚐAddTaskLabelInput(ctx, tmp) + if err != nil { + return nil, err + } + } + args["input"] = arg0 + return args, nil +} + +func (ec *executionContext) field_Mutation_assignTask_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 *AssignTaskInput + if tmp, ok := rawArgs["input"]; ok { + arg0, err = ec.unmarshalOAssignTaskInput2ᚖgithubᚗcomᚋjordanknottᚋprojectᚑcitadelᚋapiᚋgraphᚐAssignTaskInput(ctx, tmp) if err != nil { return nil, err } @@ -1066,6 +1267,34 @@ func (ec *executionContext) field_Mutation_logoutUser_args(ctx context.Context, return args, nil } +func (ec *executionContext) field_Mutation_removeTaskLabel_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 *RemoveTaskLabelInput + if tmp, ok := rawArgs["input"]; ok { + arg0, err = ec.unmarshalORemoveTaskLabelInput2ᚖgithubᚗcomᚋjordanknottᚋprojectᚑcitadelᚋapiᚋgraphᚐRemoveTaskLabelInput(ctx, tmp) + if err != nil { + return nil, err + } + } + args["input"] = arg0 + return args, nil +} + +func (ec *executionContext) field_Mutation_updateTaskDescription_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 UpdateTaskDescriptionInput + if tmp, ok := rawArgs["input"]; ok { + arg0, err = ec.unmarshalNUpdateTaskDescriptionInput2githubᚗcomᚋjordanknottᚋprojectᚑcitadelᚋapiᚋgraphᚐUpdateTaskDescriptionInput(ctx, tmp) + if err != nil { + return nil, err + } + } + args["input"] = arg0 + return args, nil +} + func (ec *executionContext) field_Mutation_updateTaskGroupLocation_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { var err error args := map[string]interface{}{} @@ -1136,6 +1365,20 @@ func (ec *executionContext) field_Query_findProject_args(ctx context.Context, ra return args, nil } +func (ec *executionContext) field_Query_findTask_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 FindTask + if tmp, ok := rawArgs["input"]; ok { + arg0, err = ec.unmarshalNFindTask2githubᚗcomᚋjordanknottᚋprojectᚑcitadelᚋapiᚋgraphᚐFindTask(ctx, tmp) + if err != nil { + return nil, err + } + } + args["input"] = arg0 + return args, nil +} + func (ec *executionContext) field_Query_findUser_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { var err error args := map[string]interface{}{} @@ -1418,47 +1661,6 @@ func (ec *executionContext) _Mutation_createUserAccount(ctx context.Context, fie return ec.marshalNUserAccount2ᚖgithubᚗcomᚋjordanknottᚋprojectᚑcitadelᚋapiᚋpgᚐUserAccount(ctx, field.Selections, res) } -func (ec *executionContext) _Mutation_createOrganization(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - fc := &graphql.FieldContext{ - Object: "Mutation", - Field: field, - Args: nil, - IsMethod: true, - } - - ctx = graphql.WithFieldContext(ctx, fc) - rawArgs := field.ArgumentMap(ec.Variables) - args, err := ec.field_Mutation_createOrganization_args(ctx, rawArgs) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - fc.Args = args - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return ec.resolvers.Mutation().CreateOrganization(rctx, args["input"].(NewOrganization)) - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(*pg.Organization) - fc.Result = res - return ec.marshalNOrganization2ᚖgithubᚗcomᚋjordanknottᚋprojectᚑcitadelᚋapiᚋpgᚐOrganization(ctx, field.Selections, res) -} - func (ec *executionContext) _Mutation_createTeam(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { defer func() { if r := recover(); r != nil { @@ -1664,6 +1866,88 @@ func (ec *executionContext) _Mutation_deleteTaskGroup(ctx context.Context, field return ec.marshalNDeleteTaskGroupPayload2ᚖgithubᚗcomᚋjordanknottᚋprojectᚑcitadelᚋapiᚋgraphᚐDeleteTaskGroupPayload(ctx, field.Selections, res) } +func (ec *executionContext) _Mutation_addTaskLabel(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Mutation", + Field: field, + Args: nil, + IsMethod: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + rawArgs := field.ArgumentMap(ec.Variables) + args, err := ec.field_Mutation_addTaskLabel_args(ctx, rawArgs) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + fc.Args = args + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Mutation().AddTaskLabel(rctx, args["input"].(*AddTaskLabelInput)) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*pg.Task) + fc.Result = res + return ec.marshalNTask2ᚖgithubᚗcomᚋjordanknottᚋprojectᚑcitadelᚋapiᚋpgᚐTask(ctx, field.Selections, res) +} + +func (ec *executionContext) _Mutation_removeTaskLabel(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Mutation", + Field: field, + Args: nil, + IsMethod: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + rawArgs := field.ArgumentMap(ec.Variables) + args, err := ec.field_Mutation_removeTaskLabel_args(ctx, rawArgs) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + fc.Args = args + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Mutation().RemoveTaskLabel(rctx, args["input"].(*RemoveTaskLabelInput)) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*pg.Task) + fc.Result = res + return ec.marshalNTask2ᚖgithubᚗcomᚋjordanknottᚋprojectᚑcitadelᚋapiᚋpgᚐTask(ctx, field.Selections, res) +} + func (ec *executionContext) _Mutation_createTask(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { defer func() { if r := recover(); r != nil { @@ -1705,6 +1989,47 @@ func (ec *executionContext) _Mutation_createTask(ctx context.Context, field grap return ec.marshalNTask2ᚖgithubᚗcomᚋjordanknottᚋprojectᚑcitadelᚋapiᚋpgᚐTask(ctx, field.Selections, res) } +func (ec *executionContext) _Mutation_updateTaskDescription(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Mutation", + Field: field, + Args: nil, + IsMethod: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + rawArgs := field.ArgumentMap(ec.Variables) + args, err := ec.field_Mutation_updateTaskDescription_args(ctx, rawArgs) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + fc.Args = args + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Mutation().UpdateTaskDescription(rctx, args["input"].(UpdateTaskDescriptionInput)) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*pg.Task) + fc.Result = res + return ec.marshalNTask2ᚖgithubᚗcomᚋjordanknottᚋprojectᚑcitadelᚋapiᚋpgᚐTask(ctx, field.Selections, res) +} + func (ec *executionContext) _Mutation_updateTaskLocation(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { defer func() { if r := recover(); r != nil { @@ -1828,6 +2153,47 @@ func (ec *executionContext) _Mutation_deleteTask(ctx context.Context, field grap return ec.marshalNDeleteTaskPayload2ᚖgithubᚗcomᚋjordanknottᚋprojectᚑcitadelᚋapiᚋgraphᚐDeleteTaskPayload(ctx, field.Selections, res) } +func (ec *executionContext) _Mutation_assignTask(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Mutation", + Field: field, + Args: nil, + IsMethod: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + rawArgs := field.ArgumentMap(ec.Variables) + args, err := ec.field_Mutation_assignTask_args(ctx, rawArgs) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + fc.Args = args + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Mutation().AssignTask(rctx, args["input"].(*AssignTaskInput)) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*pg.Task) + fc.Result = res + return ec.marshalNTask2ᚖgithubᚗcomᚋjordanknottᚋprojectᚑcitadelᚋapiᚋpgᚐTask(ctx, field.Selections, res) +} + func (ec *executionContext) _Mutation_logoutUser(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { defer func() { if r := recover(); r != nil { @@ -1869,7 +2235,7 @@ func (ec *executionContext) _Mutation_logoutUser(ctx context.Context, field grap return ec.marshalNBoolean2bool(ctx, field.Selections, res) } -func (ec *executionContext) _Organization_organizationID(ctx context.Context, field graphql.CollectedField, obj *pg.Organization) (ret graphql.Marshaler) { +func (ec *executionContext) _ProfileIcon_url(ctx context.Context, field graphql.CollectedField, obj *ProfileIcon) (ret graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) @@ -1877,7 +2243,7 @@ func (ec *executionContext) _Organization_organizationID(ctx context.Context, fi } }() fc := &graphql.FieldContext{ - Object: "Organization", + Object: "ProfileIcon", Field: field, Args: nil, IsMethod: false, @@ -1886,24 +2252,21 @@ func (ec *executionContext) _Organization_organizationID(ctx context.Context, fi ctx = graphql.WithFieldContext(ctx, fc) resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { ctx = rctx // use context from middleware stack in children - return obj.OrganizationID, nil + return obj.URL, nil }) if err != nil { ec.Error(ctx, err) return graphql.Null } if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } return graphql.Null } - res := resTmp.(uuid.UUID) + res := resTmp.(*string) fc.Result = res - return ec.marshalNID2githubᚗcomᚋgoogleᚋuuidᚐUUID(ctx, field.Selections, res) + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) } -func (ec *executionContext) _Organization_createdAt(ctx context.Context, field graphql.CollectedField, obj *pg.Organization) (ret graphql.Marshaler) { +func (ec *executionContext) _ProfileIcon_initials(ctx context.Context, field graphql.CollectedField, obj *ProfileIcon) (ret graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) @@ -1911,7 +2274,7 @@ func (ec *executionContext) _Organization_createdAt(ctx context.Context, field g } }() fc := &graphql.FieldContext{ - Object: "Organization", + Object: "ProfileIcon", Field: field, Args: nil, IsMethod: false, @@ -1920,89 +2283,18 @@ func (ec *executionContext) _Organization_createdAt(ctx context.Context, field g ctx = graphql.WithFieldContext(ctx, fc) resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { ctx = rctx // use context from middleware stack in children - return obj.CreatedAt, nil + return obj.Initials, nil }) if err != nil { ec.Error(ctx, err) return graphql.Null } if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } return graphql.Null } - res := resTmp.(time.Time) + res := resTmp.(*string) fc.Result = res - return ec.marshalNTime2timeᚐTime(ctx, field.Selections, res) -} - -func (ec *executionContext) _Organization_name(ctx context.Context, field graphql.CollectedField, obj *pg.Organization) (ret graphql.Marshaler) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - fc := &graphql.FieldContext{ - Object: "Organization", - Field: field, - Args: nil, - IsMethod: false, - } - - ctx = graphql.WithFieldContext(ctx, fc) - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return obj.Name, nil - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(string) - fc.Result = res - return ec.marshalNString2string(ctx, field.Selections, res) -} - -func (ec *executionContext) _Organization_teams(ctx context.Context, field graphql.CollectedField, obj *pg.Organization) (ret graphql.Marshaler) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - fc := &graphql.FieldContext{ - Object: "Organization", - Field: field, - Args: nil, - IsMethod: true, - } - - ctx = graphql.WithFieldContext(ctx, fc) - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return ec.resolvers.Organization().Teams(rctx, obj) - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.([]pg.Team) - fc.Result = res - return ec.marshalNTeam2ᚕgithubᚗcomᚋjordanknottᚋprojectᚑcitadelᚋapiᚋpgᚐTeamᚄ(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) { @@ -2039,40 +2331,6 @@ func (ec *executionContext) _Project_projectID(ctx context.Context, field graphq return ec.marshalNID2githubᚗcomᚋgoogleᚋuuidᚐUUID(ctx, field.Selections, res) } -func (ec *executionContext) _Project_teamID(ctx context.Context, field graphql.CollectedField, obj *pg.Project) (ret graphql.Marshaler) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - fc := &graphql.FieldContext{ - Object: "Project", - Field: field, - Args: nil, - IsMethod: true, - } - - ctx = graphql.WithFieldContext(ctx, fc) - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return ec.resolvers.Project().TeamID(rctx, obj) - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.(string) - fc.Result = res - return ec.marshalNString2string(ctx, field.Selections, res) -} - func (ec *executionContext) _Project_createdAt(ctx context.Context, field graphql.CollectedField, obj *pg.Project) (ret graphql.Marshaler) { defer func() { if r := recover(); r != nil { @@ -2141,6 +2399,74 @@ func (ec *executionContext) _Project_name(ctx context.Context, field graphql.Col return ec.marshalNString2string(ctx, field.Selections, res) } +func (ec *executionContext) _Project_team(ctx context.Context, field graphql.CollectedField, obj *pg.Project) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Project", + Field: field, + Args: nil, + IsMethod: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Project().Team(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*pg.Team) + fc.Result = res + return ec.marshalNTeam2ᚖgithubᚗcomᚋjordanknottᚋprojectᚑcitadelᚋapiᚋpgᚐTeam(ctx, field.Selections, res) +} + +func (ec *executionContext) _Project_owner(ctx context.Context, field graphql.CollectedField, obj *pg.Project) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Project", + Field: field, + Args: nil, + IsMethod: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Project().Owner(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*ProjectMember) + fc.Result = res + return ec.marshalNProjectMember2ᚖgithubᚗcomᚋjordanknottᚋprojectᚑcitadelᚋapiᚋgraphᚐProjectMember(ctx, field.Selections, res) +} + func (ec *executionContext) _Project_taskGroups(ctx context.Context, field graphql.CollectedField, obj *pg.Project) (ret graphql.Marshaler) { defer func() { if r := recover(); r != nil { @@ -2175,7 +2501,7 @@ func (ec *executionContext) _Project_taskGroups(ctx context.Context, field graph return ec.marshalNTaskGroup2ᚕgithubᚗcomᚋjordanknottᚋprojectᚑcitadelᚋapiᚋpgᚐTaskGroupᚄ(ctx, field.Selections, res) } -func (ec *executionContext) _Query_organizations(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { +func (ec *executionContext) _Project_members(ctx context.Context, field graphql.CollectedField, obj *pg.Project) (ret graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) @@ -2183,7 +2509,7 @@ func (ec *executionContext) _Query_organizations(ctx context.Context, field grap } }() fc := &graphql.FieldContext{ - Object: "Query", + Object: "Project", Field: field, Args: nil, IsMethod: true, @@ -2192,7 +2518,7 @@ func (ec *executionContext) _Query_organizations(ctx context.Context, field grap ctx = graphql.WithFieldContext(ctx, fc) resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { ctx = rctx // use context from middleware stack in children - return ec.resolvers.Query().Organizations(rctx) + return ec.resolvers.Project().Members(rctx, obj) }) if err != nil { ec.Error(ctx, err) @@ -2204,9 +2530,145 @@ func (ec *executionContext) _Query_organizations(ctx context.Context, field grap } return graphql.Null } - res := resTmp.([]pg.Organization) + res := resTmp.([]ProjectMember) fc.Result = res - return ec.marshalNOrganization2ᚕgithubᚗcomᚋjordanknottᚋprojectᚑcitadelᚋapiᚋpgᚐOrganizationᚄ(ctx, field.Selections, res) + return ec.marshalNProjectMember2ᚕgithubᚗcomᚋjordanknottᚋprojectᚑcitadelᚋapiᚋgraphᚐProjectMemberᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) _ProjectMember_userID(ctx context.Context, field graphql.CollectedField, obj *ProjectMember) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "ProjectMember", + Field: field, + Args: nil, + IsMethod: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.UserID, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(uuid.UUID) + fc.Result = res + return ec.marshalNID2githubᚗcomᚋgoogleᚋuuidᚐUUID(ctx, field.Selections, res) +} + +func (ec *executionContext) _ProjectMember_firstName(ctx context.Context, field graphql.CollectedField, obj *ProjectMember) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "ProjectMember", + Field: field, + Args: nil, + IsMethod: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.FirstName, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _ProjectMember_lastName(ctx context.Context, field graphql.CollectedField, obj *ProjectMember) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "ProjectMember", + Field: field, + Args: nil, + IsMethod: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.LastName, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _ProjectMember_profileIcon(ctx context.Context, field graphql.CollectedField, obj *ProjectMember) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "ProjectMember", + Field: field, + Args: nil, + IsMethod: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.ProfileIcon, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*ProfileIcon) + fc.Result = res + return ec.marshalNProfileIcon2ᚖgithubᚗcomᚋjordanknottᚋprojectᚑcitadelᚋapiᚋgraphᚐProfileIcon(ctx, field.Selections, res) } func (ec *executionContext) _Query_users(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { @@ -2325,7 +2787,7 @@ func (ec *executionContext) _Query_findProject(ctx context.Context, field graphq return ec.marshalNProject2ᚖgithubᚗcomᚋjordanknottᚋprojectᚑcitadelᚋapiᚋpgᚐProject(ctx, field.Selections, res) } -func (ec *executionContext) _Query_teams(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { +func (ec *executionContext) _Query_findTask(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) @@ -2340,9 +2802,16 @@ func (ec *executionContext) _Query_teams(ctx context.Context, field graphql.Coll } ctx = graphql.WithFieldContext(ctx, fc) + rawArgs := field.ArgumentMap(ec.Variables) + args, err := ec.field_Query_findTask_args(ctx, rawArgs) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + fc.Args = args resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { ctx = rctx // use context from middleware stack in children - return ec.resolvers.Query().Teams(rctx) + return ec.resolvers.Query().FindTask(rctx, args["input"].(FindTask)) }) if err != nil { ec.Error(ctx, err) @@ -2354,9 +2823,9 @@ func (ec *executionContext) _Query_teams(ctx context.Context, field graphql.Coll } return graphql.Null } - res := resTmp.([]pg.Team) + res := resTmp.(*pg.Task) fc.Result = res - return ec.marshalNTeam2ᚕgithubᚗcomᚋjordanknottᚋprojectᚑcitadelᚋapiᚋpgᚐTeamᚄ(ctx, field.Selections, res) + return ec.marshalNTask2ᚖgithubᚗcomᚋjordanknottᚋprojectᚑcitadelᚋapiᚋpgᚐTask(ctx, field.Selections, res) } func (ec *executionContext) _Query_projects(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { @@ -2434,6 +2903,40 @@ func (ec *executionContext) _Query_taskGroups(ctx context.Context, field graphql return ec.marshalNTaskGroup2ᚕgithubᚗcomᚋjordanknottᚋprojectᚑcitadelᚋapiᚋpgᚐTaskGroupᚄ(ctx, field.Selections, res) } +func (ec *executionContext) _Query_me(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Query", + Field: field, + Args: nil, + IsMethod: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Query().Me(rctx) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*pg.UserAccount) + fc.Result = res + return ec.marshalNUserAccount2ᚖgithubᚗcomᚋjordanknottᚋprojectᚑcitadelᚋapiᚋpgᚐUserAccount(ctx, field.Selections, res) +} + func (ec *executionContext) _Query___type(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { defer func() { if r := recover(); r != nil { @@ -2809,6 +3312,105 @@ func (ec *executionContext) _Task_position(ctx context.Context, field graphql.Co return ec.marshalNFloat2float64(ctx, field.Selections, res) } +func (ec *executionContext) _Task_description(ctx context.Context, field graphql.CollectedField, obj *pg.Task) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Task", + Field: field, + Args: nil, + IsMethod: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Task().Description(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) _Task_assigned(ctx context.Context, field graphql.CollectedField, obj *pg.Task) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Task", + Field: field, + Args: nil, + IsMethod: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Task().Assigned(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.([]ProjectMember) + fc.Result = res + return ec.marshalNProjectMember2ᚕgithubᚗcomᚋjordanknottᚋprojectᚑcitadelᚋapiᚋgraphᚐProjectMemberᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) _Task_labels(ctx context.Context, field graphql.CollectedField, obj *pg.Task) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "Task", + Field: field, + Args: nil, + IsMethod: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Task().Labels(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.([]pg.TaskLabel) + fc.Result = 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) { defer func() { if r := recover(); r != nil { @@ -3013,6 +3615,108 @@ 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) } +func (ec *executionContext) _TaskLabel_taskLabelID(ctx context.Context, field graphql.CollectedField, obj *pg.TaskLabel) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "TaskLabel", + Field: field, + Args: nil, + IsMethod: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.TaskLabelID, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(uuid.UUID) + fc.Result = res + return ec.marshalNID2githubᚗcomᚋgoogleᚋuuidᚐUUID(ctx, field.Selections, res) +} + +func (ec *executionContext) _TaskLabel_labelColorID(ctx context.Context, field graphql.CollectedField, obj *pg.TaskLabel) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "TaskLabel", + Field: field, + Args: nil, + IsMethod: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.LabelColorID, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(uuid.UUID) + fc.Result = res + return ec.marshalNUUID2githubᚗcomᚋgoogleᚋuuidᚐUUID(ctx, field.Selections, res) +} + +func (ec *executionContext) _TaskLabel_colorHex(ctx context.Context, field graphql.CollectedField, obj *pg.TaskLabel) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "TaskLabel", + Field: field, + Args: nil, + IsMethod: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.TaskLabel().ColorHex(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + func (ec *executionContext) _Team_teamID(ctx context.Context, field graphql.CollectedField, obj *pg.Team) (ret graphql.Marshaler) { defer func() { if r := recover(); r != nil { @@ -3115,40 +3819,6 @@ func (ec *executionContext) _Team_name(ctx context.Context, field graphql.Collec return ec.marshalNString2string(ctx, field.Selections, res) } -func (ec *executionContext) _Team_projects(ctx context.Context, field graphql.CollectedField, obj *pg.Team) (ret graphql.Marshaler) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = graphql.Null - } - }() - fc := &graphql.FieldContext{ - Object: "Team", - Field: field, - Args: nil, - IsMethod: true, - } - - ctx = graphql.WithFieldContext(ctx, fc) - resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { - ctx = rctx // use context from middleware stack in children - return ec.resolvers.Team().Projects(rctx, obj) - }) - if err != nil { - ec.Error(ctx, err) - return graphql.Null - } - if resTmp == nil { - if !graphql.HasFieldError(ctx, fc) { - ec.Errorf(ctx, "must not be null") - } - return graphql.Null - } - res := resTmp.([]pg.Project) - fc.Result = res - return ec.marshalNProject2ᚕgithubᚗcomᚋjordanknottᚋprojectᚑcitadelᚋapiᚋpgᚐProjectᚄ(ctx, field.Selections, res) -} - func (ec *executionContext) _UserAccount_userID(ctx context.Context, field graphql.CollectedField, obj *pg.UserAccount) (ret graphql.Marshaler) { defer func() { if r := recover(); r != nil { @@ -3251,7 +3921,7 @@ func (ec *executionContext) _UserAccount_createdAt(ctx context.Context, field gr return ec.marshalNTime2timeᚐTime(ctx, field.Selections, res) } -func (ec *executionContext) _UserAccount_displayName(ctx context.Context, field graphql.CollectedField, obj *pg.UserAccount) (ret graphql.Marshaler) { +func (ec *executionContext) _UserAccount_firstName(ctx context.Context, field graphql.CollectedField, obj *pg.UserAccount) (ret graphql.Marshaler) { defer func() { if r := recover(); r != nil { ec.Error(ctx, ec.Recover(ctx, r)) @@ -3268,7 +3938,41 @@ func (ec *executionContext) _UserAccount_displayName(ctx context.Context, field ctx = graphql.WithFieldContext(ctx, fc) resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { ctx = rctx // use context from middleware stack in children - return obj.DisplayName, nil + return obj.FirstName, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) _UserAccount_lastName(ctx context.Context, field graphql.CollectedField, obj *pg.UserAccount) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "UserAccount", + Field: field, + Args: nil, + IsMethod: false, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.LastName, nil }) if err != nil { ec.Error(ctx, err) @@ -3319,6 +4023,40 @@ func (ec *executionContext) _UserAccount_username(ctx context.Context, field gra return ec.marshalNString2string(ctx, field.Selections, res) } +func (ec *executionContext) _UserAccount_profileIcon(ctx context.Context, field graphql.CollectedField, obj *pg.UserAccount) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "UserAccount", + Field: field, + Args: nil, + IsMethod: true, + } + + ctx = graphql.WithFieldContext(ctx, fc) + resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.UserAccount().ProfileIcon(rctx, obj) + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*ProfileIcon) + fc.Result = res + return ec.marshalNProfileIcon2ᚖgithubᚗcomᚋjordanknottᚋprojectᚑcitadelᚋapiᚋgraphᚐProfileIcon(ctx, field.Selections, res) +} + func (ec *executionContext) ___Directive_name(ctx context.Context, field graphql.CollectedField, obj *introspection.Directive) (ret graphql.Marshaler) { defer func() { if r := recover(); r != nil { @@ -4374,6 +5112,54 @@ func (ec *executionContext) ___Type_ofType(ctx context.Context, field graphql.Co // region **************************** input.gotpl ***************************** +func (ec *executionContext) unmarshalInputAddTaskLabelInput(ctx context.Context, obj interface{}) (AddTaskLabelInput, error) { + var it AddTaskLabelInput + var asMap = obj.(map[string]interface{}) + + for k, v := range asMap { + switch k { + case "taskID": + var err error + it.TaskID, err = ec.unmarshalNUUID2githubᚗcomᚋgoogleᚋuuidᚐUUID(ctx, v) + if err != nil { + return it, err + } + case "labelColorID": + var err error + it.LabelColorID, err = ec.unmarshalNUUID2githubᚗcomᚋgoogleᚋuuidᚐUUID(ctx, v) + if err != nil { + return it, err + } + } + } + + return it, nil +} + +func (ec *executionContext) unmarshalInputAssignTaskInput(ctx context.Context, obj interface{}) (AssignTaskInput, error) { + var it AssignTaskInput + var asMap = obj.(map[string]interface{}) + + for k, v := range asMap { + switch k { + case "taskID": + var err error + it.TaskID, err = ec.unmarshalNUUID2githubᚗcomᚋgoogleᚋuuidᚐUUID(ctx, v) + if err != nil { + return it, err + } + case "userID": + var err error + it.UserID, err = ec.unmarshalNUUID2githubᚗcomᚋgoogleᚋuuidᚐUUID(ctx, v) + if err != nil { + return it, err + } + } + } + + return it, nil +} + func (ec *executionContext) unmarshalInputDeleteTaskGroupInput(ctx context.Context, obj interface{}) (DeleteTaskGroupInput, error) { var it DeleteTaskGroupInput var asMap = obj.(map[string]interface{}) @@ -4428,6 +5214,24 @@ func (ec *executionContext) unmarshalInputFindProject(ctx context.Context, obj i return it, nil } +func (ec *executionContext) unmarshalInputFindTask(ctx context.Context, obj interface{}) (FindTask, error) { + var it FindTask + var asMap = obj.(map[string]interface{}) + + for k, v := range asMap { + switch k { + case "taskID": + var err error + it.TaskID, err = ec.unmarshalNUUID2githubᚗcomᚋgoogleᚋuuidᚐUUID(ctx, v) + if err != nil { + return it, err + } + } + } + + return it, nil +} + func (ec *executionContext) unmarshalInputFindUser(ctx context.Context, obj interface{}) (FindUser, error) { var it FindUser var asMap = obj.(map[string]interface{}) @@ -4464,33 +5268,21 @@ func (ec *executionContext) unmarshalInputLogoutUser(ctx context.Context, obj in return it, nil } -func (ec *executionContext) unmarshalInputNewOrganization(ctx context.Context, obj interface{}) (NewOrganization, error) { - var it NewOrganization - var asMap = obj.(map[string]interface{}) - - for k, v := range asMap { - switch k { - case "name": - var err error - it.Name, err = ec.unmarshalNString2string(ctx, v) - if err != nil { - return it, err - } - } - } - - return it, nil -} - func (ec *executionContext) unmarshalInputNewProject(ctx context.Context, obj interface{}) (NewProject, error) { var it NewProject var asMap = obj.(map[string]interface{}) for k, v := range asMap { switch k { + case "userID": + var err error + it.UserID, err = ec.unmarshalNUUID2githubᚗcomᚋgoogleᚋuuidᚐUUID(ctx, v) + if err != nil { + return it, err + } case "teamID": var err error - it.TeamID, err = ec.unmarshalNString2string(ctx, v) + it.TeamID, err = ec.unmarshalNUUID2githubᚗcomᚋgoogleᚋuuidᚐUUID(ctx, v) if err != nil { return it, err } @@ -4680,9 +5472,15 @@ func (ec *executionContext) unmarshalInputNewUserAccount(ctx context.Context, ob if err != nil { return it, err } - case "displayName": + case "firstName": var err error - it.DisplayName, err = ec.unmarshalNString2string(ctx, v) + it.FirstName, err = ec.unmarshalNString2string(ctx, v) + if err != nil { + return it, err + } + case "lastName": + var err error + it.LastName, err = ec.unmarshalNString2string(ctx, v) if err != nil { return it, err } @@ -4716,6 +5514,54 @@ func (ec *executionContext) unmarshalInputProjectsFilter(ctx context.Context, ob return it, nil } +func (ec *executionContext) unmarshalInputRemoveTaskLabelInput(ctx context.Context, obj interface{}) (RemoveTaskLabelInput, error) { + var it RemoveTaskLabelInput + var asMap = obj.(map[string]interface{}) + + for k, v := range asMap { + switch k { + case "taskID": + var err error + it.TaskID, err = ec.unmarshalNUUID2githubᚗcomᚋgoogleᚋuuidᚐUUID(ctx, v) + if err != nil { + return it, err + } + case "taskLabelID": + var err error + it.TaskLabelID, err = ec.unmarshalNUUID2githubᚗcomᚋgoogleᚋuuidᚐUUID(ctx, v) + if err != nil { + return it, err + } + } + } + + return it, nil +} + +func (ec *executionContext) unmarshalInputUpdateTaskDescriptionInput(ctx context.Context, obj interface{}) (UpdateTaskDescriptionInput, error) { + var it UpdateTaskDescriptionInput + var asMap = obj.(map[string]interface{}) + + for k, v := range asMap { + switch k { + case "taskID": + var err error + it.TaskID, err = ec.unmarshalNUUID2githubᚗcomᚋgoogleᚋuuidᚐUUID(ctx, v) + if err != nil { + return it, err + } + case "description": + var err error + it.Description, err = ec.unmarshalNString2string(ctx, v) + if err != nil { + return it, err + } + } + } + + return it, nil +} + func (ec *executionContext) unmarshalInputUpdateTaskName(ctx context.Context, obj interface{}) (UpdateTaskName, error) { var it UpdateTaskName var asMap = obj.(map[string]interface{}) @@ -4837,11 +5683,6 @@ func (ec *executionContext) _Mutation(ctx context.Context, sel ast.SelectionSet) if out.Values[i] == graphql.Null { invalids++ } - case "createOrganization": - out.Values[i] = ec._Mutation_createOrganization(ctx, field) - if out.Values[i] == graphql.Null { - invalids++ - } case "createTeam": out.Values[i] = ec._Mutation_createTeam(ctx, field) if out.Values[i] == graphql.Null { @@ -4867,11 +5708,26 @@ func (ec *executionContext) _Mutation(ctx context.Context, sel ast.SelectionSet) if out.Values[i] == graphql.Null { invalids++ } + case "addTaskLabel": + out.Values[i] = ec._Mutation_addTaskLabel(ctx, field) + if out.Values[i] == graphql.Null { + invalids++ + } + case "removeTaskLabel": + out.Values[i] = ec._Mutation_removeTaskLabel(ctx, field) + if out.Values[i] == graphql.Null { + invalids++ + } case "createTask": out.Values[i] = ec._Mutation_createTask(ctx, field) if out.Values[i] == graphql.Null { invalids++ } + case "updateTaskDescription": + out.Values[i] = ec._Mutation_updateTaskDescription(ctx, field) + if out.Values[i] == graphql.Null { + invalids++ + } case "updateTaskLocation": out.Values[i] = ec._Mutation_updateTaskLocation(ctx, field) if out.Values[i] == graphql.Null { @@ -4887,6 +5743,11 @@ func (ec *executionContext) _Mutation(ctx context.Context, sel ast.SelectionSet) if out.Values[i] == graphql.Null { invalids++ } + case "assignTask": + out.Values[i] = ec._Mutation_assignTask(ctx, field) + if out.Values[i] == graphql.Null { + invalids++ + } case "logoutUser": out.Values[i] = ec._Mutation_logoutUser(ctx, field) if out.Values[i] == graphql.Null { @@ -4903,46 +5764,21 @@ func (ec *executionContext) _Mutation(ctx context.Context, sel ast.SelectionSet) return out } -var organizationImplementors = []string{"Organization"} +var profileIconImplementors = []string{"ProfileIcon"} -func (ec *executionContext) _Organization(ctx context.Context, sel ast.SelectionSet, obj *pg.Organization) graphql.Marshaler { - fields := graphql.CollectFields(ec.OperationContext, sel, organizationImplementors) +func (ec *executionContext) _ProfileIcon(ctx context.Context, sel ast.SelectionSet, obj *ProfileIcon) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, profileIconImplementors) out := graphql.NewFieldSet(fields) var invalids uint32 for i, field := range fields { switch field.Name { case "__typename": - out.Values[i] = graphql.MarshalString("Organization") - case "organizationID": - out.Values[i] = ec._Organization_organizationID(ctx, field, obj) - if out.Values[i] == graphql.Null { - atomic.AddUint32(&invalids, 1) - } - case "createdAt": - out.Values[i] = ec._Organization_createdAt(ctx, field, obj) - if out.Values[i] == graphql.Null { - atomic.AddUint32(&invalids, 1) - } - case "name": - out.Values[i] = ec._Organization_name(ctx, field, obj) - if out.Values[i] == graphql.Null { - atomic.AddUint32(&invalids, 1) - } - case "teams": - field := field - out.Concurrently(i, func() (res graphql.Marshaler) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - } - }() - res = ec._Organization_teams(ctx, field, obj) - if res == graphql.Null { - atomic.AddUint32(&invalids, 1) - } - return res - }) + out.Values[i] = graphql.MarshalString("ProfileIcon") + case "url": + out.Values[i] = ec._ProfileIcon_url(ctx, field, obj) + case "initials": + out.Values[i] = ec._ProfileIcon_initials(ctx, field, obj) default: panic("unknown field " + strconv.Quote(field.Name)) } @@ -4970,20 +5806,6 @@ func (ec *executionContext) _Project(ctx context.Context, sel ast.SelectionSet, if out.Values[i] == graphql.Null { atomic.AddUint32(&invalids, 1) } - case "teamID": - field := field - out.Concurrently(i, func() (res graphql.Marshaler) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - } - }() - res = ec._Project_teamID(ctx, field, obj) - if res == graphql.Null { - atomic.AddUint32(&invalids, 1) - } - return res - }) case "createdAt": out.Values[i] = ec._Project_createdAt(ctx, field, obj) if out.Values[i] == graphql.Null { @@ -4994,6 +5816,34 @@ func (ec *executionContext) _Project(ctx context.Context, sel ast.SelectionSet, if out.Values[i] == graphql.Null { atomic.AddUint32(&invalids, 1) } + case "team": + field := field + out.Concurrently(i, func() (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._Project_team(ctx, field, obj) + if res == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + return res + }) + case "owner": + field := field + out.Concurrently(i, func() (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._Project_owner(ctx, field, obj) + if res == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + return res + }) case "taskGroups": field := field out.Concurrently(i, func() (res graphql.Marshaler) { @@ -5008,6 +5858,62 @@ func (ec *executionContext) _Project(ctx context.Context, sel ast.SelectionSet, } return res }) + case "members": + field := field + out.Concurrently(i, func() (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._Project_members(ctx, field, obj) + if res == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + return res + }) + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalids > 0 { + return graphql.Null + } + return out +} + +var projectMemberImplementors = []string{"ProjectMember"} + +func (ec *executionContext) _ProjectMember(ctx context.Context, sel ast.SelectionSet, obj *ProjectMember) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, projectMemberImplementors) + + out := graphql.NewFieldSet(fields) + var invalids uint32 + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("ProjectMember") + case "userID": + out.Values[i] = ec._ProjectMember_userID(ctx, field, obj) + if out.Values[i] == graphql.Null { + invalids++ + } + case "firstName": + out.Values[i] = ec._ProjectMember_firstName(ctx, field, obj) + if out.Values[i] == graphql.Null { + invalids++ + } + case "lastName": + out.Values[i] = ec._ProjectMember_lastName(ctx, field, obj) + if out.Values[i] == graphql.Null { + invalids++ + } + case "profileIcon": + out.Values[i] = ec._ProjectMember_profileIcon(ctx, field, obj) + if out.Values[i] == graphql.Null { + invalids++ + } default: panic("unknown field " + strconv.Quote(field.Name)) } @@ -5034,20 +5940,6 @@ func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) gr switch field.Name { case "__typename": out.Values[i] = graphql.MarshalString("Query") - case "organizations": - field := field - out.Concurrently(i, func() (res graphql.Marshaler) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - } - }() - res = ec._Query_organizations(ctx, field) - if res == graphql.Null { - atomic.AddUint32(&invalids, 1) - } - return res - }) case "users": field := field out.Concurrently(i, func() (res graphql.Marshaler) { @@ -5090,7 +5982,7 @@ func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) gr } return res }) - case "teams": + case "findTask": field := field out.Concurrently(i, func() (res graphql.Marshaler) { defer func() { @@ -5098,7 +5990,7 @@ func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) gr ec.Error(ctx, ec.Recover(ctx, r)) } }() - res = ec._Query_teams(ctx, field) + res = ec._Query_findTask(ctx, field) if res == graphql.Null { atomic.AddUint32(&invalids, 1) } @@ -5132,6 +6024,20 @@ func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) gr } return res }) + case "me": + field := field + out.Concurrently(i, func() (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._Query_me(ctx, field) + if res == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + return res + }) case "__type": out.Values[i] = ec._Query___type(ctx, field) case "__schema": @@ -5234,6 +6140,45 @@ func (ec *executionContext) _Task(ctx context.Context, sel ast.SelectionSet, obj if out.Values[i] == graphql.Null { atomic.AddUint32(&invalids, 1) } + case "description": + field := field + out.Concurrently(i, func() (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._Task_description(ctx, field, obj) + return res + }) + case "assigned": + field := field + out.Concurrently(i, func() (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._Task_assigned(ctx, field, obj) + if res == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + return res + }) + case "labels": + field := field + out.Concurrently(i, func() (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._Task_labels(ctx, field, obj) + if res == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + return res + }) default: panic("unknown field " + strconv.Quote(field.Name)) } @@ -5315,6 +6260,52 @@ func (ec *executionContext) _TaskGroup(ctx context.Context, sel ast.SelectionSet return out } +var taskLabelImplementors = []string{"TaskLabel"} + +func (ec *executionContext) _TaskLabel(ctx context.Context, sel ast.SelectionSet, obj *pg.TaskLabel) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, taskLabelImplementors) + + out := graphql.NewFieldSet(fields) + var invalids uint32 + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("TaskLabel") + case "taskLabelID": + out.Values[i] = ec._TaskLabel_taskLabelID(ctx, field, obj) + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "labelColorID": + out.Values[i] = ec._TaskLabel_labelColorID(ctx, field, obj) + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + case "colorHex": + field := field + out.Concurrently(i, func() (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._TaskLabel_colorHex(ctx, field, obj) + if res == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + return res + }) + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch() + if invalids > 0 { + return graphql.Null + } + return out +} + var teamImplementors = []string{"Team"} func (ec *executionContext) _Team(ctx context.Context, sel ast.SelectionSet, obj *pg.Team) graphql.Marshaler { @@ -5329,32 +6320,18 @@ func (ec *executionContext) _Team(ctx context.Context, sel ast.SelectionSet, obj case "teamID": out.Values[i] = ec._Team_teamID(ctx, field, obj) if out.Values[i] == graphql.Null { - atomic.AddUint32(&invalids, 1) + invalids++ } case "createdAt": out.Values[i] = ec._Team_createdAt(ctx, field, obj) if out.Values[i] == graphql.Null { - atomic.AddUint32(&invalids, 1) + invalids++ } case "name": out.Values[i] = ec._Team_name(ctx, field, obj) if out.Values[i] == graphql.Null { - atomic.AddUint32(&invalids, 1) + invalids++ } - case "projects": - field := field - out.Concurrently(i, func() (res graphql.Marshaler) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - } - }() - res = ec._Team_projects(ctx, field, obj) - if res == graphql.Null { - atomic.AddUint32(&invalids, 1) - } - return res - }) default: panic("unknown field " + strconv.Quote(field.Name)) } @@ -5380,28 +6357,47 @@ func (ec *executionContext) _UserAccount(ctx context.Context, sel ast.SelectionS case "userID": out.Values[i] = ec._UserAccount_userID(ctx, field, obj) if out.Values[i] == graphql.Null { - invalids++ + atomic.AddUint32(&invalids, 1) } case "email": out.Values[i] = ec._UserAccount_email(ctx, field, obj) if out.Values[i] == graphql.Null { - invalids++ + atomic.AddUint32(&invalids, 1) } case "createdAt": out.Values[i] = ec._UserAccount_createdAt(ctx, field, obj) if out.Values[i] == graphql.Null { - invalids++ + atomic.AddUint32(&invalids, 1) } - case "displayName": - out.Values[i] = ec._UserAccount_displayName(ctx, field, obj) + case "firstName": + out.Values[i] = ec._UserAccount_firstName(ctx, field, obj) if out.Values[i] == graphql.Null { - invalids++ + atomic.AddUint32(&invalids, 1) + } + case "lastName": + out.Values[i] = ec._UserAccount_lastName(ctx, field, obj) + if out.Values[i] == graphql.Null { + atomic.AddUint32(&invalids, 1) } case "username": out.Values[i] = ec._UserAccount_username(ctx, field, obj) if out.Values[i] == graphql.Null { - invalids++ + atomic.AddUint32(&invalids, 1) } + case "profileIcon": + field := field + out.Concurrently(i, func() (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._UserAccount_profileIcon(ctx, field, obj) + if res == graphql.Null { + atomic.AddUint32(&invalids, 1) + } + return res + }) default: panic("unknown field " + strconv.Quote(field.Name)) } @@ -5712,6 +6708,10 @@ func (ec *executionContext) unmarshalNFindProject2githubᚗcomᚋjordanknottᚋp return ec.unmarshalInputFindProject(ctx, v) } +func (ec *executionContext) unmarshalNFindTask2githubᚗcomᚋjordanknottᚋprojectᚑcitadelᚋapiᚋgraphᚐFindTask(ctx context.Context, v interface{}) (FindTask, error) { + return ec.unmarshalInputFindTask(ctx, v) +} + func (ec *executionContext) unmarshalNFindUser2githubᚗcomᚋjordanknottᚋprojectᚑcitadelᚋapiᚋgraphᚐFindUser(ctx context.Context, v interface{}) (FindUser, error) { return ec.unmarshalInputFindUser(ctx, v) } @@ -5762,10 +6762,6 @@ func (ec *executionContext) unmarshalNLogoutUser2githubᚗcomᚋjordanknottᚋpr return ec.unmarshalInputLogoutUser(ctx, v) } -func (ec *executionContext) unmarshalNNewOrganization2githubᚗcomᚋjordanknottᚋprojectᚑcitadelᚋapiᚋgraphᚐNewOrganization(ctx context.Context, v interface{}) (NewOrganization, error) { - return ec.unmarshalInputNewOrganization(ctx, v) -} - func (ec *executionContext) unmarshalNNewProject2githubᚗcomᚋjordanknottᚋprojectᚑcitadelᚋapiᚋgraphᚐNewProject(ctx context.Context, v interface{}) (NewProject, error) { return ec.unmarshalInputNewProject(ctx, v) } @@ -5798,55 +6794,18 @@ func (ec *executionContext) unmarshalNNewUserAccount2githubᚗcomᚋjordanknott return ec.unmarshalInputNewUserAccount(ctx, v) } -func (ec *executionContext) marshalNOrganization2githubᚗcomᚋjordanknottᚋprojectᚑcitadelᚋapiᚋpgᚐOrganization(ctx context.Context, sel ast.SelectionSet, v pg.Organization) graphql.Marshaler { - return ec._Organization(ctx, sel, &v) +func (ec *executionContext) marshalNProfileIcon2githubᚗcomᚋjordanknottᚋprojectᚑcitadelᚋapiᚋgraphᚐProfileIcon(ctx context.Context, sel ast.SelectionSet, v ProfileIcon) graphql.Marshaler { + return ec._ProfileIcon(ctx, sel, &v) } -func (ec *executionContext) marshalNOrganization2ᚕgithubᚗcomᚋjordanknottᚋprojectᚑcitadelᚋapiᚋpgᚐOrganizationᚄ(ctx context.Context, sel ast.SelectionSet, v []pg.Organization) graphql.Marshaler { - ret := make(graphql.Array, len(v)) - var wg sync.WaitGroup - isLen1 := len(v) == 1 - if !isLen1 { - wg.Add(len(v)) - } - for i := range v { - i := i - fc := &graphql.FieldContext{ - Index: &i, - Result: &v[i], - } - ctx := graphql.WithFieldContext(ctx, fc) - f := func(i int) { - defer func() { - if r := recover(); r != nil { - ec.Error(ctx, ec.Recover(ctx, r)) - ret = nil - } - }() - if !isLen1 { - defer wg.Done() - } - ret[i] = ec.marshalNOrganization2githubᚗcomᚋjordanknottᚋprojectᚑcitadelᚋapiᚋpgᚐOrganization(ctx, sel, v[i]) - } - if isLen1 { - f(i) - } else { - go f(i) - } - - } - wg.Wait() - return ret -} - -func (ec *executionContext) marshalNOrganization2ᚖgithubᚗcomᚋjordanknottᚋprojectᚑcitadelᚋapiᚋpgᚐOrganization(ctx context.Context, sel ast.SelectionSet, v *pg.Organization) graphql.Marshaler { +func (ec *executionContext) marshalNProfileIcon2ᚖgithubᚗcomᚋjordanknottᚋprojectᚑcitadelᚋapiᚋgraphᚐProfileIcon(ctx context.Context, sel ast.SelectionSet, v *ProfileIcon) graphql.Marshaler { if v == nil { if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { ec.Errorf(ctx, "must not be null") } return graphql.Null } - return ec._Organization(ctx, sel, v) + return ec._ProfileIcon(ctx, sel, v) } func (ec *executionContext) marshalNProject2githubᚗcomᚋjordanknottᚋprojectᚑcitadelᚋapiᚋpgᚐProject(ctx context.Context, sel ast.SelectionSet, v pg.Project) graphql.Marshaler { @@ -5900,6 +6859,57 @@ func (ec *executionContext) marshalNProject2ᚖgithubᚗcomᚋjordanknottᚋproj return ec._Project(ctx, sel, v) } +func (ec *executionContext) marshalNProjectMember2githubᚗcomᚋjordanknottᚋprojectᚑcitadelᚋapiᚋgraphᚐProjectMember(ctx context.Context, sel ast.SelectionSet, v ProjectMember) graphql.Marshaler { + return ec._ProjectMember(ctx, sel, &v) +} + +func (ec *executionContext) marshalNProjectMember2ᚕgithubᚗcomᚋjordanknottᚋprojectᚑcitadelᚋapiᚋgraphᚐProjectMemberᚄ(ctx context.Context, sel ast.SelectionSet, v []ProjectMember) graphql.Marshaler { + ret := make(graphql.Array, len(v)) + var wg sync.WaitGroup + isLen1 := len(v) == 1 + if !isLen1 { + wg.Add(len(v)) + } + for i := range v { + i := i + fc := &graphql.FieldContext{ + Index: &i, + Result: &v[i], + } + ctx := graphql.WithFieldContext(ctx, fc) + f := func(i int) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + if !isLen1 { + defer wg.Done() + } + ret[i] = ec.marshalNProjectMember2githubᚗcomᚋjordanknottᚋprojectᚑcitadelᚋapiᚋgraphᚐProjectMember(ctx, sel, v[i]) + } + if isLen1 { + f(i) + } else { + go f(i) + } + + } + wg.Wait() + return ret +} + +func (ec *executionContext) marshalNProjectMember2ᚖgithubᚗcomᚋjordanknottᚋprojectᚑcitadelᚋapiᚋgraphᚐProjectMember(ctx context.Context, sel ast.SelectionSet, v *ProjectMember) graphql.Marshaler { + if v == nil { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + return ec._ProjectMember(ctx, sel, v) +} + func (ec *executionContext) marshalNRefreshToken2githubᚗcomᚋjordanknottᚋprojectᚑcitadelᚋapiᚋpgᚐRefreshToken(ctx context.Context, sel ast.SelectionSet, v pg.RefreshToken) graphql.Marshaler { return ec._RefreshToken(ctx, sel, &v) } @@ -6030,11 +7040,11 @@ func (ec *executionContext) marshalNTaskGroup2ᚖgithubᚗcomᚋjordanknottᚋpr return ec._TaskGroup(ctx, sel, v) } -func (ec *executionContext) marshalNTeam2githubᚗcomᚋjordanknottᚋprojectᚑcitadelᚋapiᚋpgᚐTeam(ctx context.Context, sel ast.SelectionSet, v pg.Team) graphql.Marshaler { - return ec._Team(ctx, sel, &v) +func (ec *executionContext) marshalNTaskLabel2githubᚗcomᚋjordanknottᚋprojectᚑcitadelᚋapiᚋpgᚐTaskLabel(ctx context.Context, sel ast.SelectionSet, v pg.TaskLabel) graphql.Marshaler { + return ec._TaskLabel(ctx, sel, &v) } -func (ec *executionContext) marshalNTeam2ᚕgithubᚗcomᚋjordanknottᚋprojectᚑcitadelᚋapiᚋpgᚐTeamᚄ(ctx context.Context, sel ast.SelectionSet, v []pg.Team) graphql.Marshaler { +func (ec *executionContext) marshalNTaskLabel2ᚕgithubᚗcomᚋjordanknottᚋprojectᚑcitadelᚋapiᚋpgᚐTaskLabelᚄ(ctx context.Context, sel ast.SelectionSet, v []pg.TaskLabel) graphql.Marshaler { ret := make(graphql.Array, len(v)) var wg sync.WaitGroup isLen1 := len(v) == 1 @@ -6058,7 +7068,7 @@ func (ec *executionContext) marshalNTeam2ᚕgithubᚗcomᚋjordanknottᚋproject if !isLen1 { defer wg.Done() } - ret[i] = ec.marshalNTeam2githubᚗcomᚋjordanknottᚋprojectᚑcitadelᚋapiᚋpgᚐTeam(ctx, sel, v[i]) + ret[i] = ec.marshalNTaskLabel2githubᚗcomᚋjordanknottᚋprojectᚑcitadelᚋapiᚋpgᚐTaskLabel(ctx, sel, v[i]) } if isLen1 { f(i) @@ -6071,6 +7081,10 @@ func (ec *executionContext) marshalNTeam2ᚕgithubᚗcomᚋjordanknottᚋproject return ret } +func (ec *executionContext) marshalNTeam2githubᚗcomᚋjordanknottᚋprojectᚑcitadelᚋapiᚋpgᚐTeam(ctx context.Context, sel ast.SelectionSet, v pg.Team) graphql.Marshaler { + return ec._Team(ctx, sel, &v) +} + func (ec *executionContext) marshalNTeam2ᚖgithubᚗcomᚋjordanknottᚋprojectᚑcitadelᚋapiᚋpgᚐTeam(ctx context.Context, sel ast.SelectionSet, v *pg.Team) graphql.Marshaler { if v == nil { if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { @@ -6109,6 +7123,10 @@ func (ec *executionContext) marshalNUUID2githubᚗcomᚋgoogleᚋuuidᚐUUID(ctx return res } +func (ec *executionContext) unmarshalNUpdateTaskDescriptionInput2githubᚗcomᚋjordanknottᚋprojectᚑcitadelᚋapiᚋgraphᚐUpdateTaskDescriptionInput(ctx context.Context, v interface{}) (UpdateTaskDescriptionInput, error) { + return ec.unmarshalInputUpdateTaskDescriptionInput(ctx, v) +} + func (ec *executionContext) unmarshalNUpdateTaskName2githubᚗcomᚋjordanknottᚋprojectᚑcitadelᚋapiᚋgraphᚐUpdateTaskName(ctx context.Context, v interface{}) (UpdateTaskName, error) { return ec.unmarshalInputUpdateTaskName(ctx, v) } @@ -6390,6 +7408,30 @@ func (ec *executionContext) marshalN__TypeKind2string(ctx context.Context, sel a return res } +func (ec *executionContext) unmarshalOAddTaskLabelInput2githubᚗcomᚋjordanknottᚋprojectᚑcitadelᚋapiᚋgraphᚐAddTaskLabelInput(ctx context.Context, v interface{}) (AddTaskLabelInput, error) { + return ec.unmarshalInputAddTaskLabelInput(ctx, v) +} + +func (ec *executionContext) unmarshalOAddTaskLabelInput2ᚖgithubᚗcomᚋjordanknottᚋprojectᚑcitadelᚋapiᚋgraphᚐAddTaskLabelInput(ctx context.Context, v interface{}) (*AddTaskLabelInput, error) { + if v == nil { + return nil, nil + } + res, err := ec.unmarshalOAddTaskLabelInput2githubᚗcomᚋjordanknottᚋprojectᚑcitadelᚋapiᚋgraphᚐAddTaskLabelInput(ctx, v) + return &res, err +} + +func (ec *executionContext) unmarshalOAssignTaskInput2githubᚗcomᚋjordanknottᚋprojectᚑcitadelᚋapiᚋgraphᚐAssignTaskInput(ctx context.Context, v interface{}) (AssignTaskInput, error) { + return ec.unmarshalInputAssignTaskInput(ctx, v) +} + +func (ec *executionContext) unmarshalOAssignTaskInput2ᚖgithubᚗcomᚋjordanknottᚋprojectᚑcitadelᚋapiᚋgraphᚐAssignTaskInput(ctx context.Context, v interface{}) (*AssignTaskInput, error) { + if v == nil { + return nil, nil + } + res, err := ec.unmarshalOAssignTaskInput2githubᚗcomᚋjordanknottᚋprojectᚑcitadelᚋapiᚋgraphᚐAssignTaskInput(ctx, v) + return &res, err +} + func (ec *executionContext) unmarshalOBoolean2bool(ctx context.Context, v interface{}) (bool, error) { return graphql.UnmarshalBoolean(v) } @@ -6425,6 +7467,18 @@ func (ec *executionContext) unmarshalOProjectsFilter2ᚖgithubᚗcomᚋjordankno return &res, err } +func (ec *executionContext) unmarshalORemoveTaskLabelInput2githubᚗcomᚋjordanknottᚋprojectᚑcitadelᚋapiᚋgraphᚐRemoveTaskLabelInput(ctx context.Context, v interface{}) (RemoveTaskLabelInput, error) { + return ec.unmarshalInputRemoveTaskLabelInput(ctx, v) +} + +func (ec *executionContext) unmarshalORemoveTaskLabelInput2ᚖgithubᚗcomᚋjordanknottᚋprojectᚑcitadelᚋapiᚋgraphᚐRemoveTaskLabelInput(ctx context.Context, v interface{}) (*RemoveTaskLabelInput, error) { + if v == nil { + return nil, nil + } + res, err := ec.unmarshalORemoveTaskLabelInput2githubᚗcomᚋjordanknottᚋprojectᚑcitadelᚋapiᚋgraphᚐRemoveTaskLabelInput(ctx, v) + return &res, err +} + func (ec *executionContext) unmarshalOString2string(ctx context.Context, v interface{}) (string, error) { return graphql.UnmarshalString(v) } diff --git a/api/graph/graph.go b/api/graph/graph.go index 6384673..089d12b 100644 --- a/api/graph/graph.go +++ b/api/graph/graph.go @@ -1,6 +1,7 @@ package graph import ( + "context" "net/http" "os" "time" @@ -10,6 +11,7 @@ import ( "github.com/99designs/gqlgen/graphql/handler/lru" "github.com/99designs/gqlgen/graphql/handler/transport" "github.com/99designs/gqlgen/graphql/playground" + "github.com/google/uuid" "github.com/jordanknott/project-citadel/api/pg" ) @@ -45,3 +47,7 @@ func NewHandler(repo pg.Repository) http.Handler { func NewPlaygroundHandler(endpoint string) http.Handler { return playground.Handler("GraphQL Playground", endpoint) } +func GetUserID(ctx context.Context) (uuid.UUID, bool) { + userID, ok := ctx.Value("userID").(uuid.UUID) + return userID, ok +} diff --git a/api/graph/models_gen.go b/api/graph/models_gen.go index 250208f..bf136ff 100644 --- a/api/graph/models_gen.go +++ b/api/graph/models_gen.go @@ -7,6 +7,16 @@ import ( "github.com/jordanknott/project-citadel/api/pg" ) +type AddTaskLabelInput struct { + TaskID uuid.UUID `json:"taskID"` + LabelColorID uuid.UUID `json:"labelColorID"` +} + +type AssignTaskInput struct { + TaskID uuid.UUID `json:"taskID"` + UserID uuid.UUID `json:"userID"` +} + type DeleteTaskGroupInput struct { TaskGroupID uuid.UUID `json:"taskGroupID"` } @@ -29,6 +39,10 @@ type FindProject struct { ProjectID string `json:"projectId"` } +type FindTask struct { + TaskID uuid.UUID `json:"taskID"` +} + type FindUser struct { UserID string `json:"userId"` } @@ -37,13 +51,10 @@ type LogoutUser struct { UserID string `json:"userID"` } -type NewOrganization struct { - Name string `json:"name"` -} - type NewProject struct { - TeamID string `json:"teamID"` - Name string `json:"name"` + UserID uuid.UUID `json:"userID"` + TeamID uuid.UUID `json:"teamID"` + Name string `json:"name"` } type NewRefreshToken struct { @@ -79,16 +90,39 @@ type NewTeam struct { } type NewUserAccount struct { - Username string `json:"username"` - Email string `json:"email"` - DisplayName string `json:"displayName"` - Password string `json:"password"` + Username string `json:"username"` + Email string `json:"email"` + FirstName string `json:"firstName"` + LastName string `json:"lastName"` + Password string `json:"password"` +} + +type ProfileIcon struct { + URL *string `json:"url"` + Initials *string `json:"initials"` +} + +type ProjectMember struct { + UserID uuid.UUID `json:"userID"` + FirstName string `json:"firstName"` + LastName string `json:"lastName"` + ProfileIcon *ProfileIcon `json:"profileIcon"` } type ProjectsFilter struct { TeamID *string `json:"teamID"` } +type RemoveTaskLabelInput struct { + TaskID uuid.UUID `json:"taskID"` + TaskLabelID uuid.UUID `json:"taskLabelID"` +} + +type UpdateTaskDescriptionInput struct { + TaskID uuid.UUID `json:"taskID"` + Description string `json:"description"` +} + type UpdateTaskName struct { TaskID string `json:"taskID"` Name string `json:"name"` diff --git a/api/graph/schema.graphqls b/api/graph/schema.graphqls index 452c952..349f297 100644 --- a/api/graph/schema.graphqls +++ b/api/graph/schema.graphqls @@ -1,7 +1,24 @@ scalar Time - scalar UUID +type TaskLabel { + taskLabelID: ID! + labelColorID: UUID! + colorHex: String! +} + +type ProfileIcon { + url: String + initials: String +} + +type ProjectMember { + userID: ID! + firstName: String! + lastName: String! + profileIcon: ProfileIcon! +} + type RefreshToken { tokenId: ID! userId: UUID! @@ -13,30 +30,26 @@ type UserAccount { userID: ID! email: String! createdAt: Time! - displayName: String! + firstName: String! + lastName: String! username: String! -} - -type Organization { - organizationID: ID! - createdAt: Time! - name: String! - teams: [Team!]! + profileIcon: ProfileIcon! } type Team { teamID: ID! createdAt: Time! name: String! - projects: [Project!]! } type Project { projectID: ID! - teamID: String! createdAt: Time! name: String! + team: Team! + owner: ProjectMember! taskGroups: [TaskGroup!]! + members: [ProjectMember!]! } type TaskGroup { @@ -54,6 +67,9 @@ type Task { createdAt: Time! name: String! position: Float! + description: String + assigned: [ProjectMember!]! + labels: [TaskLabel!]! } input ProjectsFilter { @@ -68,14 +84,18 @@ input FindProject { projectId: String! } +input FindTask { + taskID: UUID! +} + type Query { - organizations: [Organization!]! users: [UserAccount!]! findUser(input: FindUser!): UserAccount! findProject(input: FindProject!): Project! - teams: [Team!]! + findTask(input: FindTask!): Task! projects(input: ProjectsFilter): [Project!]! taskGroups: [TaskGroup!]! + me: UserAccount! } input NewRefreshToken { @@ -85,7 +105,8 @@ input NewRefreshToken { input NewUserAccount { username: String! email: String! - displayName: String! + firstName: String! + lastName: String! password: String! } @@ -95,7 +116,8 @@ input NewTeam { } input NewProject { - teamID: String! + userID: UUID! + teamID: UUID! name: String! } @@ -105,10 +127,6 @@ input NewTaskGroup { position: Float! } -input NewOrganization { - name: String! -} - input LogoutUser { userID: String! } @@ -151,13 +169,31 @@ type DeleteTaskGroupPayload { taskGroup: TaskGroup! } +input AssignTaskInput { + taskID: UUID! + userID: UUID! +} + +input UpdateTaskDescriptionInput { + taskID: UUID! + description: String! +} + +input AddTaskLabelInput { + taskID: UUID! + labelColorID: UUID! +} + +input RemoveTaskLabelInput { + taskID: UUID! + taskLabelID: UUID! +} + type Mutation { createRefreshToken(input: NewRefreshToken!): RefreshToken! createUserAccount(input: NewUserAccount!): UserAccount! - createOrganization(input: NewOrganization!): Organization! - createTeam(input: NewTeam!): Team! createProject(input: NewProject!): Project! @@ -166,10 +202,15 @@ type Mutation { updateTaskGroupLocation(input: NewTaskGroupLocation!): TaskGroup! deleteTaskGroup(input: DeleteTaskGroupInput!): DeleteTaskGroupPayload! + addTaskLabel(input: AddTaskLabelInput): Task! + removeTaskLabel(input: RemoveTaskLabelInput): Task! + createTask(input: NewTask!): Task! + updateTaskDescription(input: UpdateTaskDescriptionInput!): Task! updateTaskLocation(input: NewTaskLocation!): Task! updateTaskName(input: UpdateTaskName!): Task! deleteTask(input: DeleteTaskInput!): DeleteTaskPayload! + assignTask(input: AssignTaskInput): Task! logoutUser(input: LogoutUser!): Boolean! } diff --git a/api/graph/schema.resolvers.go b/api/graph/schema.resolvers.go index dc2785f..02940b7 100644 --- a/api/graph/schema.resolvers.go +++ b/api/graph/schema.resolvers.go @@ -6,6 +6,7 @@ package graph import ( "context" "database/sql" + "fmt" "time" "github.com/google/uuid" @@ -24,16 +25,10 @@ func (r *mutationResolver) CreateRefreshToken(ctx context.Context, input NewRefr func (r *mutationResolver) CreateUserAccount(ctx context.Context, input NewUserAccount) (*pg.UserAccount, error) { createdAt := time.Now().UTC() - userAccount, err := r.Repository.CreateUserAccount(ctx, pg.CreateUserAccountParams{input.Username, input.Email, input.DisplayName, createdAt, input.Password}) + userAccount, err := r.Repository.CreateUserAccount(ctx, pg.CreateUserAccountParams{input.FirstName, input.LastName, input.Email, input.Username, createdAt, input.Password}) return &userAccount, err } -func (r *mutationResolver) CreateOrganization(ctx context.Context, input NewOrganization) (*pg.Organization, error) { - createdAt := time.Now().UTC() - organization, err := r.Repository.CreateOrganization(ctx, pg.CreateOrganizationParams{createdAt, input.Name}) - return &organization, err -} - func (r *mutationResolver) CreateTeam(ctx context.Context, input NewTeam) (*pg.Team, error) { organizationID, err := uuid.Parse(input.OrganizationID) if err != nil { @@ -46,11 +41,7 @@ func (r *mutationResolver) CreateTeam(ctx context.Context, input NewTeam) (*pg.T func (r *mutationResolver) CreateProject(ctx context.Context, input NewProject) (*pg.Project, error) { createdAt := time.Now().UTC() - teamID, err := uuid.Parse(input.TeamID) - if err != nil { - return &pg.Project{}, err - } - project, err := r.Repository.CreateProject(ctx, pg.CreateProjectParams{teamID, createdAt, input.Name}) + project, err := r.Repository.CreateProject(ctx, pg.CreateProjectParams{input.UserID, input.TeamID, createdAt, input.Name}) return &project, err } @@ -89,6 +80,20 @@ func (r *mutationResolver) DeleteTaskGroup(ctx context.Context, input DeleteTask return &DeleteTaskGroupPayload{true, int(deletedTasks + deletedTaskGroups), &taskGroup}, nil } +func (r *mutationResolver) AddTaskLabel(ctx context.Context, input *AddTaskLabelInput) (*pg.Task, error) { + assignedDate := time.Now().UTC() + _, err := r.Repository.CreateTaskLabelForTask(ctx, pg.CreateTaskLabelForTaskParams{input.TaskID, input.LabelColorID, assignedDate}) + if err != nil { + return &pg.Task{}, err + } + task, err := r.Repository.GetTaskByID(ctx, input.TaskID) + return &task, nil +} + +func (r *mutationResolver) RemoveTaskLabel(ctx context.Context, input *RemoveTaskLabelInput) (*pg.Task, error) { + panic(fmt.Errorf("not implemented")) +} + func (r *mutationResolver) CreateTask(ctx context.Context, input NewTask) (*pg.Task, error) { taskGroupID, err := uuid.Parse(input.TaskGroupID) createdAt := time.Now().UTC() @@ -100,6 +105,11 @@ func (r *mutationResolver) CreateTask(ctx context.Context, input NewTask) (*pg.T return &task, err } +func (r *mutationResolver) UpdateTaskDescription(ctx context.Context, input UpdateTaskDescriptionInput) (*pg.Task, error) { + task, err := r.Repository.UpdateTaskDescription(ctx, pg.UpdateTaskDescriptionParams{input.TaskID, sql.NullString{String: input.Description, Valid: true}}) + return &task, err +} + func (r *mutationResolver) UpdateTaskLocation(ctx context.Context, input NewTaskLocation) (*pg.Task, error) { taskID, err := uuid.Parse(input.TaskID) if err != nil { @@ -139,6 +149,21 @@ func (r *mutationResolver) DeleteTask(ctx context.Context, input DeleteTaskInput return &DeleteTaskPayload{taskID.String()}, nil } +func (r *mutationResolver) AssignTask(ctx context.Context, input *AssignTaskInput) (*pg.Task, error) { + assignedDate := time.Now().UTC() + assignedTask, err := r.Repository.CreateTaskAssigned(ctx, pg.CreateTaskAssignedParams{input.TaskID, input.UserID, assignedDate}) + log.WithFields(log.Fields{ + "userID": assignedTask.UserID, + "taskID": assignedTask.TaskID, + "assignedTaskID": assignedTask.TaskAssignedID, + }).Info("assigned task") + if err != nil { + return &pg.Task{}, err + } + task, err := r.Repository.GetTaskByID(ctx, input.TaskID) + return &task, err +} + func (r *mutationResolver) LogoutUser(ctx context.Context, input LogoutUser) (bool, error) { userID, err := uuid.Parse(input.UserID) if err != nil { @@ -149,21 +174,35 @@ func (r *mutationResolver) LogoutUser(ctx context.Context, input LogoutUser) (bo return true, err } -func (r *organizationResolver) Teams(ctx context.Context, obj *pg.Organization) ([]pg.Team, error) { - teams, err := r.Repository.GetTeamsForOrganization(ctx, obj.OrganizationID) - return teams, err +func (r *projectResolver) Team(ctx context.Context, obj *pg.Project) (*pg.Team, error) { + team, err := r.Repository.GetTeamByID(ctx, obj.TeamID) + return &team, err } -func (r *projectResolver) TeamID(ctx context.Context, obj *pg.Project) (string, error) { - return obj.TeamID.String(), nil +func (r *projectResolver) Owner(ctx context.Context, obj *pg.Project) (*ProjectMember, error) { + user, err := r.Repository.GetUserAccountByID(ctx, obj.Owner) + if err != nil { + return &ProjectMember{}, err + } + initials := string([]rune(user.FirstName)[0]) + string([]rune(user.LastName)[0]) + profileIcon := &ProfileIcon{nil, &initials} + return &ProjectMember{obj.Owner, user.FirstName, user.LastName, profileIcon}, nil } func (r *projectResolver) TaskGroups(ctx context.Context, obj *pg.Project) ([]pg.TaskGroup, error) { return r.Repository.GetTaskGroupsForProject(ctx, obj.ProjectID) } -func (r *queryResolver) Organizations(ctx context.Context) ([]pg.Organization, error) { - return r.Repository.GetAllOrganizations(ctx) +func (r *projectResolver) Members(ctx context.Context, obj *pg.Project) ([]ProjectMember, error) { + user, err := r.Repository.GetUserAccountByID(ctx, obj.Owner) + members := []ProjectMember{} + if err != nil { + return members, err + } + initials := string([]rune(user.FirstName)[0]) + string([]rune(user.LastName)[0]) + profileIcon := &ProfileIcon{nil, &initials} + members = append(members, ProjectMember{obj.Owner, user.FirstName, user.LastName, profileIcon}) + return members, nil } func (r *queryResolver) Users(ctx context.Context) ([]pg.UserAccount, error) { @@ -204,8 +243,9 @@ func (r *queryResolver) FindProject(ctx context.Context, input FindProject) (*pg return &project, err } -func (r *queryResolver) Teams(ctx context.Context) ([]pg.Team, error) { - return r.Repository.GetAllTeams(ctx) +func (r *queryResolver) FindTask(ctx context.Context, input FindTask) (*pg.Task, error) { + task, err := r.Repository.GetTaskByID(ctx, input.TaskID) + return &task, err } func (r *queryResolver) Projects(ctx context.Context, input *ProjectsFilter) ([]pg.Project, error) { @@ -223,11 +263,59 @@ func (r *queryResolver) TaskGroups(ctx context.Context) ([]pg.TaskGroup, error) return r.Repository.GetAllTaskGroups(ctx) } +func (r *queryResolver) Me(ctx context.Context) (*pg.UserAccount, error) { + userID, ok := GetUserID(ctx) + if !ok { + return &pg.UserAccount{}, fmt.Errorf("internal server error") + } + log.WithFields(log.Fields{ + "userID": userID, + }).Info("getting user account") + user, err := r.Repository.GetUserAccountByID(ctx, userID) + if err != nil { + return &pg.UserAccount{}, err + } + return &user, err +} + func (r *taskResolver) TaskGroup(ctx context.Context, obj *pg.Task) (*pg.TaskGroup, error) { taskGroup, err := r.Repository.GetTaskGroupByID(ctx, obj.TaskGroupID) return &taskGroup, err } +func (r *taskResolver) Description(ctx context.Context, obj *pg.Task) (*string, error) { + task, err := r.Repository.GetTaskByID(ctx, obj.TaskID) + if err != nil { + return nil, err + } + if !task.Description.Valid { + return nil, nil + } + return &task.Description.String, nil +} + +func (r *taskResolver) Assigned(ctx context.Context, obj *pg.Task) ([]ProjectMember, error) { + taskMemberLinks, err := r.Repository.GetAssignedMembersForTask(ctx, obj.TaskID) + taskMembers := []ProjectMember{} + if err != nil { + return taskMembers, err + } + for _, taskMemberLink := range taskMemberLinks { + user, err := r.Repository.GetUserAccountByID(ctx, taskMemberLink.UserID) + if err != nil { + return taskMembers, err + } + initials := string([]rune(user.FirstName)[0]) + string([]rune(user.LastName)[0]) + profileIcon := &ProfileIcon{nil, &initials} + taskMembers = append(taskMembers, ProjectMember{taskMemberLink.UserID, user.FirstName, user.LastName, profileIcon}) + } + return taskMembers, nil +} + +func (r *taskResolver) Labels(ctx context.Context, obj *pg.Task) ([]pg.TaskLabel, error) { + return r.Repository.GetTaskLabelsForTaskID(ctx, obj.TaskID) +} + func (r *taskGroupResolver) ProjectID(ctx context.Context, obj *pg.TaskGroup) (string, error) { return obj.ProjectID.String(), nil } @@ -237,16 +325,23 @@ func (r *taskGroupResolver) Tasks(ctx context.Context, obj *pg.TaskGroup) ([]pg. return tasks, err } -func (r *teamResolver) Projects(ctx context.Context, obj *pg.Team) ([]pg.Project, error) { - return r.Repository.GetAllProjectsForTeam(ctx, obj.TeamID) +func (r *taskLabelResolver) ColorHex(ctx context.Context, obj *pg.TaskLabel) (string, error) { + labelColor, err := r.Repository.GetLabelColorByID(ctx, obj.LabelColorID) + if err != nil { + return "", err + } + return labelColor.ColorHex, nil +} + +func (r *userAccountResolver) ProfileIcon(ctx context.Context, obj *pg.UserAccount) (*ProfileIcon, error) { + initials := string([]rune(obj.FirstName)[0]) + string([]rune(obj.LastName)[0]) + profileIcon := &ProfileIcon{nil, &initials} + return profileIcon, nil } // Mutation returns MutationResolver implementation. func (r *Resolver) Mutation() MutationResolver { return &mutationResolver{r} } -// Organization returns OrganizationResolver implementation. -func (r *Resolver) Organization() OrganizationResolver { return &organizationResolver{r} } - // Project returns ProjectResolver implementation. func (r *Resolver) Project() ProjectResolver { return &projectResolver{r} } @@ -259,13 +354,26 @@ func (r *Resolver) Task() TaskResolver { return &taskResolver{r} } // TaskGroup returns TaskGroupResolver implementation. func (r *Resolver) TaskGroup() TaskGroupResolver { return &taskGroupResolver{r} } -// Team returns TeamResolver implementation. -func (r *Resolver) Team() TeamResolver { return &teamResolver{r} } +// TaskLabel returns TaskLabelResolver implementation. +func (r *Resolver) TaskLabel() TaskLabelResolver { return &taskLabelResolver{r} } + +// UserAccount returns UserAccountResolver implementation. +func (r *Resolver) UserAccount() UserAccountResolver { return &userAccountResolver{r} } type mutationResolver struct{ *Resolver } -type organizationResolver struct{ *Resolver } type projectResolver struct{ *Resolver } type queryResolver struct{ *Resolver } type taskResolver struct{ *Resolver } type taskGroupResolver struct{ *Resolver } -type teamResolver struct{ *Resolver } +type taskLabelResolver 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 *userAccountResolver) DisplayName(ctx context.Context, obj *pg.UserAccount) (string, error) { + return obj.FirstName + " " + obj.LastName, nil +} diff --git a/api/migrations/0002_add-users-table.up.sql b/api/migrations/0002_add-user_account-table.up.sql similarity index 79% rename from api/migrations/0002_add-users-table.up.sql rename to api/migrations/0002_add-user_account-table.up.sql index f0ccf28..0f75518 100644 --- a/api/migrations/0002_add-users-table.up.sql +++ b/api/migrations/0002_add-user_account-table.up.sql @@ -1,7 +1,8 @@ CREATE TABLE user_account ( user_id uuid PRIMARY KEY DEFAULT uuid_generate_v4(), created_at timestamptz NOT NULL, - display_name text NOT NULL, + first_name text NOT NULL, + last_name text NOT NULL, email text NOT NULL UNIQUE, username text NOT NULL UNIQUE, password_hash text NOT NULL diff --git a/api/migrations/0009_add-task-assigned-table.up.sql b/api/migrations/0009_add-task-assigned-table.up.sql new file mode 100644 index 0000000..0f76e6a --- /dev/null +++ b/api/migrations/0009_add-task-assigned-table.up.sql @@ -0,0 +1,6 @@ +CREATE TABLE task_assigned ( + task_assigned_id uuid PRIMARY KEY DEFAULT uuid_generate_v4(), + task_id uuid NOT NULL REFERENCES task(task_id), + user_id uuid NOT NULL REFERENCES user_account(user_id), + assigned_date timestamptz NOT NULL +); diff --git a/api/migrations/0010_add-description-to-task-table.up.sql b/api/migrations/0010_add-description-to-task-table.up.sql new file mode 100644 index 0000000..c6e0dde --- /dev/null +++ b/api/migrations/0010_add-description-to-task-table.up.sql @@ -0,0 +1 @@ +ALTER TABLE task ADD COLUMN description text; diff --git a/api/migrations/0011_add-label-color-table.up.sql b/api/migrations/0011_add-label-color-table.up.sql new file mode 100644 index 0000000..395fa06 --- /dev/null +++ b/api/migrations/0011_add-label-color-table.up.sql @@ -0,0 +1,5 @@ +CREATE TABLE label_color ( + label_color_id uuid PRIMARY KEY DEFAULT uuid_generate_v4(), + color_hex TEXT NOT NULL, + position FLOAT NOT NULL +); diff --git a/api/migrations/0012-add-task-label-table.up.sql b/api/migrations/0012-add-task-label-table.up.sql new file mode 100644 index 0000000..bddcc8e --- /dev/null +++ b/api/migrations/0012-add-task-label-table.up.sql @@ -0,0 +1,6 @@ +CREATE TABLE task_label ( + task_label_id uuid PRIMARY KEY DEFAULT uuid_generate_v4(), + task_id uuid NOT NULL REFERENCES task(task_id), + label_color_id uuid NOT NULL REFERENCES label_color(label_color_id), + assigned_date timestamptz NOT NULL +); diff --git a/api/migrations/0013_add-due-date-to-task-table.up.sql b/api/migrations/0013_add-due-date-to-task-table.up.sql new file mode 100644 index 0000000..d760906 --- /dev/null +++ b/api/migrations/0013_add-due-date-to-task-table.up.sql @@ -0,0 +1 @@ +ALTER TABLE task ADD COLUMN due_date timestamptz; diff --git a/api/migrations/0014_add-owner-column-to-project-table.up.sql b/api/migrations/0014_add-owner-column-to-project-table.up.sql new file mode 100644 index 0000000..1a59572 --- /dev/null +++ b/api/migrations/0014_add-owner-column-to-project-table.up.sql @@ -0,0 +1 @@ +ALTER TABLE project ADD COLUMN owner uuid NOT NULL; diff --git a/api/pg/label_color.sql.go b/api/pg/label_color.sql.go new file mode 100644 index 0000000..8aaae7c --- /dev/null +++ b/api/pg/label_color.sql.go @@ -0,0 +1,21 @@ +// Code generated by sqlc. DO NOT EDIT. +// source: label_color.sql + +package pg + +import ( + "context" + + "github.com/google/uuid" +) + +const getLabelColorByID = `-- name: GetLabelColorByID :one +SELECT label_color_id, color_hex, position FROM label_color WHERE label_color_id = $1 +` + +func (q *Queries) GetLabelColorByID(ctx context.Context, labelColorID uuid.UUID) (LabelColor, error) { + row := q.db.QueryRowContext(ctx, getLabelColorByID, labelColorID) + var i LabelColor + err := row.Scan(&i.LabelColorID, &i.ColorHex, &i.Position) + return i, err +} diff --git a/api/pg/models.go b/api/pg/models.go index 54d8f0e..2145255 100644 --- a/api/pg/models.go +++ b/api/pg/models.go @@ -3,11 +3,18 @@ package pg import ( + "database/sql" "time" "github.com/google/uuid" ) +type LabelColor struct { + LabelColorID uuid.UUID `json:"label_color_id"` + ColorHex string `json:"color_hex"` + Position float64 `json:"position"` +} + type Organization struct { OrganizationID uuid.UUID `json:"organization_id"` CreatedAt time.Time `json:"created_at"` @@ -19,6 +26,7 @@ type Project struct { TeamID uuid.UUID `json:"team_id"` CreatedAt time.Time `json:"created_at"` Name string `json:"name"` + Owner uuid.UUID `json:"owner"` } type RefreshToken struct { @@ -29,11 +37,20 @@ type RefreshToken struct { } type Task struct { - TaskID uuid.UUID `json:"task_id"` - TaskGroupID uuid.UUID `json:"task_group_id"` - CreatedAt time.Time `json:"created_at"` - Name string `json:"name"` - Position float64 `json:"position"` + TaskID uuid.UUID `json:"task_id"` + TaskGroupID uuid.UUID `json:"task_group_id"` + CreatedAt time.Time `json:"created_at"` + Name string `json:"name"` + Position float64 `json:"position"` + Description sql.NullString `json:"description"` + DueDate sql.NullTime `json:"due_date"` +} + +type TaskAssigned struct { + TaskAssignedID uuid.UUID `json:"task_assigned_id"` + TaskID uuid.UUID `json:"task_id"` + UserID uuid.UUID `json:"user_id"` + AssignedDate time.Time `json:"assigned_date"` } type TaskGroup struct { @@ -44,6 +61,13 @@ type TaskGroup struct { Position float64 `json:"position"` } +type TaskLabel struct { + TaskLabelID uuid.UUID `json:"task_label_id"` + TaskID uuid.UUID `json:"task_id"` + LabelColorID uuid.UUID `json:"label_color_id"` + AssignedDate time.Time `json:"assigned_date"` +} + type Team struct { TeamID uuid.UUID `json:"team_id"` CreatedAt time.Time `json:"created_at"` @@ -54,7 +78,8 @@ type Team struct { type UserAccount struct { UserID uuid.UUID `json:"user_id"` CreatedAt time.Time `json:"created_at"` - DisplayName string `json:"display_name"` + FirstName string `json:"first_name"` + LastName string `json:"last_name"` Email string `json:"email"` Username string `json:"username"` PasswordHash string `json:"password_hash"` diff --git a/api/pg/pg.go b/api/pg/pg.go index d0cd7ee..19b3bef 100644 --- a/api/pg/pg.go +++ b/api/pg/pg.go @@ -41,11 +41,20 @@ type Repository interface { GetTeamsForOrganization(ctx context.Context, organizationID uuid.UUID) ([]Team, error) CreateTask(ctx context.Context, arg CreateTaskParams) (Task, error) + GetTaskByID(ctx context.Context, taskID uuid.UUID) (Task, error) GetAllTasks(ctx context.Context) ([]Task, error) GetTasksForTaskGroupID(ctx context.Context, taskGroupID uuid.UUID) ([]Task, error) UpdateTaskLocation(ctx context.Context, arg UpdateTaskLocationParams) (Task, error) DeleteTaskByID(ctx context.Context, taskID uuid.UUID) error UpdateTaskName(ctx context.Context, arg UpdateTaskNameParams) (Task, error) + UpdateTaskDescription(ctx context.Context, arg UpdateTaskDescriptionParams) (Task, error) + + CreateTaskLabelForTask(ctx context.Context, arg CreateTaskLabelForTaskParams) (TaskLabel, error) + GetTaskLabelsForTaskID(ctx context.Context, taskID uuid.UUID) ([]TaskLabel, error) + GetLabelColorByID(ctx context.Context, labelColorID uuid.UUID) (LabelColor, error) + + CreateTaskAssigned(ctx context.Context, arg CreateTaskAssignedParams) (TaskAssigned, error) + GetAssignedMembersForTask(ctx context.Context, taskID uuid.UUID) ([]TaskAssigned, error) } type repoSvc struct { diff --git a/api/pg/project.sql.go b/api/pg/project.sql.go index c20c533..1b7f965 100644 --- a/api/pg/project.sql.go +++ b/api/pg/project.sql.go @@ -11,29 +11,36 @@ import ( ) const createProject = `-- name: CreateProject :one -INSERT INTO project(team_id, created_at, name) VALUES ($1, $2, $3) RETURNING project_id, team_id, created_at, name +INSERT INTO project(owner, team_id, created_at, name) VALUES ($1, $2, $3, $4) RETURNING project_id, team_id, created_at, name, owner ` type CreateProjectParams struct { + Owner uuid.UUID `json:"owner"` TeamID uuid.UUID `json:"team_id"` CreatedAt time.Time `json:"created_at"` Name string `json:"name"` } func (q *Queries) CreateProject(ctx context.Context, arg CreateProjectParams) (Project, error) { - row := q.db.QueryRowContext(ctx, createProject, arg.TeamID, arg.CreatedAt, arg.Name) + row := q.db.QueryRowContext(ctx, createProject, + arg.Owner, + arg.TeamID, + arg.CreatedAt, + arg.Name, + ) var i Project err := row.Scan( &i.ProjectID, &i.TeamID, &i.CreatedAt, &i.Name, + &i.Owner, ) return i, err } const getAllProjects = `-- name: GetAllProjects :many -SELECT project_id, team_id, created_at, name FROM project +SELECT project_id, team_id, created_at, name, owner FROM project ` func (q *Queries) GetAllProjects(ctx context.Context) ([]Project, error) { @@ -50,6 +57,7 @@ func (q *Queries) GetAllProjects(ctx context.Context) ([]Project, error) { &i.TeamID, &i.CreatedAt, &i.Name, + &i.Owner, ); err != nil { return nil, err } @@ -65,7 +73,7 @@ func (q *Queries) GetAllProjects(ctx context.Context) ([]Project, error) { } const getAllProjectsForTeam = `-- name: GetAllProjectsForTeam :many -SELECT project_id, team_id, created_at, name FROM project WHERE team_id = $1 +SELECT project_id, team_id, created_at, name, owner FROM project WHERE team_id = $1 ` func (q *Queries) GetAllProjectsForTeam(ctx context.Context, teamID uuid.UUID) ([]Project, error) { @@ -82,6 +90,7 @@ func (q *Queries) GetAllProjectsForTeam(ctx context.Context, teamID uuid.UUID) ( &i.TeamID, &i.CreatedAt, &i.Name, + &i.Owner, ); err != nil { return nil, err } @@ -97,7 +106,7 @@ func (q *Queries) GetAllProjectsForTeam(ctx context.Context, teamID uuid.UUID) ( } const getProjectByID = `-- name: GetProjectByID :one -SELECT project_id, team_id, created_at, name FROM project WHERE project_id = $1 +SELECT project_id, team_id, created_at, name, owner FROM project WHERE project_id = $1 ` func (q *Queries) GetProjectByID(ctx context.Context, projectID uuid.UUID) (Project, error) { @@ -108,6 +117,7 @@ func (q *Queries) GetProjectByID(ctx context.Context, projectID uuid.UUID) (Proj &i.TeamID, &i.CreatedAt, &i.Name, + &i.Owner, ) return i, err } diff --git a/api/pg/querier.go b/api/pg/querier.go index 9cfc696..114709b 100644 --- a/api/pg/querier.go +++ b/api/pg/querier.go @@ -13,7 +13,9 @@ type Querier interface { CreateProject(ctx context.Context, arg CreateProjectParams) (Project, error) CreateRefreshToken(ctx context.Context, arg CreateRefreshTokenParams) (RefreshToken, error) CreateTask(ctx context.Context, arg CreateTaskParams) (Task, error) + CreateTaskAssigned(ctx context.Context, arg CreateTaskAssignedParams) (TaskAssigned, error) CreateTaskGroup(ctx context.Context, arg CreateTaskGroupParams) (TaskGroup, error) + CreateTaskLabelForTask(ctx context.Context, arg CreateTaskLabelForTaskParams) (TaskLabel, error) CreateTeam(ctx context.Context, arg CreateTeamParams) (Team, error) CreateUserAccount(ctx context.Context, arg CreateUserAccountParams) (UserAccount, error) DeleteExpiredTokens(ctx context.Context) error @@ -30,15 +32,20 @@ type Querier interface { GetAllTasks(ctx context.Context) ([]Task, error) GetAllTeams(ctx context.Context) ([]Team, error) GetAllUserAccounts(ctx context.Context) ([]UserAccount, error) + GetAssignedMembersForTask(ctx context.Context, taskID uuid.UUID) ([]TaskAssigned, error) + GetLabelColorByID(ctx context.Context, labelColorID uuid.UUID) (LabelColor, error) GetProjectByID(ctx context.Context, projectID uuid.UUID) (Project, error) GetRefreshTokenByID(ctx context.Context, tokenID uuid.UUID) (RefreshToken, error) + GetTaskByID(ctx context.Context, taskID uuid.UUID) (Task, error) GetTaskGroupByID(ctx context.Context, taskGroupID uuid.UUID) (TaskGroup, error) GetTaskGroupsForProject(ctx context.Context, projectID uuid.UUID) ([]TaskGroup, error) + GetTaskLabelsForTaskID(ctx context.Context, taskID uuid.UUID) ([]TaskLabel, error) GetTasksForTaskGroupID(ctx context.Context, taskGroupID uuid.UUID) ([]Task, error) GetTeamByID(ctx context.Context, teamID uuid.UUID) (Team, error) GetTeamsForOrganization(ctx context.Context, organizationID uuid.UUID) ([]Team, error) GetUserAccountByID(ctx context.Context, userID uuid.UUID) (UserAccount, error) GetUserAccountByUsername(ctx context.Context, username string) (UserAccount, error) + UpdateTaskDescription(ctx context.Context, arg UpdateTaskDescriptionParams) (Task, error) UpdateTaskGroupLocation(ctx context.Context, arg UpdateTaskGroupLocationParams) (TaskGroup, error) UpdateTaskLocation(ctx context.Context, arg UpdateTaskLocationParams) (Task, error) UpdateTaskName(ctx context.Context, arg UpdateTaskNameParams) (Task, error) diff --git a/api/pg/task.sql.go b/api/pg/task.sql.go index f257abf..aa06f59 100644 --- a/api/pg/task.sql.go +++ b/api/pg/task.sql.go @@ -5,6 +5,7 @@ package pg import ( "context" + "database/sql" "time" "github.com/google/uuid" @@ -12,7 +13,7 @@ import ( const createTask = `-- name: CreateTask :one INSERT INTO task (task_group_id, created_at, name, position) - VALUES($1, $2, $3, $4) RETURNING task_id, task_group_id, created_at, name, position + VALUES($1, $2, $3, $4) RETURNING task_id, task_group_id, created_at, name, position, description, due_date ` type CreateTaskParams struct { @@ -36,6 +37,8 @@ func (q *Queries) CreateTask(ctx context.Context, arg CreateTaskParams) (Task, e &i.CreatedAt, &i.Name, &i.Position, + &i.Description, + &i.DueDate, ) return i, err } @@ -62,7 +65,7 @@ func (q *Queries) DeleteTasksByTaskGroupID(ctx context.Context, taskGroupID uuid } const getAllTasks = `-- name: GetAllTasks :many -SELECT task_id, task_group_id, created_at, name, position FROM task +SELECT task_id, task_group_id, created_at, name, position, description, due_date FROM task ` func (q *Queries) GetAllTasks(ctx context.Context) ([]Task, error) { @@ -80,6 +83,8 @@ func (q *Queries) GetAllTasks(ctx context.Context) ([]Task, error) { &i.CreatedAt, &i.Name, &i.Position, + &i.Description, + &i.DueDate, ); err != nil { return nil, err } @@ -94,8 +99,27 @@ func (q *Queries) GetAllTasks(ctx context.Context) ([]Task, error) { return items, nil } +const getTaskByID = `-- name: GetTaskByID :one +SELECT task_id, task_group_id, created_at, name, position, description, due_date FROM task WHERE task_id = $1 +` + +func (q *Queries) GetTaskByID(ctx context.Context, taskID uuid.UUID) (Task, error) { + row := q.db.QueryRowContext(ctx, getTaskByID, taskID) + var i Task + err := row.Scan( + &i.TaskID, + &i.TaskGroupID, + &i.CreatedAt, + &i.Name, + &i.Position, + &i.Description, + &i.DueDate, + ) + return i, err +} + const getTasksForTaskGroupID = `-- name: GetTasksForTaskGroupID :many -SELECT task_id, task_group_id, created_at, name, position FROM task WHERE task_group_id = $1 +SELECT task_id, task_group_id, created_at, name, position, description, due_date FROM task WHERE task_group_id = $1 ` func (q *Queries) GetTasksForTaskGroupID(ctx context.Context, taskGroupID uuid.UUID) ([]Task, error) { @@ -113,6 +137,8 @@ func (q *Queries) GetTasksForTaskGroupID(ctx context.Context, taskGroupID uuid.U &i.CreatedAt, &i.Name, &i.Position, + &i.Description, + &i.DueDate, ); err != nil { return nil, err } @@ -127,8 +153,32 @@ func (q *Queries) GetTasksForTaskGroupID(ctx context.Context, taskGroupID uuid.U return items, nil } +const updateTaskDescription = `-- name: UpdateTaskDescription :one +UPDATE task SET description = $2 WHERE task_id = $1 RETURNING task_id, task_group_id, created_at, name, position, description, due_date +` + +type UpdateTaskDescriptionParams struct { + TaskID uuid.UUID `json:"task_id"` + Description sql.NullString `json:"description"` +} + +func (q *Queries) UpdateTaskDescription(ctx context.Context, arg UpdateTaskDescriptionParams) (Task, error) { + row := q.db.QueryRowContext(ctx, updateTaskDescription, arg.TaskID, arg.Description) + var i Task + err := row.Scan( + &i.TaskID, + &i.TaskGroupID, + &i.CreatedAt, + &i.Name, + &i.Position, + &i.Description, + &i.DueDate, + ) + return i, err +} + const updateTaskLocation = `-- name: UpdateTaskLocation :one -UPDATE task SET task_group_id = $2, position = $3 WHERE task_id = $1 RETURNING task_id, task_group_id, created_at, name, position +UPDATE task SET task_group_id = $2, position = $3 WHERE task_id = $1 RETURNING task_id, task_group_id, created_at, name, position, description, due_date ` type UpdateTaskLocationParams struct { @@ -146,12 +196,14 @@ func (q *Queries) UpdateTaskLocation(ctx context.Context, arg UpdateTaskLocation &i.CreatedAt, &i.Name, &i.Position, + &i.Description, + &i.DueDate, ) return i, err } const updateTaskName = `-- name: UpdateTaskName :one -UPDATE task SET name = $2 WHERE task_id = $1 RETURNING task_id, task_group_id, created_at, name, position +UPDATE task SET name = $2 WHERE task_id = $1 RETURNING task_id, task_group_id, created_at, name, position, description, due_date ` type UpdateTaskNameParams struct { @@ -168,6 +220,8 @@ func (q *Queries) UpdateTaskName(ctx context.Context, arg UpdateTaskNameParams) &i.CreatedAt, &i.Name, &i.Position, + &i.Description, + &i.DueDate, ) return i, err } diff --git a/api/pg/task_assigned.sql.go b/api/pg/task_assigned.sql.go new file mode 100644 index 0000000..e642f54 --- /dev/null +++ b/api/pg/task_assigned.sql.go @@ -0,0 +1,66 @@ +// Code generated by sqlc. DO NOT EDIT. +// source: task_assigned.sql + +package pg + +import ( + "context" + "time" + + "github.com/google/uuid" +) + +const createTaskAssigned = `-- name: CreateTaskAssigned :one +INSERT INTO task_assigned (task_id, user_id, assigned_date) + VALUES($1, $2, $3) RETURNING task_assigned_id, task_id, user_id, assigned_date +` + +type CreateTaskAssignedParams struct { + TaskID uuid.UUID `json:"task_id"` + UserID uuid.UUID `json:"user_id"` + AssignedDate time.Time `json:"assigned_date"` +} + +func (q *Queries) CreateTaskAssigned(ctx context.Context, arg CreateTaskAssignedParams) (TaskAssigned, error) { + row := q.db.QueryRowContext(ctx, createTaskAssigned, arg.TaskID, arg.UserID, arg.AssignedDate) + var i TaskAssigned + err := row.Scan( + &i.TaskAssignedID, + &i.TaskID, + &i.UserID, + &i.AssignedDate, + ) + return i, err +} + +const getAssignedMembersForTask = `-- name: GetAssignedMembersForTask :many +SELECT task_assigned_id, task_id, user_id, assigned_date FROM task_assigned WHERE task_id = $1 +` + +func (q *Queries) GetAssignedMembersForTask(ctx context.Context, taskID uuid.UUID) ([]TaskAssigned, error) { + rows, err := q.db.QueryContext(ctx, getAssignedMembersForTask, taskID) + if err != nil { + return nil, err + } + defer rows.Close() + var items []TaskAssigned + for rows.Next() { + var i TaskAssigned + if err := rows.Scan( + &i.TaskAssignedID, + &i.TaskID, + &i.UserID, + &i.AssignedDate, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} diff --git a/api/pg/task_label.sql.go b/api/pg/task_label.sql.go new file mode 100644 index 0000000..6c47ba4 --- /dev/null +++ b/api/pg/task_label.sql.go @@ -0,0 +1,66 @@ +// Code generated by sqlc. DO NOT EDIT. +// source: task_label.sql + +package pg + +import ( + "context" + "time" + + "github.com/google/uuid" +) + +const createTaskLabelForTask = `-- name: CreateTaskLabelForTask :one +INSERT INTO task_label (task_id, label_color_id, assigned_date) + VALUES ($1, $2, $3) RETURNING task_label_id, task_id, label_color_id, assigned_date +` + +type CreateTaskLabelForTaskParams struct { + TaskID uuid.UUID `json:"task_id"` + LabelColorID uuid.UUID `json:"label_color_id"` + AssignedDate time.Time `json:"assigned_date"` +} + +func (q *Queries) CreateTaskLabelForTask(ctx context.Context, arg CreateTaskLabelForTaskParams) (TaskLabel, error) { + row := q.db.QueryRowContext(ctx, createTaskLabelForTask, arg.TaskID, arg.LabelColorID, arg.AssignedDate) + var i TaskLabel + err := row.Scan( + &i.TaskLabelID, + &i.TaskID, + &i.LabelColorID, + &i.AssignedDate, + ) + return i, err +} + +const getTaskLabelsForTaskID = `-- name: GetTaskLabelsForTaskID :many +SELECT task_label_id, task_id, label_color_id, assigned_date FROM task_label WHERE task_id = $1 +` + +func (q *Queries) GetTaskLabelsForTaskID(ctx context.Context, taskID uuid.UUID) ([]TaskLabel, error) { + rows, err := q.db.QueryContext(ctx, getTaskLabelsForTaskID, taskID) + if err != nil { + return nil, err + } + defer rows.Close() + var items []TaskLabel + for rows.Next() { + var i TaskLabel + if err := rows.Scan( + &i.TaskLabelID, + &i.TaskID, + &i.LabelColorID, + &i.AssignedDate, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} diff --git a/api/pg/user_accounts.sql.go b/api/pg/user_accounts.sql.go index 2be27c7..52f78a1 100644 --- a/api/pg/user_accounts.sql.go +++ b/api/pg/user_accounts.sql.go @@ -11,13 +11,14 @@ import ( ) const createUserAccount = `-- name: CreateUserAccount :one -INSERT INTO user_account(display_name, email, username, created_at, password_hash) - VALUES ($1, $2, $3, $4, $5) -RETURNING user_id, created_at, display_name, email, username, password_hash +INSERT INTO user_account(first_name, last_name, email, username, created_at, password_hash) + VALUES ($1, $2, $3, $4, $5, $6) +RETURNING user_id, created_at, first_name, last_name, email, username, password_hash ` type CreateUserAccountParams struct { - DisplayName string `json:"display_name"` + FirstName string `json:"first_name"` + LastName string `json:"last_name"` Email string `json:"email"` Username string `json:"username"` CreatedAt time.Time `json:"created_at"` @@ -26,7 +27,8 @@ type CreateUserAccountParams struct { func (q *Queries) CreateUserAccount(ctx context.Context, arg CreateUserAccountParams) (UserAccount, error) { row := q.db.QueryRowContext(ctx, createUserAccount, - arg.DisplayName, + arg.FirstName, + arg.LastName, arg.Email, arg.Username, arg.CreatedAt, @@ -36,7 +38,8 @@ func (q *Queries) CreateUserAccount(ctx context.Context, arg CreateUserAccountPa err := row.Scan( &i.UserID, &i.CreatedAt, - &i.DisplayName, + &i.FirstName, + &i.LastName, &i.Email, &i.Username, &i.PasswordHash, @@ -45,7 +48,7 @@ func (q *Queries) CreateUserAccount(ctx context.Context, arg CreateUserAccountPa } const getAllUserAccounts = `-- name: GetAllUserAccounts :many -SELECT user_id, created_at, display_name, email, username, password_hash FROM user_account +SELECT user_id, created_at, first_name, last_name, email, username, password_hash FROM user_account ` func (q *Queries) GetAllUserAccounts(ctx context.Context) ([]UserAccount, error) { @@ -60,7 +63,8 @@ func (q *Queries) GetAllUserAccounts(ctx context.Context) ([]UserAccount, error) if err := rows.Scan( &i.UserID, &i.CreatedAt, - &i.DisplayName, + &i.FirstName, + &i.LastName, &i.Email, &i.Username, &i.PasswordHash, @@ -79,7 +83,7 @@ func (q *Queries) GetAllUserAccounts(ctx context.Context) ([]UserAccount, error) } const getUserAccountByID = `-- name: GetUserAccountByID :one -SELECT user_id, created_at, display_name, email, username, password_hash FROM user_account WHERE user_id = $1 +SELECT user_id, created_at, first_name, last_name, email, username, password_hash FROM user_account WHERE user_id = $1 ` func (q *Queries) GetUserAccountByID(ctx context.Context, userID uuid.UUID) (UserAccount, error) { @@ -88,7 +92,8 @@ func (q *Queries) GetUserAccountByID(ctx context.Context, userID uuid.UUID) (Use err := row.Scan( &i.UserID, &i.CreatedAt, - &i.DisplayName, + &i.FirstName, + &i.LastName, &i.Email, &i.Username, &i.PasswordHash, @@ -97,7 +102,7 @@ func (q *Queries) GetUserAccountByID(ctx context.Context, userID uuid.UUID) (Use } const getUserAccountByUsername = `-- name: GetUserAccountByUsername :one -SELECT user_id, created_at, display_name, email, username, password_hash FROM user_account WHERE username = $1 +SELECT user_id, created_at, first_name, last_name, email, username, password_hash FROM user_account WHERE username = $1 ` func (q *Queries) GetUserAccountByUsername(ctx context.Context, username string) (UserAccount, error) { @@ -106,7 +111,8 @@ func (q *Queries) GetUserAccountByUsername(ctx context.Context, username string) err := row.Scan( &i.UserID, &i.CreatedAt, - &i.DisplayName, + &i.FirstName, + &i.LastName, &i.Email, &i.Username, &i.PasswordHash, diff --git a/api/query/label_color.sql b/api/query/label_color.sql new file mode 100644 index 0000000..f041ce8 --- /dev/null +++ b/api/query/label_color.sql @@ -0,0 +1,2 @@ +-- name: GetLabelColorByID :one +SELECT * FROM label_color WHERE label_color_id = $1; diff --git a/api/query/project.sql b/api/query/project.sql index 764fa80..5514793 100644 --- a/api/query/project.sql +++ b/api/query/project.sql @@ -8,4 +8,4 @@ SELECT * FROM project WHERE team_id = $1; SELECT * FROM project WHERE project_id = $1; -- name: CreateProject :one -INSERT INTO project(team_id, created_at, name) VALUES ($1, $2, $3) RETURNING *; +INSERT INTO project(owner, team_id, created_at, name) VALUES ($1, $2, $3, $4) RETURNING *; diff --git a/api/query/task.sql b/api/query/task.sql index 8d78e14..54de5b8 100644 --- a/api/query/task.sql +++ b/api/query/task.sql @@ -2,6 +2,12 @@ INSERT INTO task (task_group_id, created_at, name, position) VALUES($1, $2, $3, $4) RETURNING *; +-- name: UpdateTaskDescription :one +UPDATE task SET description = $2 WHERE task_id = $1 RETURNING *; + +-- name: GetTaskByID :one +SELECT * FROM task WHERE task_id = $1; + -- name: GetTasksForTaskGroupID :many SELECT * FROM task WHERE task_group_id = $1; diff --git a/api/query/task_assigned.sql b/api/query/task_assigned.sql new file mode 100644 index 0000000..57cd033 --- /dev/null +++ b/api/query/task_assigned.sql @@ -0,0 +1,6 @@ +-- name: CreateTaskAssigned :one +INSERT INTO task_assigned (task_id, user_id, assigned_date) + VALUES($1, $2, $3) RETURNING *; + +-- name: GetAssignedMembersForTask :many +SELECT * FROM task_assigned WHERE task_id = $1; diff --git a/api/query/task_label.sql b/api/query/task_label.sql new file mode 100644 index 0000000..58ab624 --- /dev/null +++ b/api/query/task_label.sql @@ -0,0 +1,6 @@ +-- name: CreateTaskLabelForTask :one +INSERT INTO task_label (task_id, label_color_id, assigned_date) + VALUES ($1, $2, $3) RETURNING *; + +-- name: GetTaskLabelsForTaskID :many +SELECT * FROM task_label WHERE task_id = $1; diff --git a/api/query/user_accounts.sql b/api/query/user_accounts.sql index d51f0f7..2c1b155 100644 --- a/api/query/user_accounts.sql +++ b/api/query/user_accounts.sql @@ -8,6 +8,6 @@ SELECT * FROM user_account; SELECT * FROM user_account WHERE username = $1; -- name: CreateUserAccount :one -INSERT INTO user_account(display_name, email, username, created_at, password_hash) - VALUES ($1, $2, $3, $4, $5) +INSERT INTO user_account(first_name, last_name, email, username, created_at, password_hash) + VALUES ($1, $2, $3, $4, $5, $6) RETURNING *; diff --git a/api/router/auth.go b/api/router/auth.go index dd773b2..5210ad3 100644 --- a/api/router/auth.go +++ b/api/router/auth.go @@ -42,7 +42,7 @@ func (h *CitadelHandler) RefreshTokenHandler(w http.ResponseWriter, r *http.Requ w.WriteHeader(http.StatusInternalServerError) } - accessTokenString, err := NewAccessToken("1") + accessTokenString, err := NewAccessToken(token.UserID.String()) if err != nil { w.WriteHeader(http.StatusInternalServerError) } @@ -57,6 +57,25 @@ func (h *CitadelHandler) RefreshTokenHandler(w http.ResponseWriter, r *http.Requ json.NewEncoder(w).Encode(LoginResponseData{AccessToken: accessTokenString}) } +func (h *CitadelHandler) LogoutHandler(w http.ResponseWriter, r *http.Request) { + c, err := r.Cookie("refreshToken") + if err != nil { + if err == http.ErrNoCookie { + w.WriteHeader(http.StatusBadRequest) + return + } + w.WriteHeader(http.StatusBadRequest) + return + } + refreshTokenID := uuid.MustParse(c.Value) + err = h.repo.DeleteRefreshTokenByID(r.Context(), refreshTokenID) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + return + } + json.NewEncoder(w).Encode(LogoutResponseData{Status: "success"}) +} + func (h *CitadelHandler) LoginHandler(w http.ResponseWriter, r *http.Request) { var requestData LoginRequestData err := json.NewDecoder(r.Body).Decode(&requestData) @@ -85,12 +104,11 @@ func (h *CitadelHandler) LoginHandler(w http.ResponseWriter, r *http.Request) { return } - userID := uuid.MustParse("0183d9ab-d0ed-4c9b-a3df-77a0cdd93dca") refreshCreatedAt := time.Now().UTC() refreshExpiresAt := refreshCreatedAt.AddDate(0, 0, 1) - refreshTokenString, err := h.repo.CreateRefreshToken(r.Context(), pg.CreateRefreshTokenParams{userID, refreshCreatedAt, refreshExpiresAt}) + refreshTokenString, err := h.repo.CreateRefreshToken(r.Context(), pg.CreateRefreshTokenParams{user.UserID, refreshCreatedAt, refreshExpiresAt}) - accessTokenString, err := NewAccessToken("1") + accessTokenString, err := NewAccessToken(user.UserID.String()) if err != nil { w.WriteHeader(http.StatusInternalServerError) } @@ -109,5 +127,6 @@ func (rs authResource) Routes(citadelHandler CitadelHandler) chi.Router { r := chi.NewRouter() r.Post("/login", citadelHandler.LoginHandler) r.Post("/refresh_token", citadelHandler.RefreshTokenHandler) + r.Post("/logout", citadelHandler.LogoutHandler) return r } diff --git a/api/router/middleware.go b/api/router/middleware.go index b871c0a..a4a2ed5 100644 --- a/api/router/middleware.go +++ b/api/router/middleware.go @@ -5,6 +5,7 @@ import ( "net/http" "strings" + "github.com/google/uuid" log "github.com/sirupsen/logrus" ) @@ -40,7 +41,13 @@ func AuthenticationMiddleware(next http.Handler) http.Handler { return } - ctx := context.WithValue(r.Context(), "accessClaims", accessClaims) + userID, err := uuid.Parse(accessClaims.UserID) + if err != nil { + log.Error(err) + w.WriteHeader(http.StatusBadRequest) + return + } + ctx := context.WithValue(r.Context(), "userID", userID) next.ServeHTTP(w, r.WithContext(ctx)) }) diff --git a/api/router/models.go b/api/router/models.go index 6336bfc..8f88204 100644 --- a/api/router/models.go +++ b/api/router/models.go @@ -23,6 +23,10 @@ type LoginResponseData struct { AccessToken string `json:"accessToken"` } +type LogoutResponseData struct { + Status string `json:"status"` +} + type RefreshTokenResponseData struct { AccessToken string `json:"accessToken"` } diff --git a/web/package.json b/web/package.json index 51b6f3c..0b66fec 100644 --- a/web/package.json +++ b/web/package.json @@ -20,6 +20,7 @@ "@testing-library/user-event": "^7.1.2", "@types/color": "^3.0.1", "@types/jest": "^24.0.0", + "@types/jwt-decode": "^2.2.1", "@types/lodash": "^4.14.149", "@types/node": "^12.0.0", "@types/react": "^16.9.21", @@ -41,6 +42,7 @@ "graphql-tag": "^2.10.3", "history": "^4.10.1", "immer": "^6.0.3", + "jwt-decode": "^2.2.0", "lodash": "^4.17.15", "moment": "^2.24.0", "prop-types": "^15.7.2", diff --git a/web/src/App/BaseStyles.ts b/web/src/App/BaseStyles.ts index 96499c4..1febcbf 100644 --- a/web/src/App/BaseStyles.ts +++ b/web/src/App/BaseStyles.ts @@ -7,6 +7,7 @@ export default createGlobalStyle` height: 100%; min-height: 100%; min-width: 768px; + background: #262c49; } body { diff --git a/web/src/App/Navbar.tsx b/web/src/App/Navbar.tsx index e8f9d81..ff4593e 100644 --- a/web/src/App/Navbar.tsx +++ b/web/src/App/Navbar.tsx @@ -1,9 +1,14 @@ -import React from 'react'; +import React, { useContext } from 'react'; import { Home, Stack } from 'shared/icons'; import Navbar, { ActionButton, ButtonContainer, PrimaryLogo } from 'shared/components/Navbar'; import { Link } from 'react-router-dom'; +import UserIDContext from './context'; const GlobalNavbar = () => { + const { userID } = useContext(UserIDContext); + if (!userID) { + return null; + } return ( diff --git a/web/src/App/Routes.tsx b/web/src/App/Routes.tsx index 2699205..3906919 100644 --- a/web/src/App/Routes.tsx +++ b/web/src/App/Routes.tsx @@ -12,14 +12,12 @@ type RoutesProps = { }; const Routes = ({ history }: RoutesProps) => ( - - - - - - - - + + + + + + ); export default Routes; diff --git a/web/src/App/TopNavbar.tsx b/web/src/App/TopNavbar.tsx index e196af7..fc1f776 100644 --- a/web/src/App/TopNavbar.tsx +++ b/web/src/App/TopNavbar.tsx @@ -1,8 +1,14 @@ -import React, { useState } from 'react'; +import React, { useState, useContext } from 'react'; import TopNavbar from 'shared/components/TopNavbar'; import DropdownMenu from 'shared/components/DropdownMenu'; +import { useHistory } from 'react-router'; +import UserIDContext from 'App/context'; +import { useMeQuery } from 'shared/generated/graphql'; const GlobalTopNavbar: React.FC = () => { + const { loading, data } = useMeQuery(); + const history = useHistory(); + const { userID, setUserID } = useContext(UserIDContext); const [menu, setMenu] = useState({ top: 0, left: 0, @@ -15,10 +21,33 @@ const GlobalTopNavbar: React.FC = () => { top: bottom, }); }; + + const onLogout = () => { + fetch('http://localhost:3333/auth/logout', { + method: 'POST', + credentials: 'include', + }).then(async x => { + const { status } = x; + if (status === 200) { + history.replace('/login'); + setUserID(null); + } + }); + }; + if (!userID) { + return null; + } + console.log(data); return ( <> - console.log('beep')} onProfileClick={onProfileClick} /> - {menu.isOpen && } + console.log('beep')} + onProfileClick={onProfileClick} + /> + {menu.isOpen && } ); }; diff --git a/web/src/App/context.ts b/web/src/App/context.ts new file mode 100644 index 0000000..86d30a9 --- /dev/null +++ b/web/src/App/context.ts @@ -0,0 +1,9 @@ +import React from 'react'; + +type UserIDContextState = { + userID: string | null; + setUserID: (userID: string | null) => void; +}; +export const UserIDContext = React.createContext({ userID: null, setUserID: _userID => null }); + +export default UserIDContext; diff --git a/web/src/App/index.tsx b/web/src/App/index.tsx index 8f3a54b..82bb2c0 100644 --- a/web/src/App/index.tsx +++ b/web/src/App/index.tsx @@ -1,22 +1,27 @@ import React, { useState, useEffect } from 'react'; +import jwtDecode from 'jwt-decode'; import { createBrowserHistory } from 'history'; import { setAccessToken } from 'shared/utils/accessToken'; -import Navbar from 'shared/components/Navbar'; import GlobalTopNavbar from 'App/TopNavbar'; import styled from 'styled-components'; import NormalizeStyles from './NormalizeStyles'; import BaseStyles from './BaseStyles'; import Routes from './Routes'; +import { UserIDContext } from './context'; +import Navbar from './Navbar'; +import { Router } from 'react-router'; const history = createBrowserHistory(); const MainContent = styled.div` padding: 0 0 50px 80px; background: #262c49; + height: 100%; `; const App = () => { const [loading, setLoading] = useState(true); + const [userID, setUserID] = useState(null); useEffect(() => { fetch('http://localhost:3333/auth/refresh_token', { @@ -29,28 +34,33 @@ const App = () => { } else { const response: RefreshTokenResponse = await x.json(); const { accessToken } = response; + const claims: JWTToken = jwtDecode(accessToken); + setUserID(claims.userId); setAccessToken(accessToken); } - // } setLoading(false); }); }, []); - if (loading) { - return ( - <> - - - - - - ); - } return ( <> - - - + + + + + {loading ? ( +
loading
+ ) : ( + <> + + + + + + + )} +
+
); }; diff --git a/web/src/Auth/index.tsx b/web/src/Auth/index.tsx index a9fb85a..7dc020c 100644 --- a/web/src/Auth/index.tsx +++ b/web/src/Auth/index.tsx @@ -1,4 +1,4 @@ -import React, { useState, useEffect } from 'react'; +import React, { useState, useEffect, useContext } from 'react'; import { useForm } from 'react-hook-form'; import { useHistory } from 'react-router'; @@ -6,10 +6,13 @@ import { setAccessToken } from 'shared/utils/accessToken'; import Login from 'shared/components/Login'; import { Container, LoginWrapper } from './Styles'; +import UserIDContext from 'App/context'; +import JwtDecode from 'jwt-decode'; const Auth = () => { const [invalidLoginAttempt, setInvalidLoginAttempt] = useState(0); const history = useHistory(); + const { setUserID } = useContext(UserIDContext); const login = ( data: LoginFormData, setComplete: (val: boolean) => void, @@ -31,8 +34,11 @@ const Auth = () => { } else { const response = await x.json(); const { accessToken } = response; - setAccessToken(accessToken); + const claims: JWTToken = JwtDecode(accessToken); + setUserID(claims.userId); setComplete(true); + setAccessToken(accessToken); + history.push('/'); } }); diff --git a/web/src/Projects/Project/Details/index.tsx b/web/src/Projects/Project/Details/index.tsx new file mode 100644 index 0000000..f1b03d7 --- /dev/null +++ b/web/src/Projects/Project/Details/index.tsx @@ -0,0 +1,110 @@ +import React, { useState, useContext } from 'react'; +import Modal from 'shared/components/Modal'; +import TaskDetails from 'shared/components/TaskDetails'; +import PopupMenu from 'shared/components/PopupMenu'; +import MemberManager from 'shared/components/MemberManager'; +import { useRouteMatch, useHistory } from 'react-router'; +import { useFindTaskQuery, useAssignTaskMutation } from 'shared/generated/graphql'; +import UserIDContext from 'App/context'; + +type DetailsProps = { + taskID: string; + projectURL: string; + onTaskNameChange: (task: Task, newName: string) => void; + onTaskDescriptionChange: (task: Task, newDescription: string) => void; + onDeleteTask: (task: Task) => void; + onOpenAddLabelPopup: (task: Task, bounds: ElementBounds) => void; + availableMembers: Array; +}; + +const initialMemberPopupState = { taskID: '', isOpen: false, top: 0, left: 0 }; + +const Details: React.FC = ({ + projectURL, + taskID, + onTaskNameChange, + onTaskDescriptionChange, + onDeleteTask, + onOpenAddLabelPopup, + availableMembers, +}) => { + const { userID } = useContext(UserIDContext); + const history = useHistory(); + const match = useRouteMatch(); + const [memberPopupData, setMemberPopupData] = useState(initialMemberPopupState); + const { loading, data } = useFindTaskQuery({ variables: { taskID } }); + const [assignTask] = useAssignTaskMutation(); + if (loading) { + return
loading
; + } + if (!data) { + return
loading
; + } + const taskMembers = data.findTask.assigned.map(assigned => { + return { + userID: assigned.userID, + displayName: `${assigned.firstName} ${assigned.lastName}`, + profileIcon: { + url: null, + initials: assigned.profileIcon.initials ?? null, + }, + }; + }); + return ( + <> + { + history.push(projectURL); + }} + renderContent={() => { + return ( + history.push(projectURL)} + onOpenAddMemberPopup={(task, bounds) => { + console.log(task, bounds); + setMemberPopupData({ + isOpen: true, + taskID: task.taskID, + top: bounds.position.top + bounds.size.height + 10, + left: bounds.position.left, + }); + }} + onOpenAddLabelPopup={onOpenAddLabelPopup} + /> + ); + }} + /> + {memberPopupData.isOpen && ( + setMemberPopupData(initialMemberPopupState)} + left={memberPopupData.left} + > + { + if (isActive) { + assignTask({ variables: { taskID: data.findTask.taskID, userID: userID ?? '' } }); + } + console.log(member, isActive); + }} + /> + + )} + + ); +}; + +export default Details; diff --git a/web/src/Projects/Project/index.tsx b/web/src/Projects/Project/index.tsx index f084069..16ebaee 100644 --- a/web/src/Projects/Project/index.tsx +++ b/web/src/Projects/Project/index.tsx @@ -11,18 +11,17 @@ import { useUpdateTaskGroupLocationMutation, useCreateTaskGroupMutation, useDeleteTaskGroupMutation, + useUpdateTaskDescriptionMutation, + useAssignTaskMutation, } from 'shared/generated/graphql'; -import Navbar from 'App/Navbar'; -import TopNavbar from 'App/TopNavbar'; import QuickCardEditor from 'shared/components/QuickCardEditor'; import PopupMenu from 'shared/components/PopupMenu'; import ListActions from 'shared/components/ListActions'; -import Modal from 'shared/components/Modal'; -import TaskDetails from 'shared/components/TaskDetails'; import MemberManager from 'shared/components/MemberManager'; import { LabelsPopup } from 'shared/components/PopupMenu/PopupMenu.stories'; import KanbanBoard from 'Projects/Project/KanbanBoard'; +import Details from './Details'; type TaskRouteProps = { taskID: string; @@ -35,17 +34,6 @@ interface QuickCardEditorState { task?: Task; } -const MainContent = styled.div` - padding: 0 0 50px 80px; - height: 100%; - background: #262c49; -`; - -const Wrapper = styled.div` - font-size: 16px; - background-color: red; -`; - const TitleWrapper = styled.div` margin-left: 38px; margin-bottom: 15px; @@ -64,7 +52,6 @@ interface ProjectParams { const initialState: BoardState = { tasks: {}, columns: {} }; const initialPopupState = { left: 0, top: 0, isOpen: false, taskGroupID: '' }; const initialQuickCardEditorState: QuickCardEditorState = { isOpen: false, top: 0, left: 0 }; -const initialMemberPopupState = { taskID: '', isOpen: false, top: 0, left: 0 }; const initialLabelsPopupState = { taskID: '', isOpen: false, top: 0, left: 0 }; const initialTaskDetailsState = { isOpen: false, taskID: '' }; @@ -73,9 +60,9 @@ const Project = () => { const match = useRouteMatch(); const history = useHistory(); + const [updateTaskDescription] = useUpdateTaskDescriptionMutation(); const [listsData, setListsData] = useState(initialState); const [popupData, setPopupData] = useState(initialPopupState); - const [memberPopupData, setMemberPopupData] = useState(initialMemberPopupState); const [taskDetails, setTaskDetails] = useState(initialTaskDetailsState); const [quickCardEditor, setQuickCardEditor] = useState(initialQuickCardEditorState); const [updateTaskLocation] = useUpdateTaskLocationMutation(); @@ -142,6 +129,7 @@ const Project = () => { name: task.name, position: task.position, labels: [], + description: task.description ?? undefined, }; }); }); @@ -199,30 +187,35 @@ const Project = () => { createTaskGroup({ variables: { projectID: projectId, name: listName, position } }); }; + const [assignTask] = useAssignTaskMutation(); + if (loading) { - return Loading; + return Error Loading; } if (data) { + const availableMembers = data.findProject.members.map(member => { + return { + displayName: `${member.firstName} ${member.lastName}`, + profileIcon: { url: null, initials: member.profileIcon.initials ?? null }, + userID: member.userID, + }; + }); return ( <> - - - - - {data.findProject.name} - { - setPopupData({ isOpen, top, left, taskGroupID }); - }} - /> - - + + {data.findProject.name} + + { + setPopupData({ isOpen, top, left, taskGroupID }); + }} + /> {popupData.isOpen && ( { ) => ( - { - history.push(match.url); +
{ + updateTaskName({ variables: { taskID: updatedTask.taskID, name: newName } }); }} - renderContent={() => { - const task = listsData.tasks[routeProps.match.params.taskID]; - if (!task) { - return
loading
; - } - return ( - { - updateTaskName({ variables: { taskID: updatedTask.taskID, name: newName } }); - }} - onTaskDescriptionChange={(updatedTask, newDescription) => { - console.log(updatedTask, newDescription); - }} - onDeleteTask={deletedTask => { - setTaskDetails(initialTaskDetailsState); - deleteTask({ variables: { taskID: deletedTask.taskID } }); - }} - onCloseModal={() => history.push(match.url)} - onOpenAddMemberPopup={(task, bounds) => { - console.log(task, bounds); - setMemberPopupData({ - isOpen: true, - taskID: task.taskID, - top: bounds.position.top + bounds.size.height + 10, - left: bounds.position.left, - }); - }} - onOpenAddLabelPopup={(task, bounds) => {}} - /> - ); + onTaskDescriptionChange={(updatedTask, newDescription) => { + updateTaskDescription({ variables: { taskID: updatedTask.taskID, description: newDescription } }); }} + onDeleteTask={deletedTask => { + setTaskDetails(initialTaskDetailsState); + deleteTask({ variables: { taskID: deletedTask.taskID } }); + }} + onOpenAddLabelPopup={(task, bounds) => {}} /> )} /> ); } - return Error; + return
Error
; }; export default Project; diff --git a/web/src/Projects/index.tsx b/web/src/Projects/index.tsx index dabccca..bcd0e74 100644 --- a/web/src/Projects/index.tsx +++ b/web/src/Projects/index.tsx @@ -2,7 +2,6 @@ import React, { useState } from 'react'; import styled from 'styled-components/macro'; import { useGetProjectsQuery } from 'shared/generated/graphql'; -import TopNavbar from 'App/TopNavbar'; import ProjectGridItem from 'shared/components/ProjectGridItem'; import { Link } from 'react-router-dom'; import Navbar from 'App/Navbar'; @@ -15,59 +14,42 @@ const MainContent = styled.div` const ProjectGrid = styled.div` width: 60%; + max-width: 780px; margin: 25px auto; display: flex; + flex-wrap: wrap; align-items: center; justify-content: center; `; -const Wrapper = styled.div` - font-size: 16px; - background-color: red; + +const ProjectLink = styled(Link)` + flex: 1 0 33%; + margin-bottom: 20px; `; + const Projects = () => { const { loading, data } = useGetProjectsQuery(); console.log(loading, data); if (loading) { return ( <> - - - - + loading ); } if (data) { - const { teams } = data.organizations[0]; - const projects: Project[] = []; - teams.forEach(team => - team.projects.forEach(project => { - projects.push({ - taskGroups: [], - projectID: project.projectID, - teamTitle: team.name, - name: project.name, - color: '#aa62e3', - }); - }), - ); + const { projects } = data; return ( - <> - - - - - {projects.map(project => ( - - - - ))} - - - + + {projects.map(project => ( + + + + ))} + ); } - return Error; + return
Error!
; }; export default Projects; diff --git a/web/src/citadel.d.ts b/web/src/citadel.d.ts index 3b6df43..5a833f2 100644 --- a/web/src/citadel.d.ts +++ b/web/src/citadel.d.ts @@ -1,3 +1,8 @@ +interface JWTToken { + userId: string; + iat: string; + exp: string; +} interface ColumnState { [key: string]: TaskGroup; } @@ -29,9 +34,15 @@ type InnerTaskGroup = { position?: number; }; +type ProfileIcon = { + url: string | null; + initials: string | null; +}; + type TaskUser = { userID: string; displayName: string; + profileIcon: ProfileIcon; }; type Task = { diff --git a/web/src/shared/components/DropdownMenu/DropdownMenu.stories.tsx b/web/src/shared/components/DropdownMenu/DropdownMenu.stories.tsx index fef40d6..49f6d41 100644 --- a/web/src/shared/components/DropdownMenu/DropdownMenu.stories.tsx +++ b/web/src/shared/components/DropdownMenu/DropdownMenu.stories.tsx @@ -2,6 +2,7 @@ import React, { createRef, useState } from 'react'; import styled from 'styled-components'; import DropdownMenu from '.'; +import { action } from '@storybook/addon-actions'; export default { component: DropdownMenu, @@ -49,7 +50,7 @@ export const Default = () => { Click me - {menu.isOpen && } + {menu.isOpen && } ); }; diff --git a/web/src/shared/components/DropdownMenu/index.tsx b/web/src/shared/components/DropdownMenu/index.tsx index def0c04..a8d4ea8 100644 --- a/web/src/shared/components/DropdownMenu/index.tsx +++ b/web/src/shared/components/DropdownMenu/index.tsx @@ -6,9 +6,10 @@ import { Separator, Container, WrapperDiamond, Wrapper, ActionsList, ActionItem, type DropdownMenuProps = { left: number; top: number; + onLogout: () => void; }; -const DropdownMenu: React.FC = ({ left, top }) => { +const DropdownMenu: React.FC = ({ left, top, onLogout }) => { return ( @@ -18,7 +19,7 @@ const DropdownMenu: React.FC = ({ left, top }) => { - + Logout diff --git a/web/src/shared/components/DueDateManager/DueDateManager.stories.tsx b/web/src/shared/components/DueDateManager/DueDateManager.stories.tsx index 806b5a8..dd31a7b 100644 --- a/web/src/shared/components/DueDateManager/DueDateManager.stories.tsx +++ b/web/src/shared/components/DueDateManager/DueDateManager.stories.tsx @@ -23,7 +23,7 @@ export const Default = () => { position: 1, labels: [{ labelId: 'soft-skills', color: '#fff', active: true, name: 'Soft Skills' }], description: 'hello!', - members: [{ userID: '1', displayName: 'Jordan Knott' }], + members: [{ userID: '1', profileIcon: { url: null, initials: null }, displayName: 'Jordan Knott' }], }} onCancel={action('cancel')} onDueDateChange={action('due date change')} diff --git a/web/src/shared/components/Login/index.tsx b/web/src/shared/components/Login/index.tsx index 0a3c4dd..da44245 100644 --- a/web/src/shared/components/Login/index.tsx +++ b/web/src/shared/components/Login/index.tsx @@ -55,7 +55,7 @@ const Login = ({ onSubmit }: LoginProps) => { Password { {popupData.isOpen && ( setPopupData(initalState)} left={popupData.left}> )} { if ($buttonRef && $buttonRef.current) { @@ -162,7 +158,7 @@ export const DueDateManagerPopup = () => { position: 1, labels: [{ labelId: 'soft-skills', color: '#fff', active: true, name: 'Soft Skills' }], description: 'hello!', - members: [{ userID: '1', displayName: 'Jordan Knott' }], + members: [{ userID: '1', profileIcon: { url: null, initials: null }, displayName: 'Jordan Knott' }], }} onCancel={action('cancel')} onDueDateChange={action('due date change')} diff --git a/web/src/shared/components/ProjectGridItem/Styles.ts b/web/src/shared/components/ProjectGridItem/Styles.ts index c638dbd..b59cd27 100644 --- a/web/src/shared/components/ProjectGridItem/Styles.ts +++ b/web/src/shared/components/ProjectGridItem/Styles.ts @@ -4,27 +4,22 @@ import { mixin } from 'shared/utils/styles'; export const ProjectContent = styled.div` display: flex; flex-direction: column; - align-items: center; - justify-content: center; `; export const ProjectTitle = styled.span` font-size: 18px; font-weight: 700; transition: transform 0.25s ease; - text-align: center; `; export const TeamTitle = styled.span` margin-top: 5px; font-size: 14px; font-weight: normal; - text-align: center; color: #c2c6dc; `; export const ProjectWrapper = styled.div<{ color: string }>` display: flex; - align-items: center; padding: 15px 25px; border-radius: 20px; ${mixin.boxShadowCard} @@ -32,11 +27,10 @@ export const ProjectWrapper = styled.div<{ color: string }>` color: #fff; cursor: pointer; margin: 0 10px; - width: 120px; - height: 120px; - align-items: center; - justify-content: center; + width: 240px; + height: 100px; transition: transform 0.25s ease; + align-items: center; &:hover { transform: translateY(-5px); diff --git a/web/src/shared/components/TaskDetails/TaskDetails.stories.tsx b/web/src/shared/components/TaskDetails/TaskDetails.stories.tsx index 3117e5f..a860aaa 100644 --- a/web/src/shared/components/TaskDetails/TaskDetails.stories.tsx +++ b/web/src/shared/components/TaskDetails/TaskDetails.stories.tsx @@ -35,7 +35,7 @@ export const Default = () => { position: 1, labels: [{ labelId: 'soft-skills', color: '#fff', active: true, name: 'Soft Skills' }], description, - members: [{ userID: '1', displayName: 'Jordan Knott' }], + members: [{ userID: '1', profileIcon: { url: null, initials: null }, displayName: 'Jordan Knott' }], }} onTaskNameChange={action('task name change')} onTaskDescriptionChange={(_task, desc) => setDescription(desc)} diff --git a/web/src/shared/components/TaskDetails/index.tsx b/web/src/shared/components/TaskDetails/index.tsx index 01b8a8c..1bcd962 100644 --- a/web/src/shared/components/TaskDetails/index.tsx +++ b/web/src/shared/components/TaskDetails/index.tsx @@ -97,9 +97,9 @@ type TaskDetailsProps = { onTaskNameChange: (task: Task, newName: string) => void; onTaskDescriptionChange: (task: Task, newDescription: string) => void; onDeleteTask: (task: Task) => void; - onCloseModal: () => void; onOpenAddMemberPopup: (task: Task, bounds: ElementBounds) => void; onOpenAddLabelPopup: (task: Task, bounds: ElementBounds) => void; + onCloseModal: () => void; }; const TaskDetails: React.FC = ({ @@ -112,6 +112,7 @@ const TaskDetails: React.FC = ({ onOpenAddLabelPopup, }) => { const [editorOpen, setEditorOpen] = useState(false); + const [description, setDescription] = useState(task.description ?? ''); const [taskName, setTaskName] = useState(task.name); const handleClick = () => { setEditorOpen(!editorOpen); @@ -141,6 +142,7 @@ const TaskDetails: React.FC = ({ onOpenAddLabelPopup(task, bounds); } }; + console.log(task); return ( <> @@ -172,9 +174,10 @@ const TaskDetails: React.FC = ({ Description {editorOpen ? ( { setEditorOpen(false); + setDescription(newDescription); onTaskDescriptionChange(task, newDescription); }} onCancel={() => { @@ -182,7 +185,7 @@ const TaskDetails: React.FC = ({ }} /> ) : ( - + )} @@ -190,10 +193,10 @@ const TaskDetails: React.FC = ({ {task.members && task.members.map(member => { - const initials = 'JK'; + console.log(member); return ( - {initials} + {member.profileIcon.initials ?? ''} ); })} diff --git a/web/src/shared/components/TopNavbar/TopNavbar.stories.tsx b/web/src/shared/components/TopNavbar/TopNavbar.stories.tsx index 76d3f07..64fa318 100644 --- a/web/src/shared/components/TopNavbar/TopNavbar.stories.tsx +++ b/web/src/shared/components/TopNavbar/TopNavbar.stories.tsx @@ -37,8 +37,14 @@ export const Default = () => { <> - - {menu.isOpen && } + + {menu.isOpen && } ); }; diff --git a/web/src/shared/components/TopNavbar/index.tsx b/web/src/shared/components/TopNavbar/index.tsx index 6b2ed66..0181e7c 100644 --- a/web/src/shared/components/TopNavbar/index.tsx +++ b/web/src/shared/components/TopNavbar/index.tsx @@ -19,8 +19,11 @@ import { type NavBarProps = { onProfileClick: (bottom: number, right: number) => void; onNotificationClick: () => void; + firstName: string; + lastName: string; + initials: string; }; -const NavBar: React.FC = ({ onProfileClick, onNotificationClick }) => { +const NavBar: React.FC = ({ onProfileClick, onNotificationClick, firstName, lastName, initials }) => { const $profileRef: any = useRef(null); const handleProfileClick = () => { console.log('click'); @@ -45,11 +48,13 @@ const NavBar: React.FC = ({ onProfileClick, onNotificationClick }) - Jordan Knott + + {firstName} {lastName} + Manager - JK + {initials} diff --git a/web/src/shared/generated/graphql.tsx b/web/src/shared/generated/graphql.tsx index 3af4736..ee6f512 100644 --- a/web/src/shared/generated/graphql.tsx +++ b/web/src/shared/generated/graphql.tsx @@ -15,6 +15,27 @@ export type Scalars = { +export type TaskLabel = { + __typename?: 'TaskLabel'; + taskLabelID: Scalars['ID']; + labelColorID: Scalars['UUID']; + colorHex: Scalars['String']; +}; + +export type ProfileIcon = { + __typename?: 'ProfileIcon'; + url?: Maybe; + initials?: Maybe; +}; + +export type ProjectMember = { + __typename?: 'ProjectMember'; + userID: Scalars['ID']; + firstName: Scalars['String']; + lastName: Scalars['String']; + profileIcon: ProfileIcon; +}; + export type RefreshToken = { __typename?: 'RefreshToken'; tokenId: Scalars['ID']; @@ -28,16 +49,10 @@ export type UserAccount = { userID: Scalars['ID']; email: Scalars['String']; createdAt: Scalars['Time']; - displayName: Scalars['String']; + firstName: Scalars['String']; + lastName: Scalars['String']; username: Scalars['String']; -}; - -export type Organization = { - __typename?: 'Organization'; - organizationID: Scalars['ID']; - createdAt: Scalars['Time']; - name: Scalars['String']; - teams: Array; + profileIcon: ProfileIcon; }; export type Team = { @@ -45,16 +60,17 @@ export type Team = { teamID: Scalars['ID']; createdAt: Scalars['Time']; name: Scalars['String']; - projects: Array; }; export type Project = { __typename?: 'Project'; projectID: Scalars['ID']; - teamID: Scalars['String']; createdAt: Scalars['Time']; name: Scalars['String']; + team: Team; + owner: ProjectMember; taskGroups: Array; + members: Array; }; export type TaskGroup = { @@ -74,6 +90,9 @@ export type Task = { createdAt: Scalars['Time']; name: Scalars['String']; position: Scalars['Float']; + description?: Maybe; + assigned: Array; + labels: Array; }; export type ProjectsFilter = { @@ -88,15 +107,19 @@ export type FindProject = { projectId: Scalars['String']; }; +export type FindTask = { + taskID: Scalars['UUID']; +}; + export type Query = { __typename?: 'Query'; - organizations: Array; users: Array; findUser: UserAccount; findProject: Project; - teams: Array; + findTask: Task; projects: Array; taskGroups: Array; + me: UserAccount; }; @@ -110,6 +133,11 @@ export type QueryFindProjectArgs = { }; +export type QueryFindTaskArgs = { + input: FindTask; +}; + + export type QueryProjectsArgs = { input?: Maybe; }; @@ -121,7 +149,8 @@ export type NewRefreshToken = { export type NewUserAccount = { username: Scalars['String']; email: Scalars['String']; - displayName: Scalars['String']; + firstName: Scalars['String']; + lastName: Scalars['String']; password: Scalars['String']; }; @@ -131,7 +160,8 @@ export type NewTeam = { }; export type NewProject = { - teamID: Scalars['String']; + userID: Scalars['UUID']; + teamID: Scalars['UUID']; name: Scalars['String']; }; @@ -141,10 +171,6 @@ export type NewTaskGroup = { position: Scalars['Float']; }; -export type NewOrganization = { - name: Scalars['String']; -}; - export type LogoutUser = { userID: Scalars['String']; }; @@ -191,20 +217,43 @@ export type DeleteTaskGroupPayload = { taskGroup: TaskGroup; }; +export type AssignTaskInput = { + taskID: Scalars['UUID']; + userID: Scalars['UUID']; +}; + +export type UpdateTaskDescriptionInput = { + taskID: Scalars['UUID']; + description: Scalars['String']; +}; + +export type AddTaskLabelInput = { + taskID: Scalars['UUID']; + labelColorID: Scalars['UUID']; +}; + +export type RemoveTaskLabelInput = { + taskID: Scalars['UUID']; + taskLabelID: Scalars['UUID']; +}; + export type Mutation = { __typename?: 'Mutation'; createRefreshToken: RefreshToken; createUserAccount: UserAccount; - createOrganization: Organization; createTeam: Team; createProject: Project; createTaskGroup: TaskGroup; updateTaskGroupLocation: TaskGroup; deleteTaskGroup: DeleteTaskGroupPayload; + addTaskLabel: Task; + removeTaskLabel: Task; createTask: Task; + updateTaskDescription: Task; updateTaskLocation: Task; updateTaskName: Task; deleteTask: DeleteTaskPayload; + assignTask: Task; logoutUser: Scalars['Boolean']; }; @@ -219,11 +268,6 @@ export type MutationCreateUserAccountArgs = { }; -export type MutationCreateOrganizationArgs = { - input: NewOrganization; -}; - - export type MutationCreateTeamArgs = { input: NewTeam; }; @@ -249,11 +293,26 @@ export type MutationDeleteTaskGroupArgs = { }; +export type MutationAddTaskLabelArgs = { + input?: Maybe; +}; + + +export type MutationRemoveTaskLabelArgs = { + input?: Maybe; +}; + + export type MutationCreateTaskArgs = { input: NewTask; }; +export type MutationUpdateTaskDescriptionArgs = { + input: UpdateTaskDescriptionInput; +}; + + export type MutationUpdateTaskLocationArgs = { input: NewTaskLocation; }; @@ -269,10 +328,33 @@ export type MutationDeleteTaskArgs = { }; +export type MutationAssignTaskArgs = { + input?: Maybe; +}; + + export type MutationLogoutUserArgs = { input: LogoutUser; }; +export type AssignTaskMutationVariables = { + taskID: Scalars['UUID']; + userID: Scalars['UUID']; +}; + + +export type AssignTaskMutation = ( + { __typename?: 'Mutation' } + & { assignTask: ( + { __typename?: 'Task' } + & Pick + & { assigned: Array<( + { __typename?: 'ProjectMember' } + & Pick + )> } + ) } +); + export type CreateTaskMutationVariables = { taskGroupID: Scalars['String']; name: Scalars['String']; @@ -351,36 +433,92 @@ export type FindProjectQuery = ( & { findProject: ( { __typename?: 'Project' } & Pick - & { taskGroups: Array<( + & { members: Array<( + { __typename?: 'ProjectMember' } + & Pick + & { profileIcon: ( + { __typename?: 'ProfileIcon' } + & Pick + ) } + )>, taskGroups: Array<( { __typename?: 'TaskGroup' } & Pick & { tasks: Array<( { __typename?: 'Task' } - & Pick + & Pick )> } )> } ) } ); +export type FindTaskQueryVariables = { + taskID: Scalars['UUID']; +}; + + +export type FindTaskQuery = ( + { __typename?: 'Query' } + & { findTask: ( + { __typename?: 'Task' } + & Pick + & { taskGroup: ( + { __typename?: 'TaskGroup' } + & Pick + ), assigned: Array<( + { __typename?: 'ProjectMember' } + & Pick + & { profileIcon: ( + { __typename?: 'ProfileIcon' } + & Pick + ) } + )> } + ) } +); + export type GetProjectsQueryVariables = {}; export type GetProjectsQuery = ( { __typename?: 'Query' } - & { organizations: Array<( - { __typename?: 'Organization' } - & Pick - & { teams: Array<( + & { projects: Array<( + { __typename?: 'Project' } + & Pick + & { team: ( { __typename?: 'Team' } - & Pick - & { projects: Array<( - { __typename?: 'Project' } - & Pick - )> } - )> } + & Pick + ) } )> } ); +export type MeQueryVariables = {}; + + +export type MeQuery = ( + { __typename?: 'Query' } + & { me: ( + { __typename?: 'UserAccount' } + & Pick + & { profileIcon: ( + { __typename?: 'ProfileIcon' } + & Pick + ) } + ) } +); + +export type UpdateTaskDescriptionMutationVariables = { + taskID: Scalars['UUID']; + description: Scalars['String']; +}; + + +export type UpdateTaskDescriptionMutation = ( + { __typename?: 'Mutation' } + & { updateTaskDescription: ( + { __typename?: 'Task' } + & Pick + ) } +); + export type UpdateTaskGroupLocationMutationVariables = { taskGroupID: Scalars['UUID']; position: Scalars['Float']; @@ -425,6 +563,44 @@ export type UpdateTaskNameMutation = ( ); +export const AssignTaskDocument = gql` + mutation assignTask($taskID: UUID!, $userID: UUID!) { + assignTask(input: {taskID: $taskID, userID: $userID}) { + assigned { + userID + firstName + lastName + } + taskID + } +} + `; +export type AssignTaskMutationFn = ApolloReactCommon.MutationFunction; + +/** + * __useAssignTaskMutation__ + * + * To run a mutation, you first call `useAssignTaskMutation` within a React component and pass it any options that fit your needs. + * When your component renders, `useAssignTaskMutation` 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 [assignTaskMutation, { data, loading, error }] = useAssignTaskMutation({ + * variables: { + * taskID: // value for 'taskID' + * userID: // value for 'userID' + * }, + * }); + */ +export function useAssignTaskMutation(baseOptions?: ApolloReactHooks.MutationHookOptions) { + return ApolloReactHooks.useMutation(AssignTaskDocument, baseOptions); + } +export type AssignTaskMutationHookResult = ReturnType; +export type AssignTaskMutationResult = ApolloReactCommon.MutationResult; +export type AssignTaskMutationOptions = ApolloReactCommon.BaseMutationOptions; export const CreateTaskDocument = gql` mutation createTask($taskGroupID: String!, $name: String!, $position: Float!) { createTask(input: {taskGroupID: $taskGroupID, name: $name, position: $position}) { @@ -576,6 +752,15 @@ export const FindProjectDocument = gql` query findProject($projectId: String!) { findProject(input: {projectId: $projectId}) { name + members { + userID + firstName + lastName + profileIcon { + url + initials + } + } taskGroups { taskGroupID name @@ -584,6 +769,7 @@ export const FindProjectDocument = gql` taskID name position + description } } } @@ -615,16 +801,62 @@ export function useFindProjectLazyQuery(baseOptions?: ApolloReactHooks.LazyQuery export type FindProjectQueryHookResult = ReturnType; export type FindProjectLazyQueryHookResult = ReturnType; export type FindProjectQueryResult = ApolloReactCommon.QueryResult; +export const FindTaskDocument = gql` + query findTask($taskID: UUID!) { + findTask(input: {taskID: $taskID}) { + taskID + name + description + position + taskGroup { + taskGroupID + } + assigned { + userID + firstName + lastName + profileIcon { + url + initials + } + } + } +} + `; + +/** + * __useFindTaskQuery__ + * + * To run a query within a React component, call `useFindTaskQuery` and pass it any options that fit your needs. + * When your component renders, `useFindTaskQuery` returns an object from Apollo Client that contains loading, error, and data properties + * you can use to render your UI. + * + * @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options; + * + * @example + * const { data, loading, error } = useFindTaskQuery({ + * variables: { + * taskID: // value for 'taskID' + * }, + * }); + */ +export function useFindTaskQuery(baseOptions?: ApolloReactHooks.QueryHookOptions) { + return ApolloReactHooks.useQuery(FindTaskDocument, baseOptions); + } +export function useFindTaskLazyQuery(baseOptions?: ApolloReactHooks.LazyQueryHookOptions) { + return ApolloReactHooks.useLazyQuery(FindTaskDocument, baseOptions); + } +export type FindTaskQueryHookResult = ReturnType; +export type FindTaskLazyQueryHookResult = ReturnType; +export type FindTaskQueryResult = ApolloReactCommon.QueryResult; export const GetProjectsDocument = gql` query getProjects { - organizations { + projects { + projectID name - teams { + team { + teamID name - projects { - name - projectID - } } } } @@ -654,6 +886,75 @@ export function useGetProjectsLazyQuery(baseOptions?: ApolloReactHooks.LazyQuery export type GetProjectsQueryHookResult = ReturnType; export type GetProjectsLazyQueryHookResult = ReturnType; export type GetProjectsQueryResult = ApolloReactCommon.QueryResult; +export const MeDocument = gql` + query me { + me { + firstName + lastName + profileIcon { + initials + } + } +} + `; + +/** + * __useMeQuery__ + * + * To run a query within a React component, call `useMeQuery` and pass it any options that fit your needs. + * When your component renders, `useMeQuery` returns an object from Apollo Client that contains loading, error, and data properties + * you can use to render your UI. + * + * @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options; + * + * @example + * const { data, loading, error } = useMeQuery({ + * variables: { + * }, + * }); + */ +export function useMeQuery(baseOptions?: ApolloReactHooks.QueryHookOptions) { + return ApolloReactHooks.useQuery(MeDocument, baseOptions); + } +export function useMeLazyQuery(baseOptions?: ApolloReactHooks.LazyQueryHookOptions) { + return ApolloReactHooks.useLazyQuery(MeDocument, baseOptions); + } +export type MeQueryHookResult = ReturnType; +export type MeLazyQueryHookResult = ReturnType; +export type MeQueryResult = ApolloReactCommon.QueryResult; +export const UpdateTaskDescriptionDocument = gql` + mutation updateTaskDescription($taskID: UUID!, $description: String!) { + updateTaskDescription(input: {taskID: $taskID, description: $description}) { + taskID + } +} + `; +export type UpdateTaskDescriptionMutationFn = ApolloReactCommon.MutationFunction; + +/** + * __useUpdateTaskDescriptionMutation__ + * + * To run a mutation, you first call `useUpdateTaskDescriptionMutation` within a React component and pass it any options that fit your needs. + * When your component renders, `useUpdateTaskDescriptionMutation` 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 [updateTaskDescriptionMutation, { data, loading, error }] = useUpdateTaskDescriptionMutation({ + * variables: { + * taskID: // value for 'taskID' + * description: // value for 'description' + * }, + * }); + */ +export function useUpdateTaskDescriptionMutation(baseOptions?: ApolloReactHooks.MutationHookOptions) { + return ApolloReactHooks.useMutation(UpdateTaskDescriptionDocument, baseOptions); + } +export type UpdateTaskDescriptionMutationHookResult = ReturnType; +export type UpdateTaskDescriptionMutationResult = ApolloReactCommon.MutationResult; +export type UpdateTaskDescriptionMutationOptions = ApolloReactCommon.BaseMutationOptions; export const UpdateTaskGroupLocationDocument = gql` mutation updateTaskGroupLocation($taskGroupID: UUID!, $position: Float!) { updateTaskGroupLocation(input: {taskGroupID: $taskGroupID, position: $position}) { diff --git a/web/src/shared/graphql/assignTask.graphqls b/web/src/shared/graphql/assignTask.graphqls new file mode 100644 index 0000000..9376eb3 --- /dev/null +++ b/web/src/shared/graphql/assignTask.graphqls @@ -0,0 +1,10 @@ +mutation assignTask($taskID: UUID!, $userID: UUID!) { + assignTask(input: {taskID: $taskID, userID: $userID}) { + assigned { + userID + firstName + lastName + } + taskID + } +} diff --git a/web/src/shared/graphql/findProject.graphqls b/web/src/shared/graphql/findProject.graphqls index 9eebe7c..221b7d5 100644 --- a/web/src/shared/graphql/findProject.graphqls +++ b/web/src/shared/graphql/findProject.graphqls @@ -1,6 +1,15 @@ query findProject($projectId: String!) { findProject(input: { projectId: $projectId }) { name + members { + userID + firstName + lastName + profileIcon { + url + initials + } + } taskGroups { taskGroupID name @@ -9,6 +18,7 @@ query findProject($projectId: String!) { taskID name position + description } } } diff --git a/web/src/shared/graphql/findTask.graphqls b/web/src/shared/graphql/findTask.graphqls new file mode 100644 index 0000000..7091b19 --- /dev/null +++ b/web/src/shared/graphql/findTask.graphqls @@ -0,0 +1,20 @@ +query findTask($taskID: UUID!) { + findTask(input: {taskID: $taskID}) { + taskID + name + description + position + taskGroup { + taskGroupID + } + assigned { + userID + firstName + lastName + profileIcon { + url + initials + } + } + } +} diff --git a/web/src/shared/graphql/getProjects.graphqls b/web/src/shared/graphql/getProjects.graphqls index 6ed76b3..7e4a523 100644 --- a/web/src/shared/graphql/getProjects.graphqls +++ b/web/src/shared/graphql/getProjects.graphqls @@ -1,12 +1,10 @@ query getProjects { - organizations { + projects { + projectID name - teams { + team { + teamID name - projects { - name - projectID - } } } } diff --git a/web/src/shared/graphql/me.graphqls b/web/src/shared/graphql/me.graphqls new file mode 100644 index 0000000..7f182c6 --- /dev/null +++ b/web/src/shared/graphql/me.graphqls @@ -0,0 +1,9 @@ +query me { + me { + firstName + lastName + profileIcon { + initials + } + } +} diff --git a/web/src/shared/graphql/updateTaskDescription.graphqls b/web/src/shared/graphql/updateTaskDescription.graphqls new file mode 100644 index 0000000..9f0df30 --- /dev/null +++ b/web/src/shared/graphql/updateTaskDescription.graphqls @@ -0,0 +1,5 @@ +mutation updateTaskDescription($taskID: UUID!, $description: String!) { + updateTaskDescription(input: {taskID: $taskID, description: $description}) { + taskID + } +} diff --git a/web/yarn.lock b/web/yarn.lock index 6eca232..111085d 100644 --- a/web/yarn.lock +++ b/web/yarn.lock @@ -3104,6 +3104,11 @@ resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.4.tgz#38fd73ddfd9b55abb1e1b2ed578cb55bd7b7d339" integrity sha512-8+KAKzEvSUdeo+kmqnKrqgeE+LcA0tjYWFY7RPProVYwnqDjukzO+3b6dLD56rYX5TdWejnEOLJYOIeh4CXKuA== +"@types/jwt-decode@^2.2.1": + version "2.2.1" + resolved "https://registry.yarnpkg.com/@types/jwt-decode/-/jwt-decode-2.2.1.tgz#afdf5c527fcfccbd4009b5fd02d1e18241f2d2f2" + integrity sha512-aWw2YTtAdT7CskFyxEX2K21/zSDStuf/ikI3yBqmwpwJF0pS+/IX5DWv+1UFffZIbruP6cnT9/LAJV1gFwAT1A== + "@types/lodash@^4.14.149": version "4.14.149" resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.149.tgz#1342d63d948c6062838fbf961012f74d4e638440" @@ -10202,6 +10207,11 @@ jws@^3.2.2: jwa "^1.4.1" safe-buffer "^5.0.1" +jwt-decode@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/jwt-decode/-/jwt-decode-2.2.0.tgz#7d86bd56679f58ce6a84704a657dd392bba81a79" + integrity sha1-fYa9VmefWM5qhHBKZX3TkruoGnk= + killable@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/killable/-/killable-1.0.1.tgz#4c8ce441187a061c7474fb87ca08e2a638194892"