diff --git a/twenty-backend/lib/twenty-backend/graphql/mutation/set_random_project_color.rb b/twenty-backend/lib/twenty-backend/graphql/mutation/set_random_project_color.rb new file mode 100644 index 0000000..dbf1ef8 --- /dev/null +++ b/twenty-backend/lib/twenty-backend/graphql/mutation/set_random_project_color.rb @@ -0,0 +1,18 @@ +module Twenty::GraphQL::Mutation + class SetRandomProjectColor < ::GraphQL::Schema::Mutation + require_relative "../type/project" + argument :project_id, Int, required: true + field :ok, Boolean, null: false + field :errors, [String], null: false + field :project, Twenty::GraphQL::Type::Project, null: true + + def resolve(project_id:) + project = Twenty::Project.find_by(id: project_id) + project.color = project.send(:random_color) + project.save! + {ok: true, errors: [], project:} + rescue => ex + {ok: false, errors: [ex.message]} + end + end +end diff --git a/twenty-backend/lib/twenty-backend/graphql/type/mutation.rb b/twenty-backend/lib/twenty-backend/graphql/type/mutation.rb index 94a2ab0..08929a6 100644 --- a/twenty-backend/lib/twenty-backend/graphql/type/mutation.rb +++ b/twenty-backend/lib/twenty-backend/graphql/type/mutation.rb @@ -4,9 +4,11 @@ module Twenty::GraphQL::Type require_relative "../mutation/complete_task" require_relative "../mutation/create_task" require_relative "../mutation/update_task" + require_relative "../mutation/set_random_project_color" field :destroy_task, mutation: Twenty::GraphQL::Mutation::DestroyTask field :complete_task, mutation: Twenty::GraphQL::Mutation::CompleteTask field :create_task, mutation: Twenty::GraphQL::Mutation::CreateTask field :update_task, mutation: Twenty::GraphQL::Mutation::UpdateTask + field :set_random_project_color, mutation: Twenty::GraphQL::Mutation::SetRandomProjectColor end end diff --git a/twenty-backend/share/twenty-backend/schema.graphql b/twenty-backend/share/twenty-backend/schema.graphql index 233af8b..9e045f4 100644 --- a/twenty-backend/share/twenty-backend/schema.graphql +++ b/twenty-backend/share/twenty-backend/schema.graphql @@ -30,6 +30,7 @@ type Mutation { completeTask(taskId: Int!): CompleteTaskPayload createTask(input: TaskInput!): CreateTaskPayload destroyTask(taskId: Int!): DestroyTaskPayload + setRandomProjectColor(projectId: Int!): SetRandomProjectColorPayload updateTask(input: TaskInput!, taskId: Int!): UpdateTaskPayload } @@ -47,6 +48,15 @@ type Query { tasks(projectId: Int, status: TaskStatus!): [Task!]! } +""" +Autogenerated return type of SetRandomProjectColor. +""" +type SetRandomProjectColorPayload { + errors: [String!]! + ok: Boolean! + project: Project +} + type Task { content: String! id: Int! diff --git a/twenty-frontend/src/js/components/Projects.tsx b/twenty-frontend/src/js/components/Projects.tsx index 8553f19..cc42080 100644 --- a/twenty-frontend/src/js/components/Projects.tsx +++ b/twenty-frontend/src/js/components/Projects.tsx @@ -1,3 +1,4 @@ +import { useSetRandomProjectColor } from "/hooks/mutations/useSetRandomProjectColor"; import React, { useEffect } from "react"; import { NavBar } from "/components/NavBar"; import { useProjects } from "/hooks/queries/useProjects"; @@ -5,6 +6,7 @@ import { Project } from "/types/schema"; export function Projects() { const { data, loading } = useProjects(); + const setRandomProjectColor = useSetRandomProjectColor(); const projects = data?.projects; useEffect(() => { @@ -16,28 +18,41 @@ export function Projects() { } return ( -
-
+
+
-
-
-

Projects

-
- -
-
+
+

Projects

+
    + {projects.map((project: Project, i: number) => { + return ( +
  • +
    { + await setRandomProjectColor({ + variables: { projectId: project.id }, + }); + }} + >
    + + {project.name} + + {project.path} + + +
  • + ); + })} +
); diff --git a/twenty-frontend/src/js/hooks/mutations/useSetRandomProjectColor.tsx b/twenty-frontend/src/js/hooks/mutations/useSetRandomProjectColor.tsx new file mode 100644 index 0000000..6008d5e --- /dev/null +++ b/twenty-frontend/src/js/hooks/mutations/useSetRandomProjectColor.tsx @@ -0,0 +1,62 @@ +import { ApolloCache, useMutation, gql } from "@apollo/client"; +import { + SetRandomProjectColorPayload, + MutationSetRandomProjectColorArgs, + Project, +} from "/types/schema"; + +const GQL = gql` + mutation SetRandomProjectColor($projectId: Int!) { + setRandomProjectColor(projectId: $projectId) { + project { + id + color + } + errors + } + } +`; + +type TArgs = { + variables: { projectId: number }; +}; + +export function useSetRandomProjectColor() { + const [setRandomProjectColor] = useMutation< + SetRandomProjectColorPayload, + MutationSetRandomProjectColorArgs + >(GQL); + + return ({ variables }: TArgs) => { + return setRandomProjectColor({ + variables, + update(cache, { data }) { + const project: Project = data.project; + modify(cache, project); + }, + }); + }; +} + +const modify = ( + cache: ApolloCache, + project: Project, +) => { + cache.modify({ + id: cache.identify(project), + fields: { + projects(existingProjects = []) { + cache.writeFragment({ + id: cache.identify(project), + data: { project }, + fragment: gql` + fragment P on Project { + color + } + `, + }); + return [...existingProjects, project]; + }, + }, + }); +}; diff --git a/twenty-frontend/src/js/types/schema.ts b/twenty-frontend/src/js/types/schema.ts index 52e2b4a..6b858e5 100644 --- a/twenty-frontend/src/js/types/schema.ts +++ b/twenty-frontend/src/js/types/schema.ts @@ -54,6 +54,7 @@ export type Mutation = { completeTask?: Maybe; createTask?: Maybe; destroyTask?: Maybe; + setRandomProjectColor?: Maybe; updateTask?: Maybe; }; @@ -69,6 +70,10 @@ export type MutationDestroyTaskArgs = { taskId: Scalars["Int"]["input"]; }; +export type MutationSetRandomProjectColorArgs = { + projectId: Scalars["Int"]["input"]; +}; + export type MutationUpdateTaskArgs = { input: TaskInput; taskId: Scalars["Int"]["input"]; @@ -99,6 +104,14 @@ export type QueryTasksArgs = { status: TaskStatus; }; +/** Autogenerated return type of SetRandomProjectColor. */ +export type SetRandomProjectColorPayload = { + __typename?: "SetRandomProjectColorPayload"; + errors: Array; + ok: Scalars["Boolean"]["output"]; + project?: Maybe; +}; + export type Task = { __typename?: "Task"; content: Scalars["String"]["output"];