feature: add ability to assign tasks
This commit is contained in:
parent
beaa215bc2
commit
c38024e692
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,7 @@
|
|||||||
package graph
|
package graph
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"time"
|
"time"
|
||||||
@ -10,6 +11,7 @@ import (
|
|||||||
"github.com/99designs/gqlgen/graphql/handler/lru"
|
"github.com/99designs/gqlgen/graphql/handler/lru"
|
||||||
"github.com/99designs/gqlgen/graphql/handler/transport"
|
"github.com/99designs/gqlgen/graphql/handler/transport"
|
||||||
"github.com/99designs/gqlgen/graphql/playground"
|
"github.com/99designs/gqlgen/graphql/playground"
|
||||||
|
"github.com/google/uuid"
|
||||||
"github.com/jordanknott/project-citadel/api/pg"
|
"github.com/jordanknott/project-citadel/api/pg"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -45,3 +47,7 @@ func NewHandler(repo pg.Repository) http.Handler {
|
|||||||
func NewPlaygroundHandler(endpoint string) http.Handler {
|
func NewPlaygroundHandler(endpoint string) http.Handler {
|
||||||
return playground.Handler("GraphQL Playground", endpoint)
|
return playground.Handler("GraphQL Playground", endpoint)
|
||||||
}
|
}
|
||||||
|
func GetUserID(ctx context.Context) (uuid.UUID, bool) {
|
||||||
|
userID, ok := ctx.Value("userID").(uuid.UUID)
|
||||||
|
return userID, ok
|
||||||
|
}
|
||||||
|
@ -7,6 +7,16 @@ import (
|
|||||||
"github.com/jordanknott/project-citadel/api/pg"
|
"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 {
|
type DeleteTaskGroupInput struct {
|
||||||
TaskGroupID uuid.UUID `json:"taskGroupID"`
|
TaskGroupID uuid.UUID `json:"taskGroupID"`
|
||||||
}
|
}
|
||||||
@ -29,6 +39,10 @@ type FindProject struct {
|
|||||||
ProjectID string `json:"projectId"`
|
ProjectID string `json:"projectId"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type FindTask struct {
|
||||||
|
TaskID uuid.UUID `json:"taskID"`
|
||||||
|
}
|
||||||
|
|
||||||
type FindUser struct {
|
type FindUser struct {
|
||||||
UserID string `json:"userId"`
|
UserID string `json:"userId"`
|
||||||
}
|
}
|
||||||
@ -37,12 +51,9 @@ type LogoutUser struct {
|
|||||||
UserID string `json:"userID"`
|
UserID string `json:"userID"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type NewOrganization struct {
|
|
||||||
Name string `json:"name"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type NewProject struct {
|
type NewProject struct {
|
||||||
TeamID string `json:"teamID"`
|
UserID uuid.UUID `json:"userID"`
|
||||||
|
TeamID uuid.UUID `json:"teamID"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -81,14 +92,37 @@ type NewTeam struct {
|
|||||||
type NewUserAccount struct {
|
type NewUserAccount struct {
|
||||||
Username string `json:"username"`
|
Username string `json:"username"`
|
||||||
Email string `json:"email"`
|
Email string `json:"email"`
|
||||||
DisplayName string `json:"displayName"`
|
FirstName string `json:"firstName"`
|
||||||
|
LastName string `json:"lastName"`
|
||||||
Password string `json:"password"`
|
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 {
|
type ProjectsFilter struct {
|
||||||
TeamID *string `json:"teamID"`
|
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 {
|
type UpdateTaskName struct {
|
||||||
TaskID string `json:"taskID"`
|
TaskID string `json:"taskID"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
|
@ -1,7 +1,24 @@
|
|||||||
scalar Time
|
scalar Time
|
||||||
|
|
||||||
scalar UUID
|
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 {
|
type RefreshToken {
|
||||||
tokenId: ID!
|
tokenId: ID!
|
||||||
userId: UUID!
|
userId: UUID!
|
||||||
@ -13,30 +30,26 @@ type UserAccount {
|
|||||||
userID: ID!
|
userID: ID!
|
||||||
email: String!
|
email: String!
|
||||||
createdAt: Time!
|
createdAt: Time!
|
||||||
displayName: String!
|
firstName: String!
|
||||||
|
lastName: String!
|
||||||
username: String!
|
username: String!
|
||||||
}
|
profileIcon: ProfileIcon!
|
||||||
|
|
||||||
type Organization {
|
|
||||||
organizationID: ID!
|
|
||||||
createdAt: Time!
|
|
||||||
name: String!
|
|
||||||
teams: [Team!]!
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type Team {
|
type Team {
|
||||||
teamID: ID!
|
teamID: ID!
|
||||||
createdAt: Time!
|
createdAt: Time!
|
||||||
name: String!
|
name: String!
|
||||||
projects: [Project!]!
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type Project {
|
type Project {
|
||||||
projectID: ID!
|
projectID: ID!
|
||||||
teamID: String!
|
|
||||||
createdAt: Time!
|
createdAt: Time!
|
||||||
name: String!
|
name: String!
|
||||||
|
team: Team!
|
||||||
|
owner: ProjectMember!
|
||||||
taskGroups: [TaskGroup!]!
|
taskGroups: [TaskGroup!]!
|
||||||
|
members: [ProjectMember!]!
|
||||||
}
|
}
|
||||||
|
|
||||||
type TaskGroup {
|
type TaskGroup {
|
||||||
@ -54,6 +67,9 @@ type Task {
|
|||||||
createdAt: Time!
|
createdAt: Time!
|
||||||
name: String!
|
name: String!
|
||||||
position: Float!
|
position: Float!
|
||||||
|
description: String
|
||||||
|
assigned: [ProjectMember!]!
|
||||||
|
labels: [TaskLabel!]!
|
||||||
}
|
}
|
||||||
|
|
||||||
input ProjectsFilter {
|
input ProjectsFilter {
|
||||||
@ -68,14 +84,18 @@ input FindProject {
|
|||||||
projectId: String!
|
projectId: String!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input FindTask {
|
||||||
|
taskID: UUID!
|
||||||
|
}
|
||||||
|
|
||||||
type Query {
|
type Query {
|
||||||
organizations: [Organization!]!
|
|
||||||
users: [UserAccount!]!
|
users: [UserAccount!]!
|
||||||
findUser(input: FindUser!): UserAccount!
|
findUser(input: FindUser!): UserAccount!
|
||||||
findProject(input: FindProject!): Project!
|
findProject(input: FindProject!): Project!
|
||||||
teams: [Team!]!
|
findTask(input: FindTask!): Task!
|
||||||
projects(input: ProjectsFilter): [Project!]!
|
projects(input: ProjectsFilter): [Project!]!
|
||||||
taskGroups: [TaskGroup!]!
|
taskGroups: [TaskGroup!]!
|
||||||
|
me: UserAccount!
|
||||||
}
|
}
|
||||||
|
|
||||||
input NewRefreshToken {
|
input NewRefreshToken {
|
||||||
@ -85,7 +105,8 @@ input NewRefreshToken {
|
|||||||
input NewUserAccount {
|
input NewUserAccount {
|
||||||
username: String!
|
username: String!
|
||||||
email: String!
|
email: String!
|
||||||
displayName: String!
|
firstName: String!
|
||||||
|
lastName: String!
|
||||||
password: String!
|
password: String!
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -95,7 +116,8 @@ input NewTeam {
|
|||||||
}
|
}
|
||||||
|
|
||||||
input NewProject {
|
input NewProject {
|
||||||
teamID: String!
|
userID: UUID!
|
||||||
|
teamID: UUID!
|
||||||
name: String!
|
name: String!
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -105,10 +127,6 @@ input NewTaskGroup {
|
|||||||
position: Float!
|
position: Float!
|
||||||
}
|
}
|
||||||
|
|
||||||
input NewOrganization {
|
|
||||||
name: String!
|
|
||||||
}
|
|
||||||
|
|
||||||
input LogoutUser {
|
input LogoutUser {
|
||||||
userID: String!
|
userID: String!
|
||||||
}
|
}
|
||||||
@ -151,13 +169,31 @@ type DeleteTaskGroupPayload {
|
|||||||
taskGroup: TaskGroup!
|
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 {
|
type Mutation {
|
||||||
createRefreshToken(input: NewRefreshToken!): RefreshToken!
|
createRefreshToken(input: NewRefreshToken!): RefreshToken!
|
||||||
|
|
||||||
createUserAccount(input: NewUserAccount!): UserAccount!
|
createUserAccount(input: NewUserAccount!): UserAccount!
|
||||||
|
|
||||||
createOrganization(input: NewOrganization!): Organization!
|
|
||||||
|
|
||||||
createTeam(input: NewTeam!): Team!
|
createTeam(input: NewTeam!): Team!
|
||||||
|
|
||||||
createProject(input: NewProject!): Project!
|
createProject(input: NewProject!): Project!
|
||||||
@ -166,10 +202,15 @@ type Mutation {
|
|||||||
updateTaskGroupLocation(input: NewTaskGroupLocation!): TaskGroup!
|
updateTaskGroupLocation(input: NewTaskGroupLocation!): TaskGroup!
|
||||||
deleteTaskGroup(input: DeleteTaskGroupInput!): DeleteTaskGroupPayload!
|
deleteTaskGroup(input: DeleteTaskGroupInput!): DeleteTaskGroupPayload!
|
||||||
|
|
||||||
|
addTaskLabel(input: AddTaskLabelInput): Task!
|
||||||
|
removeTaskLabel(input: RemoveTaskLabelInput): Task!
|
||||||
|
|
||||||
createTask(input: NewTask!): Task!
|
createTask(input: NewTask!): Task!
|
||||||
|
updateTaskDescription(input: UpdateTaskDescriptionInput!): Task!
|
||||||
updateTaskLocation(input: NewTaskLocation!): Task!
|
updateTaskLocation(input: NewTaskLocation!): Task!
|
||||||
updateTaskName(input: UpdateTaskName!): Task!
|
updateTaskName(input: UpdateTaskName!): Task!
|
||||||
deleteTask(input: DeleteTaskInput!): DeleteTaskPayload!
|
deleteTask(input: DeleteTaskInput!): DeleteTaskPayload!
|
||||||
|
assignTask(input: AssignTaskInput): Task!
|
||||||
|
|
||||||
logoutUser(input: LogoutUser!): Boolean!
|
logoutUser(input: LogoutUser!): Boolean!
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ package graph
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/google/uuid"
|
"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) {
|
func (r *mutationResolver) CreateUserAccount(ctx context.Context, input NewUserAccount) (*pg.UserAccount, error) {
|
||||||
createdAt := time.Now().UTC()
|
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
|
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) {
|
func (r *mutationResolver) CreateTeam(ctx context.Context, input NewTeam) (*pg.Team, error) {
|
||||||
organizationID, err := uuid.Parse(input.OrganizationID)
|
organizationID, err := uuid.Parse(input.OrganizationID)
|
||||||
if err != nil {
|
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) {
|
func (r *mutationResolver) CreateProject(ctx context.Context, input NewProject) (*pg.Project, error) {
|
||||||
createdAt := time.Now().UTC()
|
createdAt := time.Now().UTC()
|
||||||
teamID, err := uuid.Parse(input.TeamID)
|
project, err := r.Repository.CreateProject(ctx, pg.CreateProjectParams{input.UserID, input.TeamID, createdAt, input.Name})
|
||||||
if err != nil {
|
|
||||||
return &pg.Project{}, err
|
|
||||||
}
|
|
||||||
project, err := r.Repository.CreateProject(ctx, pg.CreateProjectParams{teamID, createdAt, input.Name})
|
|
||||||
return &project, err
|
return &project, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,6 +80,20 @@ func (r *mutationResolver) DeleteTaskGroup(ctx context.Context, input DeleteTask
|
|||||||
return &DeleteTaskGroupPayload{true, int(deletedTasks + deletedTaskGroups), &taskGroup}, nil
|
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) {
|
func (r *mutationResolver) CreateTask(ctx context.Context, input NewTask) (*pg.Task, error) {
|
||||||
taskGroupID, err := uuid.Parse(input.TaskGroupID)
|
taskGroupID, err := uuid.Parse(input.TaskGroupID)
|
||||||
createdAt := time.Now().UTC()
|
createdAt := time.Now().UTC()
|
||||||
@ -100,6 +105,11 @@ func (r *mutationResolver) CreateTask(ctx context.Context, input NewTask) (*pg.T
|
|||||||
return &task, err
|
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) {
|
func (r *mutationResolver) UpdateTaskLocation(ctx context.Context, input NewTaskLocation) (*pg.Task, error) {
|
||||||
taskID, err := uuid.Parse(input.TaskID)
|
taskID, err := uuid.Parse(input.TaskID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -139,6 +149,21 @@ func (r *mutationResolver) DeleteTask(ctx context.Context, input DeleteTaskInput
|
|||||||
return &DeleteTaskPayload{taskID.String()}, nil
|
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) {
|
func (r *mutationResolver) LogoutUser(ctx context.Context, input LogoutUser) (bool, error) {
|
||||||
userID, err := uuid.Parse(input.UserID)
|
userID, err := uuid.Parse(input.UserID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -149,21 +174,35 @@ func (r *mutationResolver) LogoutUser(ctx context.Context, input LogoutUser) (bo
|
|||||||
return true, err
|
return true, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *organizationResolver) Teams(ctx context.Context, obj *pg.Organization) ([]pg.Team, error) {
|
func (r *projectResolver) Team(ctx context.Context, obj *pg.Project) (*pg.Team, error) {
|
||||||
teams, err := r.Repository.GetTeamsForOrganization(ctx, obj.OrganizationID)
|
team, err := r.Repository.GetTeamByID(ctx, obj.TeamID)
|
||||||
return teams, err
|
return &team, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *projectResolver) TeamID(ctx context.Context, obj *pg.Project) (string, error) {
|
func (r *projectResolver) Owner(ctx context.Context, obj *pg.Project) (*ProjectMember, error) {
|
||||||
return obj.TeamID.String(), nil
|
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) {
|
func (r *projectResolver) TaskGroups(ctx context.Context, obj *pg.Project) ([]pg.TaskGroup, error) {
|
||||||
return r.Repository.GetTaskGroupsForProject(ctx, obj.ProjectID)
|
return r.Repository.GetTaskGroupsForProject(ctx, obj.ProjectID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *queryResolver) Organizations(ctx context.Context) ([]pg.Organization, error) {
|
func (r *projectResolver) Members(ctx context.Context, obj *pg.Project) ([]ProjectMember, error) {
|
||||||
return r.Repository.GetAllOrganizations(ctx)
|
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) {
|
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
|
return &project, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *queryResolver) Teams(ctx context.Context) ([]pg.Team, error) {
|
func (r *queryResolver) FindTask(ctx context.Context, input FindTask) (*pg.Task, error) {
|
||||||
return r.Repository.GetAllTeams(ctx)
|
task, err := r.Repository.GetTaskByID(ctx, input.TaskID)
|
||||||
|
return &task, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *queryResolver) Projects(ctx context.Context, input *ProjectsFilter) ([]pg.Project, error) {
|
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)
|
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) {
|
func (r *taskResolver) TaskGroup(ctx context.Context, obj *pg.Task) (*pg.TaskGroup, error) {
|
||||||
taskGroup, err := r.Repository.GetTaskGroupByID(ctx, obj.TaskGroupID)
|
taskGroup, err := r.Repository.GetTaskGroupByID(ctx, obj.TaskGroupID)
|
||||||
return &taskGroup, err
|
return &taskGroup, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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) {
|
func (r *taskGroupResolver) ProjectID(ctx context.Context, obj *pg.TaskGroup) (string, error) {
|
||||||
return obj.ProjectID.String(), nil
|
return obj.ProjectID.String(), nil
|
||||||
}
|
}
|
||||||
@ -237,16 +325,23 @@ func (r *taskGroupResolver) Tasks(ctx context.Context, obj *pg.TaskGroup) ([]pg.
|
|||||||
return tasks, err
|
return tasks, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *teamResolver) Projects(ctx context.Context, obj *pg.Team) ([]pg.Project, error) {
|
func (r *taskLabelResolver) ColorHex(ctx context.Context, obj *pg.TaskLabel) (string, error) {
|
||||||
return r.Repository.GetAllProjectsForTeam(ctx, obj.TeamID)
|
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.
|
// Mutation returns MutationResolver implementation.
|
||||||
func (r *Resolver) Mutation() MutationResolver { return &mutationResolver{r} }
|
func (r *Resolver) Mutation() MutationResolver { return &mutationResolver{r} }
|
||||||
|
|
||||||
// Organization returns OrganizationResolver implementation.
|
|
||||||
func (r *Resolver) Organization() OrganizationResolver { return &organizationResolver{r} }
|
|
||||||
|
|
||||||
// Project returns ProjectResolver implementation.
|
// Project returns ProjectResolver implementation.
|
||||||
func (r *Resolver) Project() ProjectResolver { return &projectResolver{r} }
|
func (r *Resolver) Project() ProjectResolver { return &projectResolver{r} }
|
||||||
|
|
||||||
@ -259,13 +354,26 @@ func (r *Resolver) Task() TaskResolver { return &taskResolver{r} }
|
|||||||
// TaskGroup returns TaskGroupResolver implementation.
|
// TaskGroup returns TaskGroupResolver implementation.
|
||||||
func (r *Resolver) TaskGroup() TaskGroupResolver { return &taskGroupResolver{r} }
|
func (r *Resolver) TaskGroup() TaskGroupResolver { return &taskGroupResolver{r} }
|
||||||
|
|
||||||
// Team returns TeamResolver implementation.
|
// TaskLabel returns TaskLabelResolver implementation.
|
||||||
func (r *Resolver) Team() TeamResolver { return &teamResolver{r} }
|
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 mutationResolver struct{ *Resolver }
|
||||||
type organizationResolver struct{ *Resolver }
|
|
||||||
type projectResolver struct{ *Resolver }
|
type projectResolver struct{ *Resolver }
|
||||||
type queryResolver struct{ *Resolver }
|
type queryResolver struct{ *Resolver }
|
||||||
type taskResolver struct{ *Resolver }
|
type taskResolver struct{ *Resolver }
|
||||||
type taskGroupResolver 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
|
||||||
|
}
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
CREATE TABLE user_account (
|
CREATE TABLE user_account (
|
||||||
user_id uuid PRIMARY KEY DEFAULT uuid_generate_v4(),
|
user_id uuid PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||||||
created_at timestamptz NOT NULL,
|
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,
|
email text NOT NULL UNIQUE,
|
||||||
username text NOT NULL UNIQUE,
|
username text NOT NULL UNIQUE,
|
||||||
password_hash text NOT NULL
|
password_hash text NOT NULL
|
6
api/migrations/0009_add-task-assigned-table.up.sql
Normal file
6
api/migrations/0009_add-task-assigned-table.up.sql
Normal file
@ -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
|
||||||
|
);
|
1
api/migrations/0010_add-description-to-task-table.up.sql
Normal file
1
api/migrations/0010_add-description-to-task-table.up.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
ALTER TABLE task ADD COLUMN description text;
|
5
api/migrations/0011_add-label-color-table.up.sql
Normal file
5
api/migrations/0011_add-label-color-table.up.sql
Normal file
@ -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
|
||||||
|
);
|
6
api/migrations/0012-add-task-label-table.up.sql
Normal file
6
api/migrations/0012-add-task-label-table.up.sql
Normal file
@ -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
|
||||||
|
);
|
1
api/migrations/0013_add-due-date-to-task-table.up.sql
Normal file
1
api/migrations/0013_add-due-date-to-task-table.up.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
ALTER TABLE task ADD COLUMN due_date timestamptz;
|
@ -0,0 +1 @@
|
|||||||
|
ALTER TABLE project ADD COLUMN owner uuid NOT NULL;
|
21
api/pg/label_color.sql.go
Normal file
21
api/pg/label_color.sql.go
Normal file
@ -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
|
||||||
|
}
|
@ -3,11 +3,18 @@
|
|||||||
package pg
|
package pg
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"database/sql"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/google/uuid"
|
"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 {
|
type Organization struct {
|
||||||
OrganizationID uuid.UUID `json:"organization_id"`
|
OrganizationID uuid.UUID `json:"organization_id"`
|
||||||
CreatedAt time.Time `json:"created_at"`
|
CreatedAt time.Time `json:"created_at"`
|
||||||
@ -19,6 +26,7 @@ type Project struct {
|
|||||||
TeamID uuid.UUID `json:"team_id"`
|
TeamID uuid.UUID `json:"team_id"`
|
||||||
CreatedAt time.Time `json:"created_at"`
|
CreatedAt time.Time `json:"created_at"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
|
Owner uuid.UUID `json:"owner"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type RefreshToken struct {
|
type RefreshToken struct {
|
||||||
@ -34,6 +42,15 @@ type Task struct {
|
|||||||
CreatedAt time.Time `json:"created_at"`
|
CreatedAt time.Time `json:"created_at"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Position float64 `json:"position"`
|
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 {
|
type TaskGroup struct {
|
||||||
@ -44,6 +61,13 @@ type TaskGroup struct {
|
|||||||
Position float64 `json:"position"`
|
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 {
|
type Team struct {
|
||||||
TeamID uuid.UUID `json:"team_id"`
|
TeamID uuid.UUID `json:"team_id"`
|
||||||
CreatedAt time.Time `json:"created_at"`
|
CreatedAt time.Time `json:"created_at"`
|
||||||
@ -54,7 +78,8 @@ type Team struct {
|
|||||||
type UserAccount struct {
|
type UserAccount struct {
|
||||||
UserID uuid.UUID `json:"user_id"`
|
UserID uuid.UUID `json:"user_id"`
|
||||||
CreatedAt time.Time `json:"created_at"`
|
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"`
|
Email string `json:"email"`
|
||||||
Username string `json:"username"`
|
Username string `json:"username"`
|
||||||
PasswordHash string `json:"password_hash"`
|
PasswordHash string `json:"password_hash"`
|
||||||
|
@ -41,11 +41,20 @@ type Repository interface {
|
|||||||
GetTeamsForOrganization(ctx context.Context, organizationID uuid.UUID) ([]Team, error)
|
GetTeamsForOrganization(ctx context.Context, organizationID uuid.UUID) ([]Team, error)
|
||||||
|
|
||||||
CreateTask(ctx context.Context, arg CreateTaskParams) (Task, error)
|
CreateTask(ctx context.Context, arg CreateTaskParams) (Task, error)
|
||||||
|
GetTaskByID(ctx context.Context, taskID uuid.UUID) (Task, error)
|
||||||
GetAllTasks(ctx context.Context) ([]Task, error)
|
GetAllTasks(ctx context.Context) ([]Task, error)
|
||||||
GetTasksForTaskGroupID(ctx context.Context, taskGroupID uuid.UUID) ([]Task, error)
|
GetTasksForTaskGroupID(ctx context.Context, taskGroupID uuid.UUID) ([]Task, error)
|
||||||
UpdateTaskLocation(ctx context.Context, arg UpdateTaskLocationParams) (Task, error)
|
UpdateTaskLocation(ctx context.Context, arg UpdateTaskLocationParams) (Task, error)
|
||||||
DeleteTaskByID(ctx context.Context, taskID uuid.UUID) error
|
DeleteTaskByID(ctx context.Context, taskID uuid.UUID) error
|
||||||
UpdateTaskName(ctx context.Context, arg UpdateTaskNameParams) (Task, 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 {
|
type repoSvc struct {
|
||||||
|
@ -11,29 +11,36 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const createProject = `-- name: CreateProject :one
|
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 {
|
type CreateProjectParams struct {
|
||||||
|
Owner uuid.UUID `json:"owner"`
|
||||||
TeamID uuid.UUID `json:"team_id"`
|
TeamID uuid.UUID `json:"team_id"`
|
||||||
CreatedAt time.Time `json:"created_at"`
|
CreatedAt time.Time `json:"created_at"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Queries) CreateProject(ctx context.Context, arg CreateProjectParams) (Project, error) {
|
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
|
var i Project
|
||||||
err := row.Scan(
|
err := row.Scan(
|
||||||
&i.ProjectID,
|
&i.ProjectID,
|
||||||
&i.TeamID,
|
&i.TeamID,
|
||||||
&i.CreatedAt,
|
&i.CreatedAt,
|
||||||
&i.Name,
|
&i.Name,
|
||||||
|
&i.Owner,
|
||||||
)
|
)
|
||||||
return i, err
|
return i, err
|
||||||
}
|
}
|
||||||
|
|
||||||
const getAllProjects = `-- name: GetAllProjects :many
|
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) {
|
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.TeamID,
|
||||||
&i.CreatedAt,
|
&i.CreatedAt,
|
||||||
&i.Name,
|
&i.Name,
|
||||||
|
&i.Owner,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -65,7 +73,7 @@ func (q *Queries) GetAllProjects(ctx context.Context) ([]Project, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const getAllProjectsForTeam = `-- name: GetAllProjectsForTeam :many
|
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) {
|
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.TeamID,
|
||||||
&i.CreatedAt,
|
&i.CreatedAt,
|
||||||
&i.Name,
|
&i.Name,
|
||||||
|
&i.Owner,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -97,7 +106,7 @@ func (q *Queries) GetAllProjectsForTeam(ctx context.Context, teamID uuid.UUID) (
|
|||||||
}
|
}
|
||||||
|
|
||||||
const getProjectByID = `-- name: GetProjectByID :one
|
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) {
|
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.TeamID,
|
||||||
&i.CreatedAt,
|
&i.CreatedAt,
|
||||||
&i.Name,
|
&i.Name,
|
||||||
|
&i.Owner,
|
||||||
)
|
)
|
||||||
return i, err
|
return i, err
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,9 @@ type Querier interface {
|
|||||||
CreateProject(ctx context.Context, arg CreateProjectParams) (Project, error)
|
CreateProject(ctx context.Context, arg CreateProjectParams) (Project, error)
|
||||||
CreateRefreshToken(ctx context.Context, arg CreateRefreshTokenParams) (RefreshToken, error)
|
CreateRefreshToken(ctx context.Context, arg CreateRefreshTokenParams) (RefreshToken, error)
|
||||||
CreateTask(ctx context.Context, arg CreateTaskParams) (Task, 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)
|
CreateTaskGroup(ctx context.Context, arg CreateTaskGroupParams) (TaskGroup, error)
|
||||||
|
CreateTaskLabelForTask(ctx context.Context, arg CreateTaskLabelForTaskParams) (TaskLabel, error)
|
||||||
CreateTeam(ctx context.Context, arg CreateTeamParams) (Team, error)
|
CreateTeam(ctx context.Context, arg CreateTeamParams) (Team, error)
|
||||||
CreateUserAccount(ctx context.Context, arg CreateUserAccountParams) (UserAccount, error)
|
CreateUserAccount(ctx context.Context, arg CreateUserAccountParams) (UserAccount, error)
|
||||||
DeleteExpiredTokens(ctx context.Context) error
|
DeleteExpiredTokens(ctx context.Context) error
|
||||||
@ -30,15 +32,20 @@ type Querier interface {
|
|||||||
GetAllTasks(ctx context.Context) ([]Task, error)
|
GetAllTasks(ctx context.Context) ([]Task, error)
|
||||||
GetAllTeams(ctx context.Context) ([]Team, error)
|
GetAllTeams(ctx context.Context) ([]Team, error)
|
||||||
GetAllUserAccounts(ctx context.Context) ([]UserAccount, 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)
|
GetProjectByID(ctx context.Context, projectID uuid.UUID) (Project, error)
|
||||||
GetRefreshTokenByID(ctx context.Context, tokenID uuid.UUID) (RefreshToken, 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)
|
GetTaskGroupByID(ctx context.Context, taskGroupID uuid.UUID) (TaskGroup, error)
|
||||||
GetTaskGroupsForProject(ctx context.Context, projectID 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)
|
GetTasksForTaskGroupID(ctx context.Context, taskGroupID uuid.UUID) ([]Task, error)
|
||||||
GetTeamByID(ctx context.Context, teamID uuid.UUID) (Team, error)
|
GetTeamByID(ctx context.Context, teamID uuid.UUID) (Team, error)
|
||||||
GetTeamsForOrganization(ctx context.Context, organizationID uuid.UUID) ([]Team, error)
|
GetTeamsForOrganization(ctx context.Context, organizationID uuid.UUID) ([]Team, error)
|
||||||
GetUserAccountByID(ctx context.Context, userID uuid.UUID) (UserAccount, error)
|
GetUserAccountByID(ctx context.Context, userID uuid.UUID) (UserAccount, error)
|
||||||
GetUserAccountByUsername(ctx context.Context, username string) (UserAccount, error)
|
GetUserAccountByUsername(ctx context.Context, username string) (UserAccount, error)
|
||||||
|
UpdateTaskDescription(ctx context.Context, arg UpdateTaskDescriptionParams) (Task, error)
|
||||||
UpdateTaskGroupLocation(ctx context.Context, arg UpdateTaskGroupLocationParams) (TaskGroup, error)
|
UpdateTaskGroupLocation(ctx context.Context, arg UpdateTaskGroupLocationParams) (TaskGroup, error)
|
||||||
UpdateTaskLocation(ctx context.Context, arg UpdateTaskLocationParams) (Task, error)
|
UpdateTaskLocation(ctx context.Context, arg UpdateTaskLocationParams) (Task, error)
|
||||||
UpdateTaskName(ctx context.Context, arg UpdateTaskNameParams) (Task, error)
|
UpdateTaskName(ctx context.Context, arg UpdateTaskNameParams) (Task, error)
|
||||||
|
@ -5,6 +5,7 @@ package pg
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"database/sql"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
@ -12,7 +13,7 @@ import (
|
|||||||
|
|
||||||
const createTask = `-- name: CreateTask :one
|
const createTask = `-- name: CreateTask :one
|
||||||
INSERT INTO task (task_group_id, created_at, name, position)
|
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 {
|
type CreateTaskParams struct {
|
||||||
@ -36,6 +37,8 @@ func (q *Queries) CreateTask(ctx context.Context, arg CreateTaskParams) (Task, e
|
|||||||
&i.CreatedAt,
|
&i.CreatedAt,
|
||||||
&i.Name,
|
&i.Name,
|
||||||
&i.Position,
|
&i.Position,
|
||||||
|
&i.Description,
|
||||||
|
&i.DueDate,
|
||||||
)
|
)
|
||||||
return i, err
|
return i, err
|
||||||
}
|
}
|
||||||
@ -62,7 +65,7 @@ func (q *Queries) DeleteTasksByTaskGroupID(ctx context.Context, taskGroupID uuid
|
|||||||
}
|
}
|
||||||
|
|
||||||
const getAllTasks = `-- name: GetAllTasks :many
|
const getAllTasks = `-- name: GetAllTasks :many
|
||||||
SELECT task_id, task_group_id, created_at, name, position FROM task
|
SELECT task_id, task_group_id, created_at, name, position, description, due_date FROM task
|
||||||
`
|
`
|
||||||
|
|
||||||
func (q *Queries) GetAllTasks(ctx context.Context) ([]Task, error) {
|
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.CreatedAt,
|
||||||
&i.Name,
|
&i.Name,
|
||||||
&i.Position,
|
&i.Position,
|
||||||
|
&i.Description,
|
||||||
|
&i.DueDate,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -94,8 +99,27 @@ func (q *Queries) GetAllTasks(ctx context.Context) ([]Task, error) {
|
|||||||
return items, nil
|
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
|
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) {
|
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.CreatedAt,
|
||||||
&i.Name,
|
&i.Name,
|
||||||
&i.Position,
|
&i.Position,
|
||||||
|
&i.Description,
|
||||||
|
&i.DueDate,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -127,8 +153,32 @@ func (q *Queries) GetTasksForTaskGroupID(ctx context.Context, taskGroupID uuid.U
|
|||||||
return items, nil
|
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
|
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 {
|
type UpdateTaskLocationParams struct {
|
||||||
@ -146,12 +196,14 @@ func (q *Queries) UpdateTaskLocation(ctx context.Context, arg UpdateTaskLocation
|
|||||||
&i.CreatedAt,
|
&i.CreatedAt,
|
||||||
&i.Name,
|
&i.Name,
|
||||||
&i.Position,
|
&i.Position,
|
||||||
|
&i.Description,
|
||||||
|
&i.DueDate,
|
||||||
)
|
)
|
||||||
return i, err
|
return i, err
|
||||||
}
|
}
|
||||||
|
|
||||||
const updateTaskName = `-- name: UpdateTaskName :one
|
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 {
|
type UpdateTaskNameParams struct {
|
||||||
@ -168,6 +220,8 @@ func (q *Queries) UpdateTaskName(ctx context.Context, arg UpdateTaskNameParams)
|
|||||||
&i.CreatedAt,
|
&i.CreatedAt,
|
||||||
&i.Name,
|
&i.Name,
|
||||||
&i.Position,
|
&i.Position,
|
||||||
|
&i.Description,
|
||||||
|
&i.DueDate,
|
||||||
)
|
)
|
||||||
return i, err
|
return i, err
|
||||||
}
|
}
|
||||||
|
66
api/pg/task_assigned.sql.go
Normal file
66
api/pg/task_assigned.sql.go
Normal file
@ -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
|
||||||
|
}
|
66
api/pg/task_label.sql.go
Normal file
66
api/pg/task_label.sql.go
Normal file
@ -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
|
||||||
|
}
|
@ -11,13 +11,14 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const createUserAccount = `-- name: CreateUserAccount :one
|
const createUserAccount = `-- name: CreateUserAccount :one
|
||||||
INSERT INTO user_account(display_name, email, username, created_at, password_hash)
|
INSERT INTO user_account(first_name, last_name, email, username, created_at, password_hash)
|
||||||
VALUES ($1, $2, $3, $4, $5)
|
VALUES ($1, $2, $3, $4, $5, $6)
|
||||||
RETURNING user_id, created_at, display_name, email, username, password_hash
|
RETURNING user_id, created_at, first_name, last_name, email, username, password_hash
|
||||||
`
|
`
|
||||||
|
|
||||||
type CreateUserAccountParams struct {
|
type CreateUserAccountParams struct {
|
||||||
DisplayName string `json:"display_name"`
|
FirstName string `json:"first_name"`
|
||||||
|
LastName string `json:"last_name"`
|
||||||
Email string `json:"email"`
|
Email string `json:"email"`
|
||||||
Username string `json:"username"`
|
Username string `json:"username"`
|
||||||
CreatedAt time.Time `json:"created_at"`
|
CreatedAt time.Time `json:"created_at"`
|
||||||
@ -26,7 +27,8 @@ type CreateUserAccountParams struct {
|
|||||||
|
|
||||||
func (q *Queries) CreateUserAccount(ctx context.Context, arg CreateUserAccountParams) (UserAccount, error) {
|
func (q *Queries) CreateUserAccount(ctx context.Context, arg CreateUserAccountParams) (UserAccount, error) {
|
||||||
row := q.db.QueryRowContext(ctx, createUserAccount,
|
row := q.db.QueryRowContext(ctx, createUserAccount,
|
||||||
arg.DisplayName,
|
arg.FirstName,
|
||||||
|
arg.LastName,
|
||||||
arg.Email,
|
arg.Email,
|
||||||
arg.Username,
|
arg.Username,
|
||||||
arg.CreatedAt,
|
arg.CreatedAt,
|
||||||
@ -36,7 +38,8 @@ func (q *Queries) CreateUserAccount(ctx context.Context, arg CreateUserAccountPa
|
|||||||
err := row.Scan(
|
err := row.Scan(
|
||||||
&i.UserID,
|
&i.UserID,
|
||||||
&i.CreatedAt,
|
&i.CreatedAt,
|
||||||
&i.DisplayName,
|
&i.FirstName,
|
||||||
|
&i.LastName,
|
||||||
&i.Email,
|
&i.Email,
|
||||||
&i.Username,
|
&i.Username,
|
||||||
&i.PasswordHash,
|
&i.PasswordHash,
|
||||||
@ -45,7 +48,7 @@ func (q *Queries) CreateUserAccount(ctx context.Context, arg CreateUserAccountPa
|
|||||||
}
|
}
|
||||||
|
|
||||||
const getAllUserAccounts = `-- name: GetAllUserAccounts :many
|
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) {
|
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(
|
if err := rows.Scan(
|
||||||
&i.UserID,
|
&i.UserID,
|
||||||
&i.CreatedAt,
|
&i.CreatedAt,
|
||||||
&i.DisplayName,
|
&i.FirstName,
|
||||||
|
&i.LastName,
|
||||||
&i.Email,
|
&i.Email,
|
||||||
&i.Username,
|
&i.Username,
|
||||||
&i.PasswordHash,
|
&i.PasswordHash,
|
||||||
@ -79,7 +83,7 @@ func (q *Queries) GetAllUserAccounts(ctx context.Context) ([]UserAccount, error)
|
|||||||
}
|
}
|
||||||
|
|
||||||
const getUserAccountByID = `-- name: GetUserAccountByID :one
|
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) {
|
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(
|
err := row.Scan(
|
||||||
&i.UserID,
|
&i.UserID,
|
||||||
&i.CreatedAt,
|
&i.CreatedAt,
|
||||||
&i.DisplayName,
|
&i.FirstName,
|
||||||
|
&i.LastName,
|
||||||
&i.Email,
|
&i.Email,
|
||||||
&i.Username,
|
&i.Username,
|
||||||
&i.PasswordHash,
|
&i.PasswordHash,
|
||||||
@ -97,7 +102,7 @@ func (q *Queries) GetUserAccountByID(ctx context.Context, userID uuid.UUID) (Use
|
|||||||
}
|
}
|
||||||
|
|
||||||
const getUserAccountByUsername = `-- name: GetUserAccountByUsername :one
|
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) {
|
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(
|
err := row.Scan(
|
||||||
&i.UserID,
|
&i.UserID,
|
||||||
&i.CreatedAt,
|
&i.CreatedAt,
|
||||||
&i.DisplayName,
|
&i.FirstName,
|
||||||
|
&i.LastName,
|
||||||
&i.Email,
|
&i.Email,
|
||||||
&i.Username,
|
&i.Username,
|
||||||
&i.PasswordHash,
|
&i.PasswordHash,
|
||||||
|
2
api/query/label_color.sql
Normal file
2
api/query/label_color.sql
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
-- name: GetLabelColorByID :one
|
||||||
|
SELECT * FROM label_color WHERE label_color_id = $1;
|
@ -8,4 +8,4 @@ SELECT * FROM project WHERE team_id = $1;
|
|||||||
SELECT * FROM project WHERE project_id = $1;
|
SELECT * FROM project WHERE project_id = $1;
|
||||||
|
|
||||||
-- name: CreateProject :one
|
-- 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 *;
|
||||||
|
@ -2,6 +2,12 @@
|
|||||||
INSERT INTO task (task_group_id, created_at, name, position)
|
INSERT INTO task (task_group_id, created_at, name, position)
|
||||||
VALUES($1, $2, $3, $4) RETURNING *;
|
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
|
-- name: GetTasksForTaskGroupID :many
|
||||||
SELECT * FROM task WHERE task_group_id = $1;
|
SELECT * FROM task WHERE task_group_id = $1;
|
||||||
|
|
||||||
|
6
api/query/task_assigned.sql
Normal file
6
api/query/task_assigned.sql
Normal file
@ -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;
|
6
api/query/task_label.sql
Normal file
6
api/query/task_label.sql
Normal file
@ -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;
|
@ -8,6 +8,6 @@ SELECT * FROM user_account;
|
|||||||
SELECT * FROM user_account WHERE username = $1;
|
SELECT * FROM user_account WHERE username = $1;
|
||||||
|
|
||||||
-- name: CreateUserAccount :one
|
-- name: CreateUserAccount :one
|
||||||
INSERT INTO user_account(display_name, email, username, created_at, password_hash)
|
INSERT INTO user_account(first_name, last_name, email, username, created_at, password_hash)
|
||||||
VALUES ($1, $2, $3, $4, $5)
|
VALUES ($1, $2, $3, $4, $5, $6)
|
||||||
RETURNING *;
|
RETURNING *;
|
||||||
|
@ -42,7 +42,7 @@ func (h *CitadelHandler) RefreshTokenHandler(w http.ResponseWriter, r *http.Requ
|
|||||||
w.WriteHeader(http.StatusInternalServerError)
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
}
|
}
|
||||||
|
|
||||||
accessTokenString, err := NewAccessToken("1")
|
accessTokenString, err := NewAccessToken(token.UserID.String())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
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})
|
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) {
|
func (h *CitadelHandler) LoginHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
var requestData LoginRequestData
|
var requestData LoginRequestData
|
||||||
err := json.NewDecoder(r.Body).Decode(&requestData)
|
err := json.NewDecoder(r.Body).Decode(&requestData)
|
||||||
@ -85,12 +104,11 @@ func (h *CitadelHandler) LoginHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
userID := uuid.MustParse("0183d9ab-d0ed-4c9b-a3df-77a0cdd93dca")
|
|
||||||
refreshCreatedAt := time.Now().UTC()
|
refreshCreatedAt := time.Now().UTC()
|
||||||
refreshExpiresAt := refreshCreatedAt.AddDate(0, 0, 1)
|
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 {
|
if err != nil {
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
}
|
}
|
||||||
@ -109,5 +127,6 @@ func (rs authResource) Routes(citadelHandler CitadelHandler) chi.Router {
|
|||||||
r := chi.NewRouter()
|
r := chi.NewRouter()
|
||||||
r.Post("/login", citadelHandler.LoginHandler)
|
r.Post("/login", citadelHandler.LoginHandler)
|
||||||
r.Post("/refresh_token", citadelHandler.RefreshTokenHandler)
|
r.Post("/refresh_token", citadelHandler.RefreshTokenHandler)
|
||||||
|
r.Post("/logout", citadelHandler.LogoutHandler)
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -40,7 +41,13 @@ func AuthenticationMiddleware(next http.Handler) http.Handler {
|
|||||||
return
|
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))
|
next.ServeHTTP(w, r.WithContext(ctx))
|
||||||
})
|
})
|
||||||
|
@ -23,6 +23,10 @@ type LoginResponseData struct {
|
|||||||
AccessToken string `json:"accessToken"`
|
AccessToken string `json:"accessToken"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type LogoutResponseData struct {
|
||||||
|
Status string `json:"status"`
|
||||||
|
}
|
||||||
|
|
||||||
type RefreshTokenResponseData struct {
|
type RefreshTokenResponseData struct {
|
||||||
AccessToken string `json:"accessToken"`
|
AccessToken string `json:"accessToken"`
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
"@testing-library/user-event": "^7.1.2",
|
"@testing-library/user-event": "^7.1.2",
|
||||||
"@types/color": "^3.0.1",
|
"@types/color": "^3.0.1",
|
||||||
"@types/jest": "^24.0.0",
|
"@types/jest": "^24.0.0",
|
||||||
|
"@types/jwt-decode": "^2.2.1",
|
||||||
"@types/lodash": "^4.14.149",
|
"@types/lodash": "^4.14.149",
|
||||||
"@types/node": "^12.0.0",
|
"@types/node": "^12.0.0",
|
||||||
"@types/react": "^16.9.21",
|
"@types/react": "^16.9.21",
|
||||||
@ -41,6 +42,7 @@
|
|||||||
"graphql-tag": "^2.10.3",
|
"graphql-tag": "^2.10.3",
|
||||||
"history": "^4.10.1",
|
"history": "^4.10.1",
|
||||||
"immer": "^6.0.3",
|
"immer": "^6.0.3",
|
||||||
|
"jwt-decode": "^2.2.0",
|
||||||
"lodash": "^4.17.15",
|
"lodash": "^4.17.15",
|
||||||
"moment": "^2.24.0",
|
"moment": "^2.24.0",
|
||||||
"prop-types": "^15.7.2",
|
"prop-types": "^15.7.2",
|
||||||
|
@ -7,6 +7,7 @@ export default createGlobalStyle`
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
min-height: 100%;
|
min-height: 100%;
|
||||||
min-width: 768px;
|
min-width: 768px;
|
||||||
|
background: #262c49;
|
||||||
}
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
|
@ -1,9 +1,14 @@
|
|||||||
import React from 'react';
|
import React, { useContext } from 'react';
|
||||||
import { Home, Stack } from 'shared/icons';
|
import { Home, Stack } from 'shared/icons';
|
||||||
import Navbar, { ActionButton, ButtonContainer, PrimaryLogo } from 'shared/components/Navbar';
|
import Navbar, { ActionButton, ButtonContainer, PrimaryLogo } from 'shared/components/Navbar';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
|
import UserIDContext from './context';
|
||||||
|
|
||||||
const GlobalNavbar = () => {
|
const GlobalNavbar = () => {
|
||||||
|
const { userID } = useContext(UserIDContext);
|
||||||
|
if (!userID) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<Navbar>
|
<Navbar>
|
||||||
<PrimaryLogo />
|
<PrimaryLogo />
|
||||||
|
@ -12,14 +12,12 @@ type RoutesProps = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const Routes = ({ history }: RoutesProps) => (
|
const Routes = ({ history }: RoutesProps) => (
|
||||||
<Router history={history}>
|
|
||||||
<Switch>
|
<Switch>
|
||||||
|
<Route exact path="/login" component={Login} />
|
||||||
<Route exact path="/" component={Dashboard} />
|
<Route exact path="/" component={Dashboard} />
|
||||||
<Route exact path="/projects" component={Projects} />
|
<Route exact path="/projects" component={Projects} />
|
||||||
<Route path="/projects/:projectId" component={Project} />
|
<Route path="/projects/:projectId" component={Project} />
|
||||||
<Route exact path="/login" component={Login} />
|
|
||||||
</Switch>
|
</Switch>
|
||||||
</Router>
|
|
||||||
);
|
);
|
||||||
|
|
||||||
export default Routes;
|
export default Routes;
|
||||||
|
@ -1,8 +1,14 @@
|
|||||||
import React, { useState } from 'react';
|
import React, { useState, useContext } from 'react';
|
||||||
import TopNavbar from 'shared/components/TopNavbar';
|
import TopNavbar from 'shared/components/TopNavbar';
|
||||||
import DropdownMenu from 'shared/components/DropdownMenu';
|
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 GlobalTopNavbar: React.FC = () => {
|
||||||
|
const { loading, data } = useMeQuery();
|
||||||
|
const history = useHistory();
|
||||||
|
const { userID, setUserID } = useContext(UserIDContext);
|
||||||
const [menu, setMenu] = useState({
|
const [menu, setMenu] = useState({
|
||||||
top: 0,
|
top: 0,
|
||||||
left: 0,
|
left: 0,
|
||||||
@ -15,10 +21,33 @@ const GlobalTopNavbar: React.FC = () => {
|
|||||||
top: bottom,
|
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 (
|
return (
|
||||||
<>
|
<>
|
||||||
<TopNavbar onNotificationClick={() => console.log('beep')} onProfileClick={onProfileClick} />
|
<TopNavbar
|
||||||
{menu.isOpen && <DropdownMenu left={menu.left} top={menu.top} />}
|
firstName={data ? data.me.firstName : ''}
|
||||||
|
lastName={data ? data.me.lastName : ''}
|
||||||
|
initials={!data ? '' : data.me.profileIcon.initials ?? ''}
|
||||||
|
onNotificationClick={() => console.log('beep')}
|
||||||
|
onProfileClick={onProfileClick}
|
||||||
|
/>
|
||||||
|
{menu.isOpen && <DropdownMenu onLogout={onLogout} left={menu.left} top={menu.top} />}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
9
web/src/App/context.ts
Normal file
9
web/src/App/context.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
type UserIDContextState = {
|
||||||
|
userID: string | null;
|
||||||
|
setUserID: (userID: string | null) => void;
|
||||||
|
};
|
||||||
|
export const UserIDContext = React.createContext<UserIDContextState>({ userID: null, setUserID: _userID => null });
|
||||||
|
|
||||||
|
export default UserIDContext;
|
@ -1,22 +1,27 @@
|
|||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
|
import jwtDecode from 'jwt-decode';
|
||||||
import { createBrowserHistory } from 'history';
|
import { createBrowserHistory } from 'history';
|
||||||
import { setAccessToken } from 'shared/utils/accessToken';
|
import { setAccessToken } from 'shared/utils/accessToken';
|
||||||
import Navbar from 'shared/components/Navbar';
|
|
||||||
import GlobalTopNavbar from 'App/TopNavbar';
|
import GlobalTopNavbar from 'App/TopNavbar';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
import NormalizeStyles from './NormalizeStyles';
|
import NormalizeStyles from './NormalizeStyles';
|
||||||
import BaseStyles from './BaseStyles';
|
import BaseStyles from './BaseStyles';
|
||||||
import Routes from './Routes';
|
import Routes from './Routes';
|
||||||
|
import { UserIDContext } from './context';
|
||||||
|
import Navbar from './Navbar';
|
||||||
|
import { Router } from 'react-router';
|
||||||
|
|
||||||
const history = createBrowserHistory();
|
const history = createBrowserHistory();
|
||||||
|
|
||||||
const MainContent = styled.div`
|
const MainContent = styled.div`
|
||||||
padding: 0 0 50px 80px;
|
padding: 0 0 50px 80px;
|
||||||
background: #262c49;
|
background: #262c49;
|
||||||
|
height: 100%;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const App = () => {
|
const App = () => {
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
|
const [userID, setUserID] = useState<string | null>(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetch('http://localhost:3333/auth/refresh_token', {
|
fetch('http://localhost:3333/auth/refresh_token', {
|
||||||
@ -29,28 +34,33 @@ const App = () => {
|
|||||||
} else {
|
} else {
|
||||||
const response: RefreshTokenResponse = await x.json();
|
const response: RefreshTokenResponse = await x.json();
|
||||||
const { accessToken } = response;
|
const { accessToken } = response;
|
||||||
|
const claims: JWTToken = jwtDecode(accessToken);
|
||||||
|
setUserID(claims.userId);
|
||||||
setAccessToken(accessToken);
|
setAccessToken(accessToken);
|
||||||
}
|
}
|
||||||
// }
|
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
});
|
});
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
if (loading) {
|
|
||||||
return (
|
return (
|
||||||
|
<>
|
||||||
|
<UserIDContext.Provider value={{ userID, setUserID }}>
|
||||||
|
<NormalizeStyles />
|
||||||
|
<BaseStyles />
|
||||||
|
<Router history={history}>
|
||||||
|
{loading ? (
|
||||||
|
<div>loading</div>
|
||||||
|
) : (
|
||||||
<>
|
<>
|
||||||
<Navbar />
|
<Navbar />
|
||||||
<MainContent>
|
<MainContent>
|
||||||
<GlobalTopNavbar />
|
<GlobalTopNavbar />
|
||||||
|
<Routes history={history} />
|
||||||
</MainContent>
|
</MainContent>
|
||||||
</>
|
</>
|
||||||
);
|
)}
|
||||||
}
|
</Router>
|
||||||
return (
|
</UserIDContext.Provider>
|
||||||
<>
|
|
||||||
<NormalizeStyles />
|
|
||||||
<BaseStyles />
|
|
||||||
<Routes history={history} />
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect, useContext } from 'react';
|
||||||
import { useForm } from 'react-hook-form';
|
import { useForm } from 'react-hook-form';
|
||||||
import { useHistory } from 'react-router';
|
import { useHistory } from 'react-router';
|
||||||
|
|
||||||
@ -6,10 +6,13 @@ import { setAccessToken } from 'shared/utils/accessToken';
|
|||||||
|
|
||||||
import Login from 'shared/components/Login';
|
import Login from 'shared/components/Login';
|
||||||
import { Container, LoginWrapper } from './Styles';
|
import { Container, LoginWrapper } from './Styles';
|
||||||
|
import UserIDContext from 'App/context';
|
||||||
|
import JwtDecode from 'jwt-decode';
|
||||||
|
|
||||||
const Auth = () => {
|
const Auth = () => {
|
||||||
const [invalidLoginAttempt, setInvalidLoginAttempt] = useState(0);
|
const [invalidLoginAttempt, setInvalidLoginAttempt] = useState(0);
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
|
const { setUserID } = useContext(UserIDContext);
|
||||||
const login = (
|
const login = (
|
||||||
data: LoginFormData,
|
data: LoginFormData,
|
||||||
setComplete: (val: boolean) => void,
|
setComplete: (val: boolean) => void,
|
||||||
@ -31,8 +34,11 @@ const Auth = () => {
|
|||||||
} else {
|
} else {
|
||||||
const response = await x.json();
|
const response = await x.json();
|
||||||
const { accessToken } = response;
|
const { accessToken } = response;
|
||||||
setAccessToken(accessToken);
|
const claims: JWTToken = JwtDecode(accessToken);
|
||||||
|
setUserID(claims.userId);
|
||||||
setComplete(true);
|
setComplete(true);
|
||||||
|
setAccessToken(accessToken);
|
||||||
|
|
||||||
history.push('/');
|
history.push('/');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
110
web/src/Projects/Project/Details/index.tsx
Normal file
110
web/src/Projects/Project/Details/index.tsx
Normal file
@ -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<TaskUser>;
|
||||||
|
};
|
||||||
|
|
||||||
|
const initialMemberPopupState = { taskID: '', isOpen: false, top: 0, left: 0 };
|
||||||
|
|
||||||
|
const Details: React.FC<DetailsProps> = ({
|
||||||
|
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 <div>loading</div>;
|
||||||
|
}
|
||||||
|
if (!data) {
|
||||||
|
return <div>loading</div>;
|
||||||
|
}
|
||||||
|
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 (
|
||||||
|
<>
|
||||||
|
<Modal
|
||||||
|
width={1040}
|
||||||
|
onClose={() => {
|
||||||
|
history.push(projectURL);
|
||||||
|
}}
|
||||||
|
renderContent={() => {
|
||||||
|
return (
|
||||||
|
<TaskDetails
|
||||||
|
task={{
|
||||||
|
...data.findTask,
|
||||||
|
members: taskMembers,
|
||||||
|
description: data.findTask.description ?? '',
|
||||||
|
labels: [],
|
||||||
|
}}
|
||||||
|
onTaskNameChange={onTaskNameChange}
|
||||||
|
onTaskDescriptionChange={onTaskDescriptionChange}
|
||||||
|
onDeleteTask={onDeleteTask}
|
||||||
|
onCloseModal={() => 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 && (
|
||||||
|
<PopupMenu
|
||||||
|
title="Members"
|
||||||
|
top={memberPopupData.top}
|
||||||
|
onClose={() => setMemberPopupData(initialMemberPopupState)}
|
||||||
|
left={memberPopupData.left}
|
||||||
|
>
|
||||||
|
<MemberManager
|
||||||
|
availableMembers={availableMembers}
|
||||||
|
activeMembers={[]}
|
||||||
|
onMemberChange={(member, isActive) => {
|
||||||
|
if (isActive) {
|
||||||
|
assignTask({ variables: { taskID: data.findTask.taskID, userID: userID ?? '' } });
|
||||||
|
}
|
||||||
|
console.log(member, isActive);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</PopupMenu>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Details;
|
@ -11,18 +11,17 @@ import {
|
|||||||
useUpdateTaskGroupLocationMutation,
|
useUpdateTaskGroupLocationMutation,
|
||||||
useCreateTaskGroupMutation,
|
useCreateTaskGroupMutation,
|
||||||
useDeleteTaskGroupMutation,
|
useDeleteTaskGroupMutation,
|
||||||
|
useUpdateTaskDescriptionMutation,
|
||||||
|
useAssignTaskMutation,
|
||||||
} from 'shared/generated/graphql';
|
} from 'shared/generated/graphql';
|
||||||
|
|
||||||
import Navbar from 'App/Navbar';
|
|
||||||
import TopNavbar from 'App/TopNavbar';
|
|
||||||
import QuickCardEditor from 'shared/components/QuickCardEditor';
|
import QuickCardEditor from 'shared/components/QuickCardEditor';
|
||||||
import PopupMenu from 'shared/components/PopupMenu';
|
import PopupMenu from 'shared/components/PopupMenu';
|
||||||
import ListActions from 'shared/components/ListActions';
|
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 MemberManager from 'shared/components/MemberManager';
|
||||||
import { LabelsPopup } from 'shared/components/PopupMenu/PopupMenu.stories';
|
import { LabelsPopup } from 'shared/components/PopupMenu/PopupMenu.stories';
|
||||||
import KanbanBoard from 'Projects/Project/KanbanBoard';
|
import KanbanBoard from 'Projects/Project/KanbanBoard';
|
||||||
|
import Details from './Details';
|
||||||
|
|
||||||
type TaskRouteProps = {
|
type TaskRouteProps = {
|
||||||
taskID: string;
|
taskID: string;
|
||||||
@ -35,17 +34,6 @@ interface QuickCardEditorState {
|
|||||||
task?: Task;
|
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`
|
const TitleWrapper = styled.div`
|
||||||
margin-left: 38px;
|
margin-left: 38px;
|
||||||
margin-bottom: 15px;
|
margin-bottom: 15px;
|
||||||
@ -64,7 +52,6 @@ interface ProjectParams {
|
|||||||
const initialState: BoardState = { tasks: {}, columns: {} };
|
const initialState: BoardState = { tasks: {}, columns: {} };
|
||||||
const initialPopupState = { left: 0, top: 0, isOpen: false, taskGroupID: '' };
|
const initialPopupState = { left: 0, top: 0, isOpen: false, taskGroupID: '' };
|
||||||
const initialQuickCardEditorState: QuickCardEditorState = { isOpen: false, top: 0, left: 0 };
|
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 initialLabelsPopupState = { taskID: '', isOpen: false, top: 0, left: 0 };
|
||||||
const initialTaskDetailsState = { isOpen: false, taskID: '' };
|
const initialTaskDetailsState = { isOpen: false, taskID: '' };
|
||||||
|
|
||||||
@ -73,9 +60,9 @@ const Project = () => {
|
|||||||
const match = useRouteMatch();
|
const match = useRouteMatch();
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
|
|
||||||
|
const [updateTaskDescription] = useUpdateTaskDescriptionMutation();
|
||||||
const [listsData, setListsData] = useState(initialState);
|
const [listsData, setListsData] = useState(initialState);
|
||||||
const [popupData, setPopupData] = useState(initialPopupState);
|
const [popupData, setPopupData] = useState(initialPopupState);
|
||||||
const [memberPopupData, setMemberPopupData] = useState(initialMemberPopupState);
|
|
||||||
const [taskDetails, setTaskDetails] = useState(initialTaskDetailsState);
|
const [taskDetails, setTaskDetails] = useState(initialTaskDetailsState);
|
||||||
const [quickCardEditor, setQuickCardEditor] = useState(initialQuickCardEditorState);
|
const [quickCardEditor, setQuickCardEditor] = useState(initialQuickCardEditorState);
|
||||||
const [updateTaskLocation] = useUpdateTaskLocationMutation();
|
const [updateTaskLocation] = useUpdateTaskLocationMutation();
|
||||||
@ -142,6 +129,7 @@ const Project = () => {
|
|||||||
name: task.name,
|
name: task.name,
|
||||||
position: task.position,
|
position: task.position,
|
||||||
labels: [],
|
labels: [],
|
||||||
|
description: task.description ?? undefined,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -199,17 +187,24 @@ const Project = () => {
|
|||||||
createTaskGroup({ variables: { projectID: projectId, name: listName, position } });
|
createTaskGroup({ variables: { projectID: projectId, name: listName, position } });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const [assignTask] = useAssignTaskMutation();
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return <Wrapper>Loading</Wrapper>;
|
return <Title>Error Loading</Title>;
|
||||||
}
|
}
|
||||||
if (data) {
|
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 (
|
return (
|
||||||
<>
|
<>
|
||||||
<Navbar />
|
|
||||||
<MainContent>
|
|
||||||
<TopNavbar />
|
|
||||||
<TitleWrapper>
|
<TitleWrapper>
|
||||||
<Title>{data.findProject.name}</Title>
|
<Title>{data.findProject.name}</Title>
|
||||||
|
</TitleWrapper>
|
||||||
<KanbanBoard
|
<KanbanBoard
|
||||||
listsData={listsData}
|
listsData={listsData}
|
||||||
onCardDrop={onCardDrop}
|
onCardDrop={onCardDrop}
|
||||||
@ -221,8 +216,6 @@ const Project = () => {
|
|||||||
setPopupData({ isOpen, top, left, taskGroupID });
|
setPopupData({ isOpen, top, left, taskGroupID });
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</TitleWrapper>
|
|
||||||
</MainContent>
|
|
||||||
{popupData.isOpen && (
|
{popupData.isOpen && (
|
||||||
<PopupMenu
|
<PopupMenu
|
||||||
title="List Actions"
|
title="List Actions"
|
||||||
@ -259,50 +252,28 @@ const Project = () => {
|
|||||||
<Route
|
<Route
|
||||||
path={`${match.path}/c/:taskID`}
|
path={`${match.path}/c/:taskID`}
|
||||||
render={(routeProps: RouteComponentProps<TaskRouteProps>) => (
|
render={(routeProps: RouteComponentProps<TaskRouteProps>) => (
|
||||||
<Modal
|
<Details
|
||||||
width={1040}
|
availableMembers={availableMembers}
|
||||||
onClose={() => {
|
projectURL={match.url}
|
||||||
history.push(match.url);
|
taskID={routeProps.match.params.taskID}
|
||||||
}}
|
|
||||||
renderContent={() => {
|
|
||||||
const task = listsData.tasks[routeProps.match.params.taskID];
|
|
||||||
if (!task) {
|
|
||||||
return <div>loading</div>;
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<TaskDetails
|
|
||||||
task={task}
|
|
||||||
onTaskNameChange={(updatedTask, newName) => {
|
onTaskNameChange={(updatedTask, newName) => {
|
||||||
updateTaskName({ variables: { taskID: updatedTask.taskID, name: newName } });
|
updateTaskName({ variables: { taskID: updatedTask.taskID, name: newName } });
|
||||||
}}
|
}}
|
||||||
onTaskDescriptionChange={(updatedTask, newDescription) => {
|
onTaskDescriptionChange={(updatedTask, newDescription) => {
|
||||||
console.log(updatedTask, newDescription);
|
updateTaskDescription({ variables: { taskID: updatedTask.taskID, description: newDescription } });
|
||||||
}}
|
}}
|
||||||
onDeleteTask={deletedTask => {
|
onDeleteTask={deletedTask => {
|
||||||
setTaskDetails(initialTaskDetailsState);
|
setTaskDetails(initialTaskDetailsState);
|
||||||
deleteTask({ variables: { taskID: deletedTask.taskID } });
|
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) => {}}
|
onOpenAddLabelPopup={(task, bounds) => {}}
|
||||||
/>
|
/>
|
||||||
);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return <Wrapper>Error</Wrapper>;
|
return <div>Error</div>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Project;
|
export default Project;
|
||||||
|
@ -2,7 +2,6 @@ import React, { useState } from 'react';
|
|||||||
import styled from 'styled-components/macro';
|
import styled from 'styled-components/macro';
|
||||||
import { useGetProjectsQuery } from 'shared/generated/graphql';
|
import { useGetProjectsQuery } from 'shared/generated/graphql';
|
||||||
|
|
||||||
import TopNavbar from 'App/TopNavbar';
|
|
||||||
import ProjectGridItem from 'shared/components/ProjectGridItem';
|
import ProjectGridItem from 'shared/components/ProjectGridItem';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
import Navbar from 'App/Navbar';
|
import Navbar from 'App/Navbar';
|
||||||
@ -15,59 +14,42 @@ const MainContent = styled.div`
|
|||||||
|
|
||||||
const ProjectGrid = styled.div`
|
const ProjectGrid = styled.div`
|
||||||
width: 60%;
|
width: 60%;
|
||||||
|
max-width: 780px;
|
||||||
margin: 25px auto;
|
margin: 25px auto;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
`;
|
`;
|
||||||
const Wrapper = styled.div`
|
|
||||||
font-size: 16px;
|
const ProjectLink = styled(Link)`
|
||||||
background-color: red;
|
flex: 1 0 33%;
|
||||||
|
margin-bottom: 20px;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const Projects = () => {
|
const Projects = () => {
|
||||||
const { loading, data } = useGetProjectsQuery();
|
const { loading, data } = useGetProjectsQuery();
|
||||||
console.log(loading, data);
|
console.log(loading, data);
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Navbar />
|
<span>loading</span>
|
||||||
<MainContent>
|
|
||||||
<TopNavbar />
|
|
||||||
</MainContent>
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (data) {
|
if (data) {
|
||||||
const { teams } = data.organizations[0];
|
const { projects } = data;
|
||||||
const projects: Project[] = [];
|
|
||||||
teams.forEach(team =>
|
|
||||||
team.projects.forEach(project => {
|
|
||||||
projects.push({
|
|
||||||
taskGroups: [],
|
|
||||||
projectID: project.projectID,
|
|
||||||
teamTitle: team.name,
|
|
||||||
name: project.name,
|
|
||||||
color: '#aa62e3',
|
|
||||||
});
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
return (
|
return (
|
||||||
<>
|
|
||||||
<Navbar />
|
|
||||||
<MainContent>
|
|
||||||
<TopNavbar />
|
|
||||||
<ProjectGrid>
|
<ProjectGrid>
|
||||||
{projects.map(project => (
|
{projects.map(project => (
|
||||||
<Link to={`/projects/${project.projectID}`}>
|
<ProjectLink key={project.projectID} to={`/projects/${project.projectID}`}>
|
||||||
<ProjectGridItem project={project} />
|
<ProjectGridItem project={{ ...project, teamTitle: project.team.name, taskGroups: [] }} />
|
||||||
</Link>
|
</ProjectLink>
|
||||||
))}
|
))}
|
||||||
</ProjectGrid>
|
</ProjectGrid>
|
||||||
</MainContent>
|
|
||||||
</>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return <Wrapper>Error</Wrapper>;
|
return <div>Error!</div>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Projects;
|
export default Projects;
|
||||||
|
11
web/src/citadel.d.ts
vendored
11
web/src/citadel.d.ts
vendored
@ -1,3 +1,8 @@
|
|||||||
|
interface JWTToken {
|
||||||
|
userId: string;
|
||||||
|
iat: string;
|
||||||
|
exp: string;
|
||||||
|
}
|
||||||
interface ColumnState {
|
interface ColumnState {
|
||||||
[key: string]: TaskGroup;
|
[key: string]: TaskGroup;
|
||||||
}
|
}
|
||||||
@ -29,9 +34,15 @@ type InnerTaskGroup = {
|
|||||||
position?: number;
|
position?: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type ProfileIcon = {
|
||||||
|
url: string | null;
|
||||||
|
initials: string | null;
|
||||||
|
};
|
||||||
|
|
||||||
type TaskUser = {
|
type TaskUser = {
|
||||||
userID: string;
|
userID: string;
|
||||||
displayName: string;
|
displayName: string;
|
||||||
|
profileIcon: ProfileIcon;
|
||||||
};
|
};
|
||||||
|
|
||||||
type Task = {
|
type Task = {
|
||||||
|
@ -2,6 +2,7 @@ import React, { createRef, useState } from 'react';
|
|||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
|
|
||||||
import DropdownMenu from '.';
|
import DropdownMenu from '.';
|
||||||
|
import { action } from '@storybook/addon-actions';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
component: DropdownMenu,
|
component: DropdownMenu,
|
||||||
@ -49,7 +50,7 @@ export const Default = () => {
|
|||||||
Click me
|
Click me
|
||||||
</Button>
|
</Button>
|
||||||
</Container>
|
</Container>
|
||||||
{menu.isOpen && <DropdownMenu left={menu.left} top={menu.top} />}
|
{menu.isOpen && <DropdownMenu onLogout={action('on logout')} left={menu.left} top={menu.top} />}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -6,9 +6,10 @@ import { Separator, Container, WrapperDiamond, Wrapper, ActionsList, ActionItem,
|
|||||||
type DropdownMenuProps = {
|
type DropdownMenuProps = {
|
||||||
left: number;
|
left: number;
|
||||||
top: number;
|
top: number;
|
||||||
|
onLogout: () => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
const DropdownMenu: React.FC<DropdownMenuProps> = ({ left, top }) => {
|
const DropdownMenu: React.FC<DropdownMenuProps> = ({ left, top, onLogout }) => {
|
||||||
return (
|
return (
|
||||||
<Container left={left} top={top}>
|
<Container left={left} top={top}>
|
||||||
<Wrapper>
|
<Wrapper>
|
||||||
@ -18,7 +19,7 @@ const DropdownMenu: React.FC<DropdownMenuProps> = ({ left, top }) => {
|
|||||||
</ActionItem>
|
</ActionItem>
|
||||||
<Separator />
|
<Separator />
|
||||||
<ActionsList>
|
<ActionsList>
|
||||||
<ActionItem>
|
<ActionItem onClick={onLogout}>
|
||||||
<Exit size={16} color="#c2c6dc" />
|
<Exit size={16} color="#c2c6dc" />
|
||||||
<ActionTitle>Logout</ActionTitle>
|
<ActionTitle>Logout</ActionTitle>
|
||||||
</ActionItem>
|
</ActionItem>
|
||||||
|
@ -23,7 +23,7 @@ export const Default = () => {
|
|||||||
position: 1,
|
position: 1,
|
||||||
labels: [{ labelId: 'soft-skills', color: '#fff', active: true, name: 'Soft Skills' }],
|
labels: [{ labelId: 'soft-skills', color: '#fff', active: true, name: 'Soft Skills' }],
|
||||||
description: 'hello!',
|
description: 'hello!',
|
||||||
members: [{ userID: '1', displayName: 'Jordan Knott' }],
|
members: [{ userID: '1', profileIcon: { url: null, initials: null }, displayName: 'Jordan Knott' }],
|
||||||
}}
|
}}
|
||||||
onCancel={action('cancel')}
|
onCancel={action('cancel')}
|
||||||
onDueDateChange={action('due date change')}
|
onDueDateChange={action('due date change')}
|
||||||
|
@ -55,7 +55,7 @@ const Login = ({ onSubmit }: LoginProps) => {
|
|||||||
<FormLabel htmlFor="password">
|
<FormLabel htmlFor="password">
|
||||||
Password
|
Password
|
||||||
<FormTextInput
|
<FormTextInput
|
||||||
type="text"
|
type="password"
|
||||||
id="password"
|
id="password"
|
||||||
name="password"
|
name="password"
|
||||||
ref={register({ required: 'Password is required' })}
|
ref={register({ required: 'Password is required' })}
|
||||||
|
@ -114,19 +114,15 @@ export const MemberManagerPopup = () => {
|
|||||||
{popupData.isOpen && (
|
{popupData.isOpen && (
|
||||||
<PopupMenu title="Members" top={popupData.top} onClose={() => setPopupData(initalState)} left={popupData.left}>
|
<PopupMenu title="Members" top={popupData.top} onClose={() => setPopupData(initalState)} left={popupData.left}>
|
||||||
<MemberManager
|
<MemberManager
|
||||||
availableMembers={[{ userID: '1', displayName: 'Jordan Knott' }]}
|
availableMembers={[
|
||||||
|
{ userID: '1', displayName: 'Jordan Knott', profileIcon: { url: null, initials: null } },
|
||||||
|
]}
|
||||||
activeMembers={[]}
|
activeMembers={[]}
|
||||||
onMemberChange={action('member change')}
|
onMemberChange={action('member change')}
|
||||||
/>
|
/>
|
||||||
</PopupMenu>
|
</PopupMenu>
|
||||||
)}
|
)}
|
||||||
<span
|
<span
|
||||||
style={{
|
|
||||||
width: '60px',
|
|
||||||
textAlign: 'center',
|
|
||||||
margin: '25px auto',
|
|
||||||
cursor: 'pointer',
|
|
||||||
}}
|
|
||||||
ref={$buttonRef}
|
ref={$buttonRef}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if ($buttonRef && $buttonRef.current) {
|
if ($buttonRef && $buttonRef.current) {
|
||||||
@ -162,7 +158,7 @@ export const DueDateManagerPopup = () => {
|
|||||||
position: 1,
|
position: 1,
|
||||||
labels: [{ labelId: 'soft-skills', color: '#fff', active: true, name: 'Soft Skills' }],
|
labels: [{ labelId: 'soft-skills', color: '#fff', active: true, name: 'Soft Skills' }],
|
||||||
description: 'hello!',
|
description: 'hello!',
|
||||||
members: [{ userID: '1', displayName: 'Jordan Knott' }],
|
members: [{ userID: '1', profileIcon: { url: null, initials: null }, displayName: 'Jordan Knott' }],
|
||||||
}}
|
}}
|
||||||
onCancel={action('cancel')}
|
onCancel={action('cancel')}
|
||||||
onDueDateChange={action('due date change')}
|
onDueDateChange={action('due date change')}
|
||||||
|
@ -4,27 +4,22 @@ import { mixin } from 'shared/utils/styles';
|
|||||||
export const ProjectContent = styled.div`
|
export const ProjectContent = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const ProjectTitle = styled.span`
|
export const ProjectTitle = styled.span`
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
transition: transform 0.25s ease;
|
transition: transform 0.25s ease;
|
||||||
text-align: center;
|
|
||||||
`;
|
`;
|
||||||
export const TeamTitle = styled.span`
|
export const TeamTitle = styled.span`
|
||||||
margin-top: 5px;
|
margin-top: 5px;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
text-align: center;
|
|
||||||
color: #c2c6dc;
|
color: #c2c6dc;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const ProjectWrapper = styled.div<{ color: string }>`
|
export const ProjectWrapper = styled.div<{ color: string }>`
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
|
||||||
padding: 15px 25px;
|
padding: 15px 25px;
|
||||||
border-radius: 20px;
|
border-radius: 20px;
|
||||||
${mixin.boxShadowCard}
|
${mixin.boxShadowCard}
|
||||||
@ -32,11 +27,10 @@ export const ProjectWrapper = styled.div<{ color: string }>`
|
|||||||
color: #fff;
|
color: #fff;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
margin: 0 10px;
|
margin: 0 10px;
|
||||||
width: 120px;
|
width: 240px;
|
||||||
height: 120px;
|
height: 100px;
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
transition: transform 0.25s ease;
|
transition: transform 0.25s ease;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
transform: translateY(-5px);
|
transform: translateY(-5px);
|
||||||
|
@ -35,7 +35,7 @@ export const Default = () => {
|
|||||||
position: 1,
|
position: 1,
|
||||||
labels: [{ labelId: 'soft-skills', color: '#fff', active: true, name: 'Soft Skills' }],
|
labels: [{ labelId: 'soft-skills', color: '#fff', active: true, name: 'Soft Skills' }],
|
||||||
description,
|
description,
|
||||||
members: [{ userID: '1', displayName: 'Jordan Knott' }],
|
members: [{ userID: '1', profileIcon: { url: null, initials: null }, displayName: 'Jordan Knott' }],
|
||||||
}}
|
}}
|
||||||
onTaskNameChange={action('task name change')}
|
onTaskNameChange={action('task name change')}
|
||||||
onTaskDescriptionChange={(_task, desc) => setDescription(desc)}
|
onTaskDescriptionChange={(_task, desc) => setDescription(desc)}
|
||||||
|
@ -97,9 +97,9 @@ type TaskDetailsProps = {
|
|||||||
onTaskNameChange: (task: Task, newName: string) => void;
|
onTaskNameChange: (task: Task, newName: string) => void;
|
||||||
onTaskDescriptionChange: (task: Task, newDescription: string) => void;
|
onTaskDescriptionChange: (task: Task, newDescription: string) => void;
|
||||||
onDeleteTask: (task: Task) => void;
|
onDeleteTask: (task: Task) => void;
|
||||||
onCloseModal: () => void;
|
|
||||||
onOpenAddMemberPopup: (task: Task, bounds: ElementBounds) => void;
|
onOpenAddMemberPopup: (task: Task, bounds: ElementBounds) => void;
|
||||||
onOpenAddLabelPopup: (task: Task, bounds: ElementBounds) => void;
|
onOpenAddLabelPopup: (task: Task, bounds: ElementBounds) => void;
|
||||||
|
onCloseModal: () => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
const TaskDetails: React.FC<TaskDetailsProps> = ({
|
const TaskDetails: React.FC<TaskDetailsProps> = ({
|
||||||
@ -112,6 +112,7 @@ const TaskDetails: React.FC<TaskDetailsProps> = ({
|
|||||||
onOpenAddLabelPopup,
|
onOpenAddLabelPopup,
|
||||||
}) => {
|
}) => {
|
||||||
const [editorOpen, setEditorOpen] = useState(false);
|
const [editorOpen, setEditorOpen] = useState(false);
|
||||||
|
const [description, setDescription] = useState(task.description ?? '');
|
||||||
const [taskName, setTaskName] = useState(task.name);
|
const [taskName, setTaskName] = useState(task.name);
|
||||||
const handleClick = () => {
|
const handleClick = () => {
|
||||||
setEditorOpen(!editorOpen);
|
setEditorOpen(!editorOpen);
|
||||||
@ -141,6 +142,7 @@ const TaskDetails: React.FC<TaskDetailsProps> = ({
|
|||||||
onOpenAddLabelPopup(task, bounds);
|
onOpenAddLabelPopup(task, bounds);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
console.log(task);
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<TaskActions>
|
<TaskActions>
|
||||||
@ -172,9 +174,10 @@ const TaskDetails: React.FC<TaskDetailsProps> = ({
|
|||||||
<TaskDetailsLabel>Description</TaskDetailsLabel>
|
<TaskDetailsLabel>Description</TaskDetailsLabel>
|
||||||
{editorOpen ? (
|
{editorOpen ? (
|
||||||
<DetailsEditor
|
<DetailsEditor
|
||||||
description={task.description ?? ''}
|
description={description}
|
||||||
onTaskDescriptionChange={newDescription => {
|
onTaskDescriptionChange={newDescription => {
|
||||||
setEditorOpen(false);
|
setEditorOpen(false);
|
||||||
|
setDescription(newDescription);
|
||||||
onTaskDescriptionChange(task, newDescription);
|
onTaskDescriptionChange(task, newDescription);
|
||||||
}}
|
}}
|
||||||
onCancel={() => {
|
onCancel={() => {
|
||||||
@ -182,7 +185,7 @@ const TaskDetails: React.FC<TaskDetailsProps> = ({
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<TaskContent description={task.description ?? ''} onEditContent={handleClick} />
|
<TaskContent description={description} onEditContent={handleClick} />
|
||||||
)}
|
)}
|
||||||
</TaskDetailsContent>
|
</TaskDetailsContent>
|
||||||
<TaskDetailsSidebar>
|
<TaskDetailsSidebar>
|
||||||
@ -190,10 +193,10 @@ const TaskDetails: React.FC<TaskDetailsProps> = ({
|
|||||||
<TaskDetailAssignees>
|
<TaskDetailAssignees>
|
||||||
{task.members &&
|
{task.members &&
|
||||||
task.members.map(member => {
|
task.members.map(member => {
|
||||||
const initials = 'JK';
|
console.log(member);
|
||||||
return (
|
return (
|
||||||
<TaskDetailAssignee key={member.userID}>
|
<TaskDetailAssignee key={member.userID}>
|
||||||
<ProfileIcon>{initials}</ProfileIcon>
|
<ProfileIcon>{member.profileIcon.initials ?? ''}</ProfileIcon>
|
||||||
</TaskDetailAssignee>
|
</TaskDetailAssignee>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
|
@ -37,8 +37,14 @@ export const Default = () => {
|
|||||||
<>
|
<>
|
||||||
<NormalizeStyles />
|
<NormalizeStyles />
|
||||||
<BaseStyles />
|
<BaseStyles />
|
||||||
<TopNavbar onNotificationClick={action('notifications click')} onProfileClick={onClick} />
|
<TopNavbar
|
||||||
{menu.isOpen && <DropdownMenu left={menu.left} top={menu.top} />}
|
firstName="Jordan"
|
||||||
|
lastName="Knott"
|
||||||
|
initials="JK"
|
||||||
|
onNotificationClick={action('notifications click')}
|
||||||
|
onProfileClick={onClick}
|
||||||
|
/>
|
||||||
|
{menu.isOpen && <DropdownMenu onLogout={action('on logout')} left={menu.left} top={menu.top} />}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -19,8 +19,11 @@ import {
|
|||||||
type NavBarProps = {
|
type NavBarProps = {
|
||||||
onProfileClick: (bottom: number, right: number) => void;
|
onProfileClick: (bottom: number, right: number) => void;
|
||||||
onNotificationClick: () => void;
|
onNotificationClick: () => void;
|
||||||
|
firstName: string;
|
||||||
|
lastName: string;
|
||||||
|
initials: string;
|
||||||
};
|
};
|
||||||
const NavBar: React.FC<NavBarProps> = ({ onProfileClick, onNotificationClick }) => {
|
const NavBar: React.FC<NavBarProps> = ({ onProfileClick, onNotificationClick, firstName, lastName, initials }) => {
|
||||||
const $profileRef: any = useRef(null);
|
const $profileRef: any = useRef(null);
|
||||||
const handleProfileClick = () => {
|
const handleProfileClick = () => {
|
||||||
console.log('click');
|
console.log('click');
|
||||||
@ -45,11 +48,13 @@ const NavBar: React.FC<NavBarProps> = ({ onProfileClick, onNotificationClick })
|
|||||||
</NotificationContainer>
|
</NotificationContainer>
|
||||||
<ProfileContainer>
|
<ProfileContainer>
|
||||||
<ProfileNameWrapper>
|
<ProfileNameWrapper>
|
||||||
<ProfileNamePrimary>Jordan Knott</ProfileNamePrimary>
|
<ProfileNamePrimary>
|
||||||
|
{firstName} {lastName}
|
||||||
|
</ProfileNamePrimary>
|
||||||
<ProfileNameSecondary>Manager</ProfileNameSecondary>
|
<ProfileNameSecondary>Manager</ProfileNameSecondary>
|
||||||
</ProfileNameWrapper>
|
</ProfileNameWrapper>
|
||||||
<ProfileIcon ref={$profileRef} onClick={handleProfileClick}>
|
<ProfileIcon ref={$profileRef} onClick={handleProfileClick}>
|
||||||
JK
|
{initials}
|
||||||
</ProfileIcon>
|
</ProfileIcon>
|
||||||
</ProfileContainer>
|
</ProfileContainer>
|
||||||
</GlobalActions>
|
</GlobalActions>
|
||||||
|
@ -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<Scalars['String']>;
|
||||||
|
initials?: Maybe<Scalars['String']>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ProjectMember = {
|
||||||
|
__typename?: 'ProjectMember';
|
||||||
|
userID: Scalars['ID'];
|
||||||
|
firstName: Scalars['String'];
|
||||||
|
lastName: Scalars['String'];
|
||||||
|
profileIcon: ProfileIcon;
|
||||||
|
};
|
||||||
|
|
||||||
export type RefreshToken = {
|
export type RefreshToken = {
|
||||||
__typename?: 'RefreshToken';
|
__typename?: 'RefreshToken';
|
||||||
tokenId: Scalars['ID'];
|
tokenId: Scalars['ID'];
|
||||||
@ -28,16 +49,10 @@ export type UserAccount = {
|
|||||||
userID: Scalars['ID'];
|
userID: Scalars['ID'];
|
||||||
email: Scalars['String'];
|
email: Scalars['String'];
|
||||||
createdAt: Scalars['Time'];
|
createdAt: Scalars['Time'];
|
||||||
displayName: Scalars['String'];
|
firstName: Scalars['String'];
|
||||||
|
lastName: Scalars['String'];
|
||||||
username: Scalars['String'];
|
username: Scalars['String'];
|
||||||
};
|
profileIcon: ProfileIcon;
|
||||||
|
|
||||||
export type Organization = {
|
|
||||||
__typename?: 'Organization';
|
|
||||||
organizationID: Scalars['ID'];
|
|
||||||
createdAt: Scalars['Time'];
|
|
||||||
name: Scalars['String'];
|
|
||||||
teams: Array<Team>;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export type Team = {
|
export type Team = {
|
||||||
@ -45,16 +60,17 @@ export type Team = {
|
|||||||
teamID: Scalars['ID'];
|
teamID: Scalars['ID'];
|
||||||
createdAt: Scalars['Time'];
|
createdAt: Scalars['Time'];
|
||||||
name: Scalars['String'];
|
name: Scalars['String'];
|
||||||
projects: Array<Project>;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export type Project = {
|
export type Project = {
|
||||||
__typename?: 'Project';
|
__typename?: 'Project';
|
||||||
projectID: Scalars['ID'];
|
projectID: Scalars['ID'];
|
||||||
teamID: Scalars['String'];
|
|
||||||
createdAt: Scalars['Time'];
|
createdAt: Scalars['Time'];
|
||||||
name: Scalars['String'];
|
name: Scalars['String'];
|
||||||
|
team: Team;
|
||||||
|
owner: ProjectMember;
|
||||||
taskGroups: Array<TaskGroup>;
|
taskGroups: Array<TaskGroup>;
|
||||||
|
members: Array<ProjectMember>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TaskGroup = {
|
export type TaskGroup = {
|
||||||
@ -74,6 +90,9 @@ export type Task = {
|
|||||||
createdAt: Scalars['Time'];
|
createdAt: Scalars['Time'];
|
||||||
name: Scalars['String'];
|
name: Scalars['String'];
|
||||||
position: Scalars['Float'];
|
position: Scalars['Float'];
|
||||||
|
description?: Maybe<Scalars['String']>;
|
||||||
|
assigned: Array<ProjectMember>;
|
||||||
|
labels: Array<TaskLabel>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type ProjectsFilter = {
|
export type ProjectsFilter = {
|
||||||
@ -88,15 +107,19 @@ export type FindProject = {
|
|||||||
projectId: Scalars['String'];
|
projectId: Scalars['String'];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type FindTask = {
|
||||||
|
taskID: Scalars['UUID'];
|
||||||
|
};
|
||||||
|
|
||||||
export type Query = {
|
export type Query = {
|
||||||
__typename?: 'Query';
|
__typename?: 'Query';
|
||||||
organizations: Array<Organization>;
|
|
||||||
users: Array<UserAccount>;
|
users: Array<UserAccount>;
|
||||||
findUser: UserAccount;
|
findUser: UserAccount;
|
||||||
findProject: Project;
|
findProject: Project;
|
||||||
teams: Array<Team>;
|
findTask: Task;
|
||||||
projects: Array<Project>;
|
projects: Array<Project>;
|
||||||
taskGroups: Array<TaskGroup>;
|
taskGroups: Array<TaskGroup>;
|
||||||
|
me: UserAccount;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -110,6 +133,11 @@ export type QueryFindProjectArgs = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export type QueryFindTaskArgs = {
|
||||||
|
input: FindTask;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
export type QueryProjectsArgs = {
|
export type QueryProjectsArgs = {
|
||||||
input?: Maybe<ProjectsFilter>;
|
input?: Maybe<ProjectsFilter>;
|
||||||
};
|
};
|
||||||
@ -121,7 +149,8 @@ export type NewRefreshToken = {
|
|||||||
export type NewUserAccount = {
|
export type NewUserAccount = {
|
||||||
username: Scalars['String'];
|
username: Scalars['String'];
|
||||||
email: Scalars['String'];
|
email: Scalars['String'];
|
||||||
displayName: Scalars['String'];
|
firstName: Scalars['String'];
|
||||||
|
lastName: Scalars['String'];
|
||||||
password: Scalars['String'];
|
password: Scalars['String'];
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -131,7 +160,8 @@ export type NewTeam = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export type NewProject = {
|
export type NewProject = {
|
||||||
teamID: Scalars['String'];
|
userID: Scalars['UUID'];
|
||||||
|
teamID: Scalars['UUID'];
|
||||||
name: Scalars['String'];
|
name: Scalars['String'];
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -141,10 +171,6 @@ export type NewTaskGroup = {
|
|||||||
position: Scalars['Float'];
|
position: Scalars['Float'];
|
||||||
};
|
};
|
||||||
|
|
||||||
export type NewOrganization = {
|
|
||||||
name: Scalars['String'];
|
|
||||||
};
|
|
||||||
|
|
||||||
export type LogoutUser = {
|
export type LogoutUser = {
|
||||||
userID: Scalars['String'];
|
userID: Scalars['String'];
|
||||||
};
|
};
|
||||||
@ -191,20 +217,43 @@ export type DeleteTaskGroupPayload = {
|
|||||||
taskGroup: TaskGroup;
|
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 = {
|
export type Mutation = {
|
||||||
__typename?: 'Mutation';
|
__typename?: 'Mutation';
|
||||||
createRefreshToken: RefreshToken;
|
createRefreshToken: RefreshToken;
|
||||||
createUserAccount: UserAccount;
|
createUserAccount: UserAccount;
|
||||||
createOrganization: Organization;
|
|
||||||
createTeam: Team;
|
createTeam: Team;
|
||||||
createProject: Project;
|
createProject: Project;
|
||||||
createTaskGroup: TaskGroup;
|
createTaskGroup: TaskGroup;
|
||||||
updateTaskGroupLocation: TaskGroup;
|
updateTaskGroupLocation: TaskGroup;
|
||||||
deleteTaskGroup: DeleteTaskGroupPayload;
|
deleteTaskGroup: DeleteTaskGroupPayload;
|
||||||
|
addTaskLabel: Task;
|
||||||
|
removeTaskLabel: Task;
|
||||||
createTask: Task;
|
createTask: Task;
|
||||||
|
updateTaskDescription: Task;
|
||||||
updateTaskLocation: Task;
|
updateTaskLocation: Task;
|
||||||
updateTaskName: Task;
|
updateTaskName: Task;
|
||||||
deleteTask: DeleteTaskPayload;
|
deleteTask: DeleteTaskPayload;
|
||||||
|
assignTask: Task;
|
||||||
logoutUser: Scalars['Boolean'];
|
logoutUser: Scalars['Boolean'];
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -219,11 +268,6 @@ export type MutationCreateUserAccountArgs = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
export type MutationCreateOrganizationArgs = {
|
|
||||||
input: NewOrganization;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
export type MutationCreateTeamArgs = {
|
export type MutationCreateTeamArgs = {
|
||||||
input: NewTeam;
|
input: NewTeam;
|
||||||
};
|
};
|
||||||
@ -249,11 +293,26 @@ export type MutationDeleteTaskGroupArgs = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export type MutationAddTaskLabelArgs = {
|
||||||
|
input?: Maybe<AddTaskLabelInput>;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export type MutationRemoveTaskLabelArgs = {
|
||||||
|
input?: Maybe<RemoveTaskLabelInput>;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
export type MutationCreateTaskArgs = {
|
export type MutationCreateTaskArgs = {
|
||||||
input: NewTask;
|
input: NewTask;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export type MutationUpdateTaskDescriptionArgs = {
|
||||||
|
input: UpdateTaskDescriptionInput;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
export type MutationUpdateTaskLocationArgs = {
|
export type MutationUpdateTaskLocationArgs = {
|
||||||
input: NewTaskLocation;
|
input: NewTaskLocation;
|
||||||
};
|
};
|
||||||
@ -269,10 +328,33 @@ export type MutationDeleteTaskArgs = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export type MutationAssignTaskArgs = {
|
||||||
|
input?: Maybe<AssignTaskInput>;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
export type MutationLogoutUserArgs = {
|
export type MutationLogoutUserArgs = {
|
||||||
input: LogoutUser;
|
input: LogoutUser;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type AssignTaskMutationVariables = {
|
||||||
|
taskID: Scalars['UUID'];
|
||||||
|
userID: Scalars['UUID'];
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export type AssignTaskMutation = (
|
||||||
|
{ __typename?: 'Mutation' }
|
||||||
|
& { assignTask: (
|
||||||
|
{ __typename?: 'Task' }
|
||||||
|
& Pick<Task, 'taskID'>
|
||||||
|
& { assigned: Array<(
|
||||||
|
{ __typename?: 'ProjectMember' }
|
||||||
|
& Pick<ProjectMember, 'userID' | 'firstName' | 'lastName'>
|
||||||
|
)> }
|
||||||
|
) }
|
||||||
|
);
|
||||||
|
|
||||||
export type CreateTaskMutationVariables = {
|
export type CreateTaskMutationVariables = {
|
||||||
taskGroupID: Scalars['String'];
|
taskGroupID: Scalars['String'];
|
||||||
name: Scalars['String'];
|
name: Scalars['String'];
|
||||||
@ -351,36 +433,92 @@ export type FindProjectQuery = (
|
|||||||
& { findProject: (
|
& { findProject: (
|
||||||
{ __typename?: 'Project' }
|
{ __typename?: 'Project' }
|
||||||
& Pick<Project, 'name'>
|
& Pick<Project, 'name'>
|
||||||
& { taskGroups: Array<(
|
& { members: Array<(
|
||||||
|
{ __typename?: 'ProjectMember' }
|
||||||
|
& Pick<ProjectMember, 'userID' | 'firstName' | 'lastName'>
|
||||||
|
& { profileIcon: (
|
||||||
|
{ __typename?: 'ProfileIcon' }
|
||||||
|
& Pick<ProfileIcon, 'url' | 'initials'>
|
||||||
|
) }
|
||||||
|
)>, taskGroups: Array<(
|
||||||
{ __typename?: 'TaskGroup' }
|
{ __typename?: 'TaskGroup' }
|
||||||
& Pick<TaskGroup, 'taskGroupID' | 'name' | 'position'>
|
& Pick<TaskGroup, 'taskGroupID' | 'name' | 'position'>
|
||||||
& { tasks: Array<(
|
& { tasks: Array<(
|
||||||
{ __typename?: 'Task' }
|
{ __typename?: 'Task' }
|
||||||
& Pick<Task, 'taskID' | 'name' | 'position'>
|
& Pick<Task, 'taskID' | 'name' | 'position' | 'description'>
|
||||||
)> }
|
)> }
|
||||||
)> }
|
)> }
|
||||||
) }
|
) }
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export type FindTaskQueryVariables = {
|
||||||
|
taskID: Scalars['UUID'];
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export type FindTaskQuery = (
|
||||||
|
{ __typename?: 'Query' }
|
||||||
|
& { findTask: (
|
||||||
|
{ __typename?: 'Task' }
|
||||||
|
& Pick<Task, 'taskID' | 'name' | 'description' | 'position'>
|
||||||
|
& { taskGroup: (
|
||||||
|
{ __typename?: 'TaskGroup' }
|
||||||
|
& Pick<TaskGroup, 'taskGroupID'>
|
||||||
|
), assigned: Array<(
|
||||||
|
{ __typename?: 'ProjectMember' }
|
||||||
|
& Pick<ProjectMember, 'userID' | 'firstName' | 'lastName'>
|
||||||
|
& { profileIcon: (
|
||||||
|
{ __typename?: 'ProfileIcon' }
|
||||||
|
& Pick<ProfileIcon, 'url' | 'initials'>
|
||||||
|
) }
|
||||||
|
)> }
|
||||||
|
) }
|
||||||
|
);
|
||||||
|
|
||||||
export type GetProjectsQueryVariables = {};
|
export type GetProjectsQueryVariables = {};
|
||||||
|
|
||||||
|
|
||||||
export type GetProjectsQuery = (
|
export type GetProjectsQuery = (
|
||||||
{ __typename?: 'Query' }
|
{ __typename?: 'Query' }
|
||||||
& { organizations: Array<(
|
|
||||||
{ __typename?: 'Organization' }
|
|
||||||
& Pick<Organization, 'name'>
|
|
||||||
& { teams: Array<(
|
|
||||||
{ __typename?: 'Team' }
|
|
||||||
& Pick<Team, 'name'>
|
|
||||||
& { projects: Array<(
|
& { projects: Array<(
|
||||||
{ __typename?: 'Project' }
|
{ __typename?: 'Project' }
|
||||||
& Pick<Project, 'name' | 'projectID'>
|
& Pick<Project, 'projectID' | 'name'>
|
||||||
)> }
|
& { team: (
|
||||||
)> }
|
{ __typename?: 'Team' }
|
||||||
|
& Pick<Team, 'teamID' | 'name'>
|
||||||
|
) }
|
||||||
)> }
|
)> }
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export type MeQueryVariables = {};
|
||||||
|
|
||||||
|
|
||||||
|
export type MeQuery = (
|
||||||
|
{ __typename?: 'Query' }
|
||||||
|
& { me: (
|
||||||
|
{ __typename?: 'UserAccount' }
|
||||||
|
& Pick<UserAccount, 'firstName' | 'lastName'>
|
||||||
|
& { profileIcon: (
|
||||||
|
{ __typename?: 'ProfileIcon' }
|
||||||
|
& Pick<ProfileIcon, 'initials'>
|
||||||
|
) }
|
||||||
|
) }
|
||||||
|
);
|
||||||
|
|
||||||
|
export type UpdateTaskDescriptionMutationVariables = {
|
||||||
|
taskID: Scalars['UUID'];
|
||||||
|
description: Scalars['String'];
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export type UpdateTaskDescriptionMutation = (
|
||||||
|
{ __typename?: 'Mutation' }
|
||||||
|
& { updateTaskDescription: (
|
||||||
|
{ __typename?: 'Task' }
|
||||||
|
& Pick<Task, 'taskID'>
|
||||||
|
) }
|
||||||
|
);
|
||||||
|
|
||||||
export type UpdateTaskGroupLocationMutationVariables = {
|
export type UpdateTaskGroupLocationMutationVariables = {
|
||||||
taskGroupID: Scalars['UUID'];
|
taskGroupID: Scalars['UUID'];
|
||||||
position: Scalars['Float'];
|
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<AssignTaskMutation, AssignTaskMutationVariables>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* __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<AssignTaskMutation, AssignTaskMutationVariables>) {
|
||||||
|
return ApolloReactHooks.useMutation<AssignTaskMutation, AssignTaskMutationVariables>(AssignTaskDocument, baseOptions);
|
||||||
|
}
|
||||||
|
export type AssignTaskMutationHookResult = ReturnType<typeof useAssignTaskMutation>;
|
||||||
|
export type AssignTaskMutationResult = ApolloReactCommon.MutationResult<AssignTaskMutation>;
|
||||||
|
export type AssignTaskMutationOptions = ApolloReactCommon.BaseMutationOptions<AssignTaskMutation, AssignTaskMutationVariables>;
|
||||||
export const CreateTaskDocument = gql`
|
export const CreateTaskDocument = gql`
|
||||||
mutation createTask($taskGroupID: String!, $name: String!, $position: Float!) {
|
mutation createTask($taskGroupID: String!, $name: String!, $position: Float!) {
|
||||||
createTask(input: {taskGroupID: $taskGroupID, name: $name, position: $position}) {
|
createTask(input: {taskGroupID: $taskGroupID, name: $name, position: $position}) {
|
||||||
@ -576,6 +752,15 @@ export const FindProjectDocument = gql`
|
|||||||
query findProject($projectId: String!) {
|
query findProject($projectId: String!) {
|
||||||
findProject(input: {projectId: $projectId}) {
|
findProject(input: {projectId: $projectId}) {
|
||||||
name
|
name
|
||||||
|
members {
|
||||||
|
userID
|
||||||
|
firstName
|
||||||
|
lastName
|
||||||
|
profileIcon {
|
||||||
|
url
|
||||||
|
initials
|
||||||
|
}
|
||||||
|
}
|
||||||
taskGroups {
|
taskGroups {
|
||||||
taskGroupID
|
taskGroupID
|
||||||
name
|
name
|
||||||
@ -584,6 +769,7 @@ export const FindProjectDocument = gql`
|
|||||||
taskID
|
taskID
|
||||||
name
|
name
|
||||||
position
|
position
|
||||||
|
description
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -615,16 +801,62 @@ export function useFindProjectLazyQuery(baseOptions?: ApolloReactHooks.LazyQuery
|
|||||||
export type FindProjectQueryHookResult = ReturnType<typeof useFindProjectQuery>;
|
export type FindProjectQueryHookResult = ReturnType<typeof useFindProjectQuery>;
|
||||||
export type FindProjectLazyQueryHookResult = ReturnType<typeof useFindProjectLazyQuery>;
|
export type FindProjectLazyQueryHookResult = ReturnType<typeof useFindProjectLazyQuery>;
|
||||||
export type FindProjectQueryResult = ApolloReactCommon.QueryResult<FindProjectQuery, FindProjectQueryVariables>;
|
export type FindProjectQueryResult = ApolloReactCommon.QueryResult<FindProjectQuery, FindProjectQueryVariables>;
|
||||||
|
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<FindTaskQuery, FindTaskQueryVariables>) {
|
||||||
|
return ApolloReactHooks.useQuery<FindTaskQuery, FindTaskQueryVariables>(FindTaskDocument, baseOptions);
|
||||||
|
}
|
||||||
|
export function useFindTaskLazyQuery(baseOptions?: ApolloReactHooks.LazyQueryHookOptions<FindTaskQuery, FindTaskQueryVariables>) {
|
||||||
|
return ApolloReactHooks.useLazyQuery<FindTaskQuery, FindTaskQueryVariables>(FindTaskDocument, baseOptions);
|
||||||
|
}
|
||||||
|
export type FindTaskQueryHookResult = ReturnType<typeof useFindTaskQuery>;
|
||||||
|
export type FindTaskLazyQueryHookResult = ReturnType<typeof useFindTaskLazyQuery>;
|
||||||
|
export type FindTaskQueryResult = ApolloReactCommon.QueryResult<FindTaskQuery, FindTaskQueryVariables>;
|
||||||
export const GetProjectsDocument = gql`
|
export const GetProjectsDocument = gql`
|
||||||
query getProjects {
|
query getProjects {
|
||||||
organizations {
|
|
||||||
name
|
|
||||||
teams {
|
|
||||||
name
|
|
||||||
projects {
|
projects {
|
||||||
name
|
|
||||||
projectID
|
projectID
|
||||||
}
|
name
|
||||||
|
team {
|
||||||
|
teamID
|
||||||
|
name
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -654,6 +886,75 @@ export function useGetProjectsLazyQuery(baseOptions?: ApolloReactHooks.LazyQuery
|
|||||||
export type GetProjectsQueryHookResult = ReturnType<typeof useGetProjectsQuery>;
|
export type GetProjectsQueryHookResult = ReturnType<typeof useGetProjectsQuery>;
|
||||||
export type GetProjectsLazyQueryHookResult = ReturnType<typeof useGetProjectsLazyQuery>;
|
export type GetProjectsLazyQueryHookResult = ReturnType<typeof useGetProjectsLazyQuery>;
|
||||||
export type GetProjectsQueryResult = ApolloReactCommon.QueryResult<GetProjectsQuery, GetProjectsQueryVariables>;
|
export type GetProjectsQueryResult = ApolloReactCommon.QueryResult<GetProjectsQuery, GetProjectsQueryVariables>;
|
||||||
|
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<MeQuery, MeQueryVariables>) {
|
||||||
|
return ApolloReactHooks.useQuery<MeQuery, MeQueryVariables>(MeDocument, baseOptions);
|
||||||
|
}
|
||||||
|
export function useMeLazyQuery(baseOptions?: ApolloReactHooks.LazyQueryHookOptions<MeQuery, MeQueryVariables>) {
|
||||||
|
return ApolloReactHooks.useLazyQuery<MeQuery, MeQueryVariables>(MeDocument, baseOptions);
|
||||||
|
}
|
||||||
|
export type MeQueryHookResult = ReturnType<typeof useMeQuery>;
|
||||||
|
export type MeLazyQueryHookResult = ReturnType<typeof useMeLazyQuery>;
|
||||||
|
export type MeQueryResult = ApolloReactCommon.QueryResult<MeQuery, MeQueryVariables>;
|
||||||
|
export const UpdateTaskDescriptionDocument = gql`
|
||||||
|
mutation updateTaskDescription($taskID: UUID!, $description: String!) {
|
||||||
|
updateTaskDescription(input: {taskID: $taskID, description: $description}) {
|
||||||
|
taskID
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
export type UpdateTaskDescriptionMutationFn = ApolloReactCommon.MutationFunction<UpdateTaskDescriptionMutation, UpdateTaskDescriptionMutationVariables>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* __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<UpdateTaskDescriptionMutation, UpdateTaskDescriptionMutationVariables>) {
|
||||||
|
return ApolloReactHooks.useMutation<UpdateTaskDescriptionMutation, UpdateTaskDescriptionMutationVariables>(UpdateTaskDescriptionDocument, baseOptions);
|
||||||
|
}
|
||||||
|
export type UpdateTaskDescriptionMutationHookResult = ReturnType<typeof useUpdateTaskDescriptionMutation>;
|
||||||
|
export type UpdateTaskDescriptionMutationResult = ApolloReactCommon.MutationResult<UpdateTaskDescriptionMutation>;
|
||||||
|
export type UpdateTaskDescriptionMutationOptions = ApolloReactCommon.BaseMutationOptions<UpdateTaskDescriptionMutation, UpdateTaskDescriptionMutationVariables>;
|
||||||
export const UpdateTaskGroupLocationDocument = gql`
|
export const UpdateTaskGroupLocationDocument = gql`
|
||||||
mutation updateTaskGroupLocation($taskGroupID: UUID!, $position: Float!) {
|
mutation updateTaskGroupLocation($taskGroupID: UUID!, $position: Float!) {
|
||||||
updateTaskGroupLocation(input: {taskGroupID: $taskGroupID, position: $position}) {
|
updateTaskGroupLocation(input: {taskGroupID: $taskGroupID, position: $position}) {
|
||||||
|
10
web/src/shared/graphql/assignTask.graphqls
Normal file
10
web/src/shared/graphql/assignTask.graphqls
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
mutation assignTask($taskID: UUID!, $userID: UUID!) {
|
||||||
|
assignTask(input: {taskID: $taskID, userID: $userID}) {
|
||||||
|
assigned {
|
||||||
|
userID
|
||||||
|
firstName
|
||||||
|
lastName
|
||||||
|
}
|
||||||
|
taskID
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,15 @@
|
|||||||
query findProject($projectId: String!) {
|
query findProject($projectId: String!) {
|
||||||
findProject(input: { projectId: $projectId }) {
|
findProject(input: { projectId: $projectId }) {
|
||||||
name
|
name
|
||||||
|
members {
|
||||||
|
userID
|
||||||
|
firstName
|
||||||
|
lastName
|
||||||
|
profileIcon {
|
||||||
|
url
|
||||||
|
initials
|
||||||
|
}
|
||||||
|
}
|
||||||
taskGroups {
|
taskGroups {
|
||||||
taskGroupID
|
taskGroupID
|
||||||
name
|
name
|
||||||
@ -9,6 +18,7 @@ query findProject($projectId: String!) {
|
|||||||
taskID
|
taskID
|
||||||
name
|
name
|
||||||
position
|
position
|
||||||
|
description
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
20
web/src/shared/graphql/findTask.graphqls
Normal file
20
web/src/shared/graphql/findTask.graphqls
Normal file
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,12 +1,10 @@
|
|||||||
query getProjects {
|
query getProjects {
|
||||||
organizations {
|
|
||||||
name
|
|
||||||
teams {
|
|
||||||
name
|
|
||||||
projects {
|
projects {
|
||||||
name
|
|
||||||
projectID
|
projectID
|
||||||
}
|
name
|
||||||
|
team {
|
||||||
|
teamID
|
||||||
|
name
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
9
web/src/shared/graphql/me.graphqls
Normal file
9
web/src/shared/graphql/me.graphqls
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
query me {
|
||||||
|
me {
|
||||||
|
firstName
|
||||||
|
lastName
|
||||||
|
profileIcon {
|
||||||
|
initials
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
5
web/src/shared/graphql/updateTaskDescription.graphqls
Normal file
5
web/src/shared/graphql/updateTaskDescription.graphqls
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
mutation updateTaskDescription($taskID: UUID!, $description: String!) {
|
||||||
|
updateTaskDescription(input: {taskID: $taskID, description: $description}) {
|
||||||
|
taskID
|
||||||
|
}
|
||||||
|
}
|
@ -3104,6 +3104,11 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.4.tgz#38fd73ddfd9b55abb1e1b2ed578cb55bd7b7d339"
|
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.4.tgz#38fd73ddfd9b55abb1e1b2ed578cb55bd7b7d339"
|
||||||
integrity sha512-8+KAKzEvSUdeo+kmqnKrqgeE+LcA0tjYWFY7RPProVYwnqDjukzO+3b6dLD56rYX5TdWejnEOLJYOIeh4CXKuA==
|
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":
|
"@types/lodash@^4.14.149":
|
||||||
version "4.14.149"
|
version "4.14.149"
|
||||||
resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.149.tgz#1342d63d948c6062838fbf961012f74d4e638440"
|
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"
|
jwa "^1.4.1"
|
||||||
safe-buffer "^5.0.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:
|
killable@^1.0.1:
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/killable/-/killable-1.0.1.tgz#4c8ce441187a061c7474fb87ca08e2a638194892"
|
resolved "https://registry.yarnpkg.com/killable/-/killable-1.0.1.tgz#4c8ce441187a061c7474fb87ca08e2a638194892"
|
||||||
|
Loading…
Reference in New Issue
Block a user