Merge branch 'develop'

This commit is contained in:
0x1eef 2024-01-17 15:15:20 -03:00
commit a369edd812
6 changed files with 140 additions and 20 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/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

View file

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

View file

@ -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 (
<div className="two-columns">
<div className="column-1">
<div className="flex">
<div className="w-1/4">
<NavBar />
</div>
<div className="column-2">
<div className="panel">
<h1>Projects</h1>
<div className="panel-body">
<ul className="collection">
{projects.map((project: Project, i: number) => {
return (
<li className="item" key={i}>
<a href={`/tasks#project_id=${project.id}`}>
<span className="title">{project.name}</span>
<span className="subtitle">{project.path}</span>
</a>
</li>
);
})}
</ul>
</div>
</div>
<div className="w-3/4">
<h1 className="bg-secondary text-primary p-3 rounded">Projects</h1>
<ul className="flex flex-wrap">
{projects.map((project: Project, i: number) => {
return (
<li
className="flex flex-row p-3 hover-bg-secondary w-full"
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
className="w-6/8 no-underline text-accent block h-14"
href={`/tasks/#projectId=${project.id}`}
>
<span className="block w-full">{project.name}</span>
<span className="block w-full text-smaller text-secondary">
{project.path}
</span>
</a>
</li>
);
})}
</ul>
</div>
</div>
);

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>;
createTask?: Maybe<CreateTaskPayload>;
destroyTask?: Maybe<DestroyTaskPayload>;
setRandomProjectColor?: Maybe<SetRandomProjectColorPayload>;
updateTask?: Maybe<UpdateTaskPayload>;
};
@ -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<Scalars["String"]["output"]>;
ok: Scalars["Boolean"]["output"];
project?: Maybe<Project>;
};
export type Task = {
__typename?: "Task";
content: Scalars["String"]["output"];