Compare commits
	
		
			1 Commits
		
	
	
		
			0.3.4
			...
			feat/updat
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					4a8d4a6ec3 | 
@@ -323,6 +323,7 @@ const ProjectBoard: React.FC<ProjectBoardProps> = ({ projectID, onCardLabelClick
 | 
			
		||||
  const [updateTaskGroupName] = useUpdateTaskGroupNameMutation({});
 | 
			
		||||
  const { loading, data } = useFindProjectQuery({
 | 
			
		||||
    variables: { projectID },
 | 
			
		||||
    pollInterval: 5000,
 | 
			
		||||
  });
 | 
			
		||||
  const [deleteTaskGroupTasks] = useDeleteTaskGroupTasksMutation({
 | 
			
		||||
    update: (client, resp) =>
 | 
			
		||||
 
 | 
			
		||||
@@ -3,7 +3,7 @@ import Modal from 'shared/components/Modal';
 | 
			
		||||
import TaskDetails from 'shared/components/TaskDetails';
 | 
			
		||||
import { Popup, usePopup } from 'shared/components/PopupMenu';
 | 
			
		||||
import MemberManager from 'shared/components/MemberManager';
 | 
			
		||||
import { useRouteMatch, useHistory } from 'react-router';
 | 
			
		||||
import { useRouteMatch, useHistory, Redirect } from 'react-router';
 | 
			
		||||
import {
 | 
			
		||||
  useDeleteTaskChecklistMutation,
 | 
			
		||||
  useUpdateTaskChecklistNameMutation,
 | 
			
		||||
@@ -32,6 +32,7 @@ import Input from 'shared/components/Input';
 | 
			
		||||
import { useForm } from 'react-hook-form';
 | 
			
		||||
import updateApolloCache from 'shared/utils/cache';
 | 
			
		||||
import NOOP from 'shared/utils/noop';
 | 
			
		||||
import hasNotFoundError from 'shared/utils/error';
 | 
			
		||||
 | 
			
		||||
const calculateChecklistBadge = (checklists: Array<TaskChecklist>) => {
 | 
			
		||||
  const total = checklists.reduce((prev: any, next: any) => {
 | 
			
		||||
@@ -269,8 +270,8 @@ const Details: React.FC<DetailsProps> = ({
 | 
			
		||||
      );
 | 
			
		||||
    },
 | 
			
		||||
  });
 | 
			
		||||
  const { loading, data, refetch } = useFindTaskQuery({ variables: { taskID } });
 | 
			
		||||
  const [setTaskComplete] = useSetTaskCompleteMutation();
 | 
			
		||||
  const { loading, data, refetch, error } = useFindTaskQuery({ variables: { taskID }, pollInterval: 5000 });
 | 
			
		||||
  const [setTaskComplete, { error: setTaskCompleteError }] = useSetTaskCompleteMutation();
 | 
			
		||||
  const [updateTaskDueDate] = useUpdateTaskDueDateMutation({
 | 
			
		||||
    onCompleted: () => {
 | 
			
		||||
      refetch();
 | 
			
		||||
@@ -289,9 +290,13 @@ const Details: React.FC<DetailsProps> = ({
 | 
			
		||||
      refreshCache();
 | 
			
		||||
    },
 | 
			
		||||
  });
 | 
			
		||||
  if (loading) {
 | 
			
		||||
    return null;
 | 
			
		||||
  if (hasNotFoundError(error, setTaskCompleteError)) {
 | 
			
		||||
    return <Redirect to={projectURL} />;
 | 
			
		||||
  }
 | 
			
		||||
  if (setTaskCompleteError && setTaskCompleteError)
 | 
			
		||||
    if (loading) {
 | 
			
		||||
      return null;
 | 
			
		||||
    }
 | 
			
		||||
  if (!data) {
 | 
			
		||||
    return null;
 | 
			
		||||
  }
 | 
			
		||||
@@ -346,7 +351,11 @@ const Details: React.FC<DetailsProps> = ({
 | 
			
		||||
              onTaskNameChange={onTaskNameChange}
 | 
			
		||||
              onTaskDescriptionChange={onTaskDescriptionChange}
 | 
			
		||||
              onToggleTaskComplete={task => {
 | 
			
		||||
                setTaskComplete({ variables: { taskID: task.id, complete: !task.complete } });
 | 
			
		||||
                setTaskComplete({ variables: { taskID: task.id, complete: !task.complete } }).catch(r => {
 | 
			
		||||
                  if (hasNotFoundError(r)) {
 | 
			
		||||
                    history.push(projectURL);
 | 
			
		||||
                  }
 | 
			
		||||
                });
 | 
			
		||||
              }}
 | 
			
		||||
              onDeleteTask={onDeleteTask}
 | 
			
		||||
              onChangeItemName={(itemID, itemName) => {
 | 
			
		||||
 
 | 
			
		||||
@@ -234,7 +234,7 @@ type ShowNewProject = {
 | 
			
		||||
 | 
			
		||||
const Projects = () => {
 | 
			
		||||
  const { showPopup, hidePopup } = usePopup();
 | 
			
		||||
  const { loading, data } = useGetProjectsQuery({ fetchPolicy: 'network-only' });
 | 
			
		||||
  const { loading, data } = useGetProjectsQuery({ fetchPolicy: 'network-only', pollInterval: 5000 });
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
    document.title = 'Taskcafé';
 | 
			
		||||
  }, []);
 | 
			
		||||
 
 | 
			
		||||
@@ -154,7 +154,7 @@ type TeamProjectsProps = {
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const TeamProjects: React.FC<TeamProjectsProps> = ({ teamID }) => {
 | 
			
		||||
  const { loading, data } = useGetTeamQuery({ variables: { teamID } });
 | 
			
		||||
  const { loading, data } = useGetTeamQuery({ variables: { teamID }, pollInterval: 5000 });
 | 
			
		||||
  if (loading) {
 | 
			
		||||
    return <span>loading</span>;
 | 
			
		||||
  }
 | 
			
		||||
 
 | 
			
		||||
@@ -209,7 +209,8 @@ export enum ObjectType {
 | 
			
		||||
  Org = 'ORG',
 | 
			
		||||
  Team = 'TEAM',
 | 
			
		||||
  Project = 'PROJECT',
 | 
			
		||||
  Task = 'TASK'
 | 
			
		||||
  Task = 'TASK',
 | 
			
		||||
  TaskGroup = 'TASK_GROUP'
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export type Query = {
 | 
			
		||||
@@ -722,7 +723,7 @@ export type UpdateProjectMemberRolePayload = {
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export type NewTask = {
 | 
			
		||||
  taskGroupID: Scalars['String'];
 | 
			
		||||
  taskGroupID: Scalars['UUID'];
 | 
			
		||||
  name: Scalars['String'];
 | 
			
		||||
  position: Scalars['Float'];
 | 
			
		||||
};
 | 
			
		||||
@@ -1472,7 +1473,7 @@ export type UpdateProjectMemberRoleMutation = (
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
export type CreateTaskMutationVariables = {
 | 
			
		||||
  taskGroupID: Scalars['String'];
 | 
			
		||||
  taskGroupID: Scalars['UUID'];
 | 
			
		||||
  name: Scalars['String'];
 | 
			
		||||
  position: Scalars['Float'];
 | 
			
		||||
};
 | 
			
		||||
@@ -3044,7 +3045,7 @@ export type UpdateProjectMemberRoleMutationHookResult = ReturnType<typeof useUpd
 | 
			
		||||
export type UpdateProjectMemberRoleMutationResult = ApolloReactCommon.MutationResult<UpdateProjectMemberRoleMutation>;
 | 
			
		||||
export type UpdateProjectMemberRoleMutationOptions = ApolloReactCommon.BaseMutationOptions<UpdateProjectMemberRoleMutation, UpdateProjectMemberRoleMutationVariables>;
 | 
			
		||||
export const CreateTaskDocument = gql`
 | 
			
		||||
    mutation createTask($taskGroupID: String!, $name: String!, $position: Float!) {
 | 
			
		||||
    mutation createTask($taskGroupID: UUID!, $name: String!, $position: Float!) {
 | 
			
		||||
  createTask(input: {taskGroupID: $taskGroupID, name: $name, position: $position}) {
 | 
			
		||||
    ...TaskFields
 | 
			
		||||
  }
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,7 @@ import gql from 'graphql-tag';
 | 
			
		||||
import TASK_FRAGMENT from '../fragments/task';
 | 
			
		||||
 | 
			
		||||
const CREATE_TASK_MUTATION = gql`
 | 
			
		||||
  mutation createTask($taskGroupID: String!, $name: String!, $position: Float!) {
 | 
			
		||||
  mutation createTask($taskGroupID: UUID!, $name: String!, $position: Float!) {
 | 
			
		||||
    createTask(input: { taskGroupID: $taskGroupID, name: $name, position: $position }) {
 | 
			
		||||
      ...TaskFields
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										13
									
								
								frontend/src/shared/utils/error.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								frontend/src/shared/utils/error.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,13 @@
 | 
			
		||||
import { ApolloError } from '@apollo/client';
 | 
			
		||||
 | 
			
		||||
export default function hasNotFoundError(...errors: Array<ApolloError | undefined>) {
 | 
			
		||||
  for (const error of errors) {
 | 
			
		||||
    if (error && error.graphQLErrors.length !== 0) {
 | 
			
		||||
      const notFound = error.graphQLErrors.find(e => e.extensions && e.extensions.code === '404');
 | 
			
		||||
      if (notFound) {
 | 
			
		||||
        return true;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  return false;
 | 
			
		||||
}
 | 
			
		||||
@@ -2648,6 +2648,7 @@ enum ObjectType {
 | 
			
		||||
  TEAM
 | 
			
		||||
  PROJECT
 | 
			
		||||
  TASK
 | 
			
		||||
  TASK_GROUP
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
directive @hasRole(roles: [RoleLevel!]!, level: ActionLevel!, type: ObjectType!) on FIELD_DEFINITION
 | 
			
		||||
@@ -2851,20 +2852,20 @@ type UpdateProjectMemberRolePayload {
 | 
			
		||||
 | 
			
		||||
extend type Mutation {
 | 
			
		||||
  createTask(input: NewTask!):
 | 
			
		||||
    Task! @hasRole(roles: [ADMIN], level: PROJECT, type: PROJECT)
 | 
			
		||||
    Task! @hasRole(roles: [ADMIN], level: PROJECT, type: TASK_GROUP)
 | 
			
		||||
  deleteTask(input: DeleteTaskInput!):
 | 
			
		||||
    DeleteTaskPayload! @hasRole(roles: [ADMIN], level: PROJECT, type: PROJECT)
 | 
			
		||||
    DeleteTaskPayload! @hasRole(roles: [ADMIN], level: PROJECT, type: TASK)
 | 
			
		||||
 | 
			
		||||
  updateTaskDescription(input: UpdateTaskDescriptionInput!):
 | 
			
		||||
    Task! @hasRole(roles: [ADMIN], level: PROJECT, type: PROJECT)
 | 
			
		||||
    Task! @hasRole(roles: [ADMIN], level: PROJECT, type: TASK)
 | 
			
		||||
  updateTaskLocation(input: NewTaskLocation!):
 | 
			
		||||
    UpdateTaskLocationPayload! @hasRole(roles: [ADMIN], level: PROJECT, type: PROJECT)
 | 
			
		||||
    UpdateTaskLocationPayload! @hasRole(roles: [ADMIN], level: PROJECT, type: TASK)
 | 
			
		||||
  updateTaskName(input: UpdateTaskName!):
 | 
			
		||||
    Task! @hasRole(roles: [ADMIN], level: PROJECT, type: PROJECT)
 | 
			
		||||
    Task! @hasRole(roles: [ADMIN], level: PROJECT, type: TASK)
 | 
			
		||||
  setTaskComplete(input: SetTaskComplete!):
 | 
			
		||||
    Task! @hasRole(roles: [ADMIN], level: PROJECT, type: PROJECT)
 | 
			
		||||
    Task! @hasRole(roles: [ADMIN], level: PROJECT, type: TASK)
 | 
			
		||||
  updateTaskDueDate(input: UpdateTaskDueDate!):
 | 
			
		||||
    Task! @hasRole(roles: [ADMIN], level: PROJECT, type: PROJECT)
 | 
			
		||||
    Task! @hasRole(roles: [ADMIN], level: PROJECT, type: TASK)
 | 
			
		||||
 | 
			
		||||
  assignTask(input: AssignTaskInput):
 | 
			
		||||
    Task! @hasRole(roles: [ADMIN], level: PROJECT, type: TASK)
 | 
			
		||||
@@ -2873,7 +2874,7 @@ extend type Mutation {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
input NewTask {
 | 
			
		||||
  taskGroupID: String!
 | 
			
		||||
  taskGroupID: UUID!
 | 
			
		||||
  name: String!
 | 
			
		||||
  position: Float!
 | 
			
		||||
}
 | 
			
		||||
@@ -6533,7 +6534,7 @@ func (ec *executionContext) _Mutation_createTask(ctx context.Context, field grap
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return nil, err
 | 
			
		||||
			}
 | 
			
		||||
			typeArg, err := ec.unmarshalNObjectType2githubᚗcomᚋjordanknottᚋtaskcafeᚋinternalᚋgraphᚐObjectType(ctx, "PROJECT")
 | 
			
		||||
			typeArg, err := ec.unmarshalNObjectType2githubᚗcomᚋjordanknottᚋtaskcafeᚋinternalᚋgraphᚐObjectType(ctx, "TASK_GROUP")
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return nil, err
 | 
			
		||||
			}
 | 
			
		||||
@@ -6606,7 +6607,7 @@ func (ec *executionContext) _Mutation_deleteTask(ctx context.Context, field grap
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return nil, err
 | 
			
		||||
			}
 | 
			
		||||
			typeArg, err := ec.unmarshalNObjectType2githubᚗcomᚋjordanknottᚋtaskcafeᚋinternalᚋgraphᚐObjectType(ctx, "PROJECT")
 | 
			
		||||
			typeArg, err := ec.unmarshalNObjectType2githubᚗcomᚋjordanknottᚋtaskcafeᚋinternalᚋgraphᚐObjectType(ctx, "TASK")
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return nil, err
 | 
			
		||||
			}
 | 
			
		||||
@@ -6679,7 +6680,7 @@ func (ec *executionContext) _Mutation_updateTaskDescription(ctx context.Context,
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return nil, err
 | 
			
		||||
			}
 | 
			
		||||
			typeArg, err := ec.unmarshalNObjectType2githubᚗcomᚋjordanknottᚋtaskcafeᚋinternalᚋgraphᚐObjectType(ctx, "PROJECT")
 | 
			
		||||
			typeArg, err := ec.unmarshalNObjectType2githubᚗcomᚋjordanknottᚋtaskcafeᚋinternalᚋgraphᚐObjectType(ctx, "TASK")
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return nil, err
 | 
			
		||||
			}
 | 
			
		||||
@@ -6752,7 +6753,7 @@ func (ec *executionContext) _Mutation_updateTaskLocation(ctx context.Context, fi
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return nil, err
 | 
			
		||||
			}
 | 
			
		||||
			typeArg, err := ec.unmarshalNObjectType2githubᚗcomᚋjordanknottᚋtaskcafeᚋinternalᚋgraphᚐObjectType(ctx, "PROJECT")
 | 
			
		||||
			typeArg, err := ec.unmarshalNObjectType2githubᚗcomᚋjordanknottᚋtaskcafeᚋinternalᚋgraphᚐObjectType(ctx, "TASK")
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return nil, err
 | 
			
		||||
			}
 | 
			
		||||
@@ -6825,7 +6826,7 @@ func (ec *executionContext) _Mutation_updateTaskName(ctx context.Context, field
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return nil, err
 | 
			
		||||
			}
 | 
			
		||||
			typeArg, err := ec.unmarshalNObjectType2githubᚗcomᚋjordanknottᚋtaskcafeᚋinternalᚋgraphᚐObjectType(ctx, "PROJECT")
 | 
			
		||||
			typeArg, err := ec.unmarshalNObjectType2githubᚗcomᚋjordanknottᚋtaskcafeᚋinternalᚋgraphᚐObjectType(ctx, "TASK")
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return nil, err
 | 
			
		||||
			}
 | 
			
		||||
@@ -6898,7 +6899,7 @@ func (ec *executionContext) _Mutation_setTaskComplete(ctx context.Context, field
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return nil, err
 | 
			
		||||
			}
 | 
			
		||||
			typeArg, err := ec.unmarshalNObjectType2githubᚗcomᚋjordanknottᚋtaskcafeᚋinternalᚋgraphᚐObjectType(ctx, "PROJECT")
 | 
			
		||||
			typeArg, err := ec.unmarshalNObjectType2githubᚗcomᚋjordanknottᚋtaskcafeᚋinternalᚋgraphᚐObjectType(ctx, "TASK")
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return nil, err
 | 
			
		||||
			}
 | 
			
		||||
@@ -6971,7 +6972,7 @@ func (ec *executionContext) _Mutation_updateTaskDueDate(ctx context.Context, fie
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return nil, err
 | 
			
		||||
			}
 | 
			
		||||
			typeArg, err := ec.unmarshalNObjectType2githubᚗcomᚋjordanknottᚋtaskcafeᚋinternalᚋgraphᚐObjectType(ctx, "PROJECT")
 | 
			
		||||
			typeArg, err := ec.unmarshalNObjectType2githubᚗcomᚋjordanknottᚋtaskcafeᚋinternalᚋgraphᚐObjectType(ctx, "TASK")
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return nil, err
 | 
			
		||||
			}
 | 
			
		||||
@@ -15194,7 +15195,7 @@ func (ec *executionContext) unmarshalInputNewTask(ctx context.Context, obj inter
 | 
			
		||||
		switch k {
 | 
			
		||||
		case "taskGroupID":
 | 
			
		||||
			var err error
 | 
			
		||||
			it.TaskGroupID, err = ec.unmarshalNString2string(ctx, v)
 | 
			
		||||
			it.TaskGroupID, err = ec.unmarshalNUUID2githubᚗcomᚋgoogleᚋuuidᚐUUID(ctx, v)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return it, err
 | 
			
		||||
			}
 | 
			
		||||
 
 | 
			
		||||
@@ -19,6 +19,7 @@ import (
 | 
			
		||||
	"github.com/jordanknott/taskcafe/internal/db"
 | 
			
		||||
	"github.com/jordanknott/taskcafe/internal/utils"
 | 
			
		||||
	log "github.com/sirupsen/logrus"
 | 
			
		||||
	"github.com/vektah/gqlparser/v2/gqlerror"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// NewHandler returns a new graphql endpoint handler.
 | 
			
		||||
@@ -51,6 +52,8 @@ func NewHandler(repo db.Repository) http.Handler {
 | 
			
		||||
			fieldName = "TeamID"
 | 
			
		||||
		case ObjectTypeTask:
 | 
			
		||||
			fieldName = "TaskID"
 | 
			
		||||
		case ObjectTypeTaskGroup:
 | 
			
		||||
			fieldName = "TaskGroupID"
 | 
			
		||||
		default:
 | 
			
		||||
			fieldName = "ProjectID"
 | 
			
		||||
		}
 | 
			
		||||
@@ -68,6 +71,13 @@ func NewHandler(repo db.Repository) http.Handler {
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					return nil, err
 | 
			
		||||
				}
 | 
			
		||||
			} else if typeArg == ObjectTypeTaskGroup {
 | 
			
		||||
				log.WithFields(log.Fields{"subjectID": subjectID}).Info("fetching project ID using task group ID")
 | 
			
		||||
				taskGroup, err := repo.GetTaskGroupByID(ctx, subjectID)
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					return nil, err
 | 
			
		||||
				}
 | 
			
		||||
				subjectID = taskGroup.ProjectID
 | 
			
		||||
			}
 | 
			
		||||
			roles, err := GetProjectRoles(ctx, repo, subjectID)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
@@ -186,3 +196,13 @@ func GetActionType(actionType int32) ActionType {
 | 
			
		||||
		panic("Not a valid entity type!")
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NotFoundError creates a 404 gqlerror
 | 
			
		||||
func NotFoundError(message string) error {
 | 
			
		||||
	return &gqlerror.Error{
 | 
			
		||||
		Message: message,
 | 
			
		||||
		Extensions: map[string]interface{}{
 | 
			
		||||
			"code": "404",
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -229,9 +229,9 @@ type NewRefreshToken struct {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type NewTask struct {
 | 
			
		||||
	TaskGroupID string  `json:"taskGroupID"`
 | 
			
		||||
	Name        string  `json:"name"`
 | 
			
		||||
	Position    float64 `json:"position"`
 | 
			
		||||
	TaskGroupID uuid.UUID `json:"taskGroupID"`
 | 
			
		||||
	Name        string    `json:"name"`
 | 
			
		||||
	Position    float64   `json:"position"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type NewTaskGroup struct {
 | 
			
		||||
@@ -648,10 +648,11 @@ func (e EntityType) MarshalGQL(w io.Writer) {
 | 
			
		||||
type ObjectType string
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	ObjectTypeOrg     ObjectType = "ORG"
 | 
			
		||||
	ObjectTypeTeam    ObjectType = "TEAM"
 | 
			
		||||
	ObjectTypeProject ObjectType = "PROJECT"
 | 
			
		||||
	ObjectTypeTask    ObjectType = "TASK"
 | 
			
		||||
	ObjectTypeOrg       ObjectType = "ORG"
 | 
			
		||||
	ObjectTypeTeam      ObjectType = "TEAM"
 | 
			
		||||
	ObjectTypeProject   ObjectType = "PROJECT"
 | 
			
		||||
	ObjectTypeTask      ObjectType = "TASK"
 | 
			
		||||
	ObjectTypeTaskGroup ObjectType = "TASK_GROUP"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var AllObjectType = []ObjectType{
 | 
			
		||||
@@ -659,11 +660,12 @@ var AllObjectType = []ObjectType{
 | 
			
		||||
	ObjectTypeTeam,
 | 
			
		||||
	ObjectTypeProject,
 | 
			
		||||
	ObjectTypeTask,
 | 
			
		||||
	ObjectTypeTaskGroup,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (e ObjectType) IsValid() bool {
 | 
			
		||||
	switch e {
 | 
			
		||||
	case ObjectTypeOrg, ObjectTypeTeam, ObjectTypeProject, ObjectTypeTask:
 | 
			
		||||
	case ObjectTypeOrg, ObjectTypeTeam, ObjectTypeProject, ObjectTypeTask, ObjectTypeTaskGroup:
 | 
			
		||||
		return true
 | 
			
		||||
	}
 | 
			
		||||
	return false
 | 
			
		||||
 
 | 
			
		||||
@@ -174,6 +174,7 @@ enum ObjectType {
 | 
			
		||||
  TEAM
 | 
			
		||||
  PROJECT
 | 
			
		||||
  TASK
 | 
			
		||||
  TASK_GROUP
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
directive @hasRole(roles: [RoleLevel!]!, level: ActionLevel!, type: ObjectType!) on FIELD_DEFINITION
 | 
			
		||||
@@ -377,20 +378,20 @@ type UpdateProjectMemberRolePayload {
 | 
			
		||||
 | 
			
		||||
extend type Mutation {
 | 
			
		||||
  createTask(input: NewTask!):
 | 
			
		||||
    Task! @hasRole(roles: [ADMIN], level: PROJECT, type: PROJECT)
 | 
			
		||||
    Task! @hasRole(roles: [ADMIN], level: PROJECT, type: TASK_GROUP)
 | 
			
		||||
  deleteTask(input: DeleteTaskInput!):
 | 
			
		||||
    DeleteTaskPayload! @hasRole(roles: [ADMIN], level: PROJECT, type: PROJECT)
 | 
			
		||||
    DeleteTaskPayload! @hasRole(roles: [ADMIN], level: PROJECT, type: TASK)
 | 
			
		||||
 | 
			
		||||
  updateTaskDescription(input: UpdateTaskDescriptionInput!):
 | 
			
		||||
    Task! @hasRole(roles: [ADMIN], level: PROJECT, type: PROJECT)
 | 
			
		||||
    Task! @hasRole(roles: [ADMIN], level: PROJECT, type: TASK)
 | 
			
		||||
  updateTaskLocation(input: NewTaskLocation!):
 | 
			
		||||
    UpdateTaskLocationPayload! @hasRole(roles: [ADMIN], level: PROJECT, type: PROJECT)
 | 
			
		||||
    UpdateTaskLocationPayload! @hasRole(roles: [ADMIN], level: PROJECT, type: TASK)
 | 
			
		||||
  updateTaskName(input: UpdateTaskName!):
 | 
			
		||||
    Task! @hasRole(roles: [ADMIN], level: PROJECT, type: PROJECT)
 | 
			
		||||
    Task! @hasRole(roles: [ADMIN], level: PROJECT, type: TASK)
 | 
			
		||||
  setTaskComplete(input: SetTaskComplete!):
 | 
			
		||||
    Task! @hasRole(roles: [ADMIN], level: PROJECT, type: PROJECT)
 | 
			
		||||
    Task! @hasRole(roles: [ADMIN], level: PROJECT, type: TASK)
 | 
			
		||||
  updateTaskDueDate(input: UpdateTaskDueDate!):
 | 
			
		||||
    Task! @hasRole(roles: [ADMIN], level: PROJECT, type: PROJECT)
 | 
			
		||||
    Task! @hasRole(roles: [ADMIN], level: PROJECT, type: TASK)
 | 
			
		||||
 | 
			
		||||
  assignTask(input: AssignTaskInput):
 | 
			
		||||
    Task! @hasRole(roles: [ADMIN], level: PROJECT, type: TASK)
 | 
			
		||||
@@ -399,7 +400,7 @@ extend type Mutation {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
input NewTask {
 | 
			
		||||
  taskGroupID: String!
 | 
			
		||||
  taskGroupID: UUID!
 | 
			
		||||
  name: String!
 | 
			
		||||
  position: Float!
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -179,14 +179,9 @@ func (r *mutationResolver) UpdateProjectMemberRole(ctx context.Context, input Up
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *mutationResolver) CreateTask(ctx context.Context, input NewTask) (*db.Task, error) {
 | 
			
		||||
	taskGroupID, err := uuid.Parse(input.TaskGroupID)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.WithError(err).Error("issue while parsing task group ID")
 | 
			
		||||
		return &db.Task{}, err
 | 
			
		||||
	}
 | 
			
		||||
	createdAt := time.Now().UTC()
 | 
			
		||||
	log.WithFields(log.Fields{"positon": input.Position, "taskGroupID": taskGroupID}).Info("creating task")
 | 
			
		||||
	task, err := r.Repository.CreateTask(ctx, db.CreateTaskParams{taskGroupID, createdAt, input.Name, input.Position})
 | 
			
		||||
	log.WithFields(log.Fields{"positon": input.Position, "taskGroupID": input.TaskGroupID}).Info("creating task")
 | 
			
		||||
	task, err := r.Repository.CreateTask(ctx, db.CreateTaskParams{input.TaskGroupID, createdAt, input.Name, input.Position})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.WithError(err).Error("issue while creating task")
 | 
			
		||||
		return &db.Task{}, err
 | 
			
		||||
@@ -238,6 +233,9 @@ func (r *mutationResolver) SetTaskComplete(ctx context.Context, input SetTaskCom
 | 
			
		||||
	completedAt := time.Now().UTC()
 | 
			
		||||
	task, err := r.Repository.SetTaskComplete(ctx, db.SetTaskCompleteParams{TaskID: input.TaskID, Complete: input.Complete, CompletedAt: sql.NullTime{Time: completedAt, Valid: true}})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		if err == sql.ErrNoRows {
 | 
			
		||||
			return &db.Task{}, NotFoundError("task does not exist")
 | 
			
		||||
		}
 | 
			
		||||
		return &db.Task{}, err
 | 
			
		||||
	}
 | 
			
		||||
	return &task, nil
 | 
			
		||||
@@ -1033,6 +1031,14 @@ func (r *queryResolver) FindProject(ctx context.Context, input FindProject) (*db
 | 
			
		||||
 | 
			
		||||
func (r *queryResolver) FindTask(ctx context.Context, input FindTask) (*db.Task, error) {
 | 
			
		||||
	task, err := r.Repository.GetTaskByID(ctx, input.TaskID)
 | 
			
		||||
	if err == sql.ErrNoRows {
 | 
			
		||||
		return &db.Task{}, &gqlerror.Error{
 | 
			
		||||
			Message: "Task does not exist",
 | 
			
		||||
			Extensions: map[string]interface{}{
 | 
			
		||||
				"code": "404",
 | 
			
		||||
			},
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return &task, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -1240,6 +1246,9 @@ func (r *taskResolver) Assigned(ctx context.Context, obj *db.Task) ([]Member, er
 | 
			
		||||
	taskMemberLinks, err := r.Repository.GetAssignedMembersForTask(ctx, obj.TaskID)
 | 
			
		||||
	taskMembers := []Member{}
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		if err == sql.ErrNoRows {
 | 
			
		||||
			return taskMembers, nil
 | 
			
		||||
		}
 | 
			
		||||
		return taskMembers, err
 | 
			
		||||
	}
 | 
			
		||||
	for _, taskMemberLink := range taskMemberLinks {
 | 
			
		||||
@@ -1274,11 +1283,19 @@ func (r *taskResolver) Assigned(ctx context.Context, obj *db.Task) ([]Member, er
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *taskResolver) Labels(ctx context.Context, obj *db.Task) ([]db.TaskLabel, error) {
 | 
			
		||||
	return r.Repository.GetTaskLabelsForTaskID(ctx, obj.TaskID)
 | 
			
		||||
	labels, err := r.Repository.GetTaskLabelsForTaskID(ctx, obj.TaskID)
 | 
			
		||||
	if err != nil && err != sql.ErrNoRows {
 | 
			
		||||
		return []db.TaskLabel{}, err
 | 
			
		||||
	}
 | 
			
		||||
	return labels, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *taskResolver) Checklists(ctx context.Context, obj *db.Task) ([]db.TaskChecklist, error) {
 | 
			
		||||
	return r.Repository.GetTaskChecklistsForTask(ctx, obj.TaskID)
 | 
			
		||||
	checklists, err := r.Repository.GetTaskChecklistsForTask(ctx, obj.TaskID)
 | 
			
		||||
	if err != nil && err != sql.ErrNoRows {
 | 
			
		||||
		return []db.TaskChecklist{}, err
 | 
			
		||||
	}
 | 
			
		||||
	return checklists, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (r *taskResolver) Badges(ctx context.Context, obj *db.Task) (*TaskBadges, error) {
 | 
			
		||||
 
 | 
			
		||||
@@ -14,6 +14,7 @@ enum ObjectType {
 | 
			
		||||
  TEAM
 | 
			
		||||
  PROJECT
 | 
			
		||||
  TASK
 | 
			
		||||
  TASK_GROUP
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
directive @hasRole(roles: [RoleLevel!]!, level: ActionLevel!, type: ObjectType!) on FIELD_DEFINITION
 | 
			
		||||
 
 | 
			
		||||
@@ -1,19 +1,19 @@
 | 
			
		||||
extend type Mutation {
 | 
			
		||||
  createTask(input: NewTask!):
 | 
			
		||||
    Task! @hasRole(roles: [ADMIN], level: PROJECT, type: PROJECT)
 | 
			
		||||
    Task! @hasRole(roles: [ADMIN], level: PROJECT, type: TASK_GROUP)
 | 
			
		||||
  deleteTask(input: DeleteTaskInput!):
 | 
			
		||||
    DeleteTaskPayload! @hasRole(roles: [ADMIN], level: PROJECT, type: PROJECT)
 | 
			
		||||
    DeleteTaskPayload! @hasRole(roles: [ADMIN], level: PROJECT, type: TASK)
 | 
			
		||||
 | 
			
		||||
  updateTaskDescription(input: UpdateTaskDescriptionInput!):
 | 
			
		||||
    Task! @hasRole(roles: [ADMIN], level: PROJECT, type: PROJECT)
 | 
			
		||||
    Task! @hasRole(roles: [ADMIN], level: PROJECT, type: TASK)
 | 
			
		||||
  updateTaskLocation(input: NewTaskLocation!):
 | 
			
		||||
    UpdateTaskLocationPayload! @hasRole(roles: [ADMIN], level: PROJECT, type: PROJECT)
 | 
			
		||||
    UpdateTaskLocationPayload! @hasRole(roles: [ADMIN], level: PROJECT, type: TASK)
 | 
			
		||||
  updateTaskName(input: UpdateTaskName!):
 | 
			
		||||
    Task! @hasRole(roles: [ADMIN], level: PROJECT, type: PROJECT)
 | 
			
		||||
    Task! @hasRole(roles: [ADMIN], level: PROJECT, type: TASK)
 | 
			
		||||
  setTaskComplete(input: SetTaskComplete!):
 | 
			
		||||
    Task! @hasRole(roles: [ADMIN], level: PROJECT, type: PROJECT)
 | 
			
		||||
    Task! @hasRole(roles: [ADMIN], level: PROJECT, type: TASK)
 | 
			
		||||
  updateTaskDueDate(input: UpdateTaskDueDate!):
 | 
			
		||||
    Task! @hasRole(roles: [ADMIN], level: PROJECT, type: PROJECT)
 | 
			
		||||
    Task! @hasRole(roles: [ADMIN], level: PROJECT, type: TASK)
 | 
			
		||||
 | 
			
		||||
  assignTask(input: AssignTaskInput):
 | 
			
		||||
    Task! @hasRole(roles: [ADMIN], level: PROJECT, type: TASK)
 | 
			
		||||
@@ -22,7 +22,7 @@ extend type Mutation {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
input NewTask {
 | 
			
		||||
  taskGroupID: String!
 | 
			
		||||
  taskGroupID: UUID!
 | 
			
		||||
  name: String!
 | 
			
		||||
  position: Float!
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user