Add ability to change project's color

This commit is contained in:
0x1eef 2024-01-17 11:02:06 -03:00
parent d7ee9e50e6
commit fb0260466a
6 changed files with 117 additions and 1 deletions

View file

@ -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

View file

@ -4,9 +4,11 @@ module Twenty::GraphQL::Type
require_relative "../mutation/complete_task" require_relative "../mutation/complete_task"
require_relative "../mutation/create_task" require_relative "../mutation/create_task"
require_relative "../mutation/update_task" require_relative "../mutation/update_task"
require_relative "../mutation/set_random_project_color"
field :destroy_task, mutation: Twenty::GraphQL::Mutation::DestroyTask field :destroy_task, mutation: Twenty::GraphQL::Mutation::DestroyTask
field :complete_task, mutation: Twenty::GraphQL::Mutation::CompleteTask field :complete_task, mutation: Twenty::GraphQL::Mutation::CompleteTask
field :create_task, mutation: Twenty::GraphQL::Mutation::CreateTask field :create_task, mutation: Twenty::GraphQL::Mutation::CreateTask
field :update_task, mutation: Twenty::GraphQL::Mutation::UpdateTask field :update_task, mutation: Twenty::GraphQL::Mutation::UpdateTask
field :set_random_project_color, mutation: Twenty::GraphQL::Mutation::SetRandomProjectColor
end end
end end

View file

@ -30,6 +30,7 @@ type Mutation {
completeTask(taskId: Int!): CompleteTaskPayload completeTask(taskId: Int!): CompleteTaskPayload
createTask(input: TaskInput!): CreateTaskPayload createTask(input: TaskInput!): CreateTaskPayload
destroyTask(taskId: Int!): DestroyTaskPayload destroyTask(taskId: Int!): DestroyTaskPayload
setRandomProjectColor(projectId: Int!): SetRandomProjectColorPayload
updateTask(input: TaskInput!, taskId: Int!): UpdateTaskPayload updateTask(input: TaskInput!, taskId: Int!): UpdateTaskPayload
} }
@ -47,6 +48,15 @@ type Query {
tasks(projectId: Int, status: TaskStatus!): [Task!]! tasks(projectId: Int, status: TaskStatus!): [Task!]!
} }
"""
Autogenerated return type of SetRandomProjectColor.
"""
type SetRandomProjectColorPayload {
errors: [String!]!
ok: Boolean!
project: Project
}
type Task { type Task {
content: String! content: String!
id: Int! id: Int!

View file

@ -1,3 +1,4 @@
import { useSetRandomProjectColor } from "/hooks/mutations/useSetRandomProjectColor";
import React, { useEffect } from "react"; import React, { useEffect } from "react";
import { NavBar } from "/components/NavBar"; import { NavBar } from "/components/NavBar";
import { useProjects } from "/hooks/queries/useProjects"; import { useProjects } from "/hooks/queries/useProjects";
@ -5,6 +6,7 @@ import { Project } from "/types/schema";
export function Projects() { export function Projects() {
const { data, loading } = useProjects(); const { data, loading } = useProjects();
const setRandomProjectColor = useSetRandomProjectColor();
const projects = data?.projects; const projects = data?.projects;
useEffect(() => { useEffect(() => {
@ -29,8 +31,17 @@ export function Projects() {
className="flex flex-row p-3 hover-bg-secondary w-full" className="flex flex-row p-3 hover-bg-secondary w-full"
key={i} key={i}
> >
<div
style={{ backgroundColor: project.color }}
className="w-2/8 rounded w-12 h-12 mr-3 cursor-pointer"
onClick={async () => {
await setRandomProjectColor({
variables: { projectId: project.id },
});
}}
></div>
<a <a
className="no-underline text-accent block h-14" className="w-6/8 no-underline text-accent block h-14"
href={`/tasks/#projectId=${project.id}`} href={`/tasks/#projectId=${project.id}`}
> >
<span className="block w-full">{project.name}</span> <span className="block w-full">{project.name}</span>

View file

@ -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<SetRandomProjectColorPayload>,
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];
},
},
});
};

View file

@ -54,6 +54,7 @@ export type Mutation = {
completeTask?: Maybe<CompleteTaskPayload>; completeTask?: Maybe<CompleteTaskPayload>;
createTask?: Maybe<CreateTaskPayload>; createTask?: Maybe<CreateTaskPayload>;
destroyTask?: Maybe<DestroyTaskPayload>; destroyTask?: Maybe<DestroyTaskPayload>;
setRandomProjectColor?: Maybe<SetRandomProjectColorPayload>;
updateTask?: Maybe<UpdateTaskPayload>; updateTask?: Maybe<UpdateTaskPayload>;
}; };
@ -69,6 +70,10 @@ export type MutationDestroyTaskArgs = {
taskId: Scalars["Int"]["input"]; taskId: Scalars["Int"]["input"];
}; };
export type MutationSetRandomProjectColorArgs = {
projectId: Scalars["Int"]["input"];
};
export type MutationUpdateTaskArgs = { export type MutationUpdateTaskArgs = {
input: TaskInput; input: TaskInput;
taskId: Scalars["Int"]["input"]; taskId: Scalars["Int"]["input"];
@ -99,6 +104,14 @@ export type QueryTasksArgs = {
status: TaskStatus; status: TaskStatus;
}; };
/** Autogenerated return type of SetRandomProjectColor. */
export type SetRandomProjectColorPayload = {
__typename?: "SetRandomProjectColorPayload";
errors: Array<Scalars["String"]["output"]>;
ok: Scalars["Boolean"]["output"];
project?: Maybe<Project>;
};
export type Task = { export type Task = {
__typename?: "Task"; __typename?: "Task";
content: Scalars["String"]["output"]; content: Scalars["String"]["output"];