From 7827d7f7221345e0c271e0886f202e4771390f5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matou=C5=A1=20Volf?= <66163112+matous-volf@users.noreply.github.com> Date: Sun, 8 Sep 2024 08:21:33 +0200 Subject: [PATCH 1/4] style: use `Self` in error enum `impl`s --- src/errors/error.rs | 4 ++-- src/errors/project_error.rs | 4 ++-- src/errors/task_error.rs | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/errors/error.rs b/src/errors/error.rs index a26a41b..993dd7e 100644 --- a/src/errors/error.rs +++ b/src/errors/error.rs @@ -11,7 +11,7 @@ pub enum Error { impl Display for Error { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { - Error::ServerInternal => write!(f, "internal server error"), + Self::ServerInternal => write!(f, "internal server error"), } } } @@ -22,7 +22,7 @@ impl FromStr for Error { fn from_str(s: &str) -> Result { Ok(match s { - "internal server error" => Error::ServerInternal, + "internal server error" => Self::ServerInternal, _ => return Err(()), }) } diff --git a/src/errors/project_error.rs b/src/errors/project_error.rs index f93283f..7bf5503 100644 --- a/src/errors/project_error.rs +++ b/src/errors/project_error.rs @@ -36,7 +36,7 @@ impl From for ErrorVec { impl From for ProjectError { fn from(_: diesel::result::Error) -> Self { - ProjectError::Error(Error::ServerInternal) + Self::Error(Error::ServerInternal) } } @@ -52,6 +52,6 @@ impl FromStr for ProjectError { type Err = (); fn from_str(_: &str) -> Result { - Ok(ProjectError::Error(Error::ServerInternal)) + Ok(Self::Error(Error::ServerInternal)) } } diff --git a/src/errors/task_error.rs b/src/errors/task_error.rs index a769de9..d745550 100644 --- a/src/errors/task_error.rs +++ b/src/errors/task_error.rs @@ -42,12 +42,12 @@ impl From for TaskError { diesel::result::DatabaseErrorKind::ForeignKeyViolation, info ) => { match info.constraint_name() { - Some("tasks_project_id_fkey") => TaskError::ProjectNotFound, - _ => TaskError::Error(Error::ServerInternal) + Some("tasks_project_id_fkey") => Self::ProjectNotFound, + _ => Self::Error(Error::ServerInternal) } } _ => { - TaskError::Error(Error::ServerInternal) + Self::Error(Error::ServerInternal) } } } @@ -65,6 +65,6 @@ impl FromStr for TaskError { type Err = (); fn from_str(_: &str) -> Result { - Ok(TaskError::Error(Error::ServerInternal)) + Ok(Self::Error(Error::ServerInternal)) } } -- 2.47.1 From b869181dcff0683a71321653755fdb73d1c42a13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matou=C5=A1=20Volf?= <66163112+matous-volf@users.noreply.github.com> Date: Sun, 8 Sep 2024 08:21:48 +0200 Subject: [PATCH 2/4] feat: create a server function for deleting a project --- src/errors/error.rs | 6 ++++++ src/server/projects.rs | 14 ++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/src/errors/error.rs b/src/errors/error.rs index 993dd7e..21e1214 100644 --- a/src/errors/error.rs +++ b/src/errors/error.rs @@ -7,6 +7,12 @@ pub enum Error { ServerInternal, } +impl From for Error { + fn from(_: diesel::result::Error) -> Self { + Self::ServerInternal + } +} + // has to be implemented for Dioxus server functions impl Display for Error { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { diff --git a/src/server/projects.rs b/src/server/projects.rs index 94ac3f9..0519dcd 100644 --- a/src/server/projects.rs +++ b/src/server/projects.rs @@ -71,3 +71,17 @@ pub(crate) async fn edit_project(project_id: i32, new_project: NewProject) Ok(updated_project) } + +#[server] +pub(crate) async fn delete_project(project_id: i32) + -> Result<(), ServerFnError>> { + use crate::schema::projects::dsl::*; + + let mut connection = establish_database_connection() + .map_err::, _>(|_| vec![Error::ServerInternal].into())?; + + diesel::delete(projects.filter(id.eq(project_id))).execute(&mut connection) + .map_err::, _>(|error| vec![error.into()].into())?; + + Ok(()) +} -- 2.47.1 From d63fb0f28d52a01b80430f86e425d1e46d2292b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matou=C5=A1=20Volf?= <66163112+matous-volf@users.noreply.github.com> Date: Sun, 8 Sep 2024 08:22:12 +0200 Subject: [PATCH 3/4] feat: create a button to delete a project in the project form --- src/components/project_form.rs | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/src/components/project_form.rs b/src/components/project_form.rs index ee71abc..945fd70 100644 --- a/src/components/project_form.rs +++ b/src/components/project_form.rs @@ -1,10 +1,10 @@ use crate::models::project::{NewProject, Project}; -use crate::server::projects::{create_project, edit_project}; +use crate::query::{QueryErrors, QueryKey, QueryValue}; +use crate::server::projects::{create_project, delete_project, edit_project}; use dioxus::core_macro::{component, rsx}; use dioxus::dioxus_core::Element; use dioxus::prelude::*; use dioxus_query::prelude::use_query_client; -use crate::query::{QueryErrors, QueryKey, QueryValue}; #[component] pub(crate) fn ProjectForm(project: Option, on_successful_submit: EventHandler<()>) @@ -25,9 +25,7 @@ pub(crate) fn ProjectForm(project: Option, on_successful_submit: EventH } else { let _ = create_project(new_project).await; } - query_client.invalidate_queries(&[ - QueryKey::Projects - ]); + query_client.invalidate_queries(&[QueryKey::Projects]); on_successful_submit.call(()); } }, @@ -44,14 +42,31 @@ pub(crate) fn ProjectForm(project: Option, on_successful_submit: EventH input { name: "title", required: true, - initial_value: project.map(|project| project.title().to_owned()), + initial_value: project.as_ref().map(|project| project.title().to_owned()), r#type: "text", class: "py-2 px-3 grow bg-zinc-800/50 rounded-lg", id: "input_title" } } div { - class: "flex flex-row justify-end mt-auto", + class: "flex flex-row justify-between mt-auto", + button { + r#type: "button", + class: "py-2 px-4 bg-zinc-300/50 rounded-lg", + onclick: move |_| { + let project = project.clone(); + async move { + if let Some(project) = project { + let _ = delete_project(project.id()).await; + query_client.invalidate_queries(&[QueryKey::Projects]); + } + on_successful_submit.call(()); + } + }, + i { + class: "fa-solid fa-trash-can" + } + } button { r#type: "submit", class: "py-2 px-4 bg-zinc-300/50 rounded-lg", -- 2.47.1 From ca1f862499b1a1c6c0658d4da9110ae15962f2ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matou=C5=A1=20Volf?= <66163112+matous-volf@users.noreply.github.com> Date: Sun, 8 Sep 2024 08:35:06 +0200 Subject: [PATCH 4/4] feat: update a migration to make the task-project foreign key set null on delete --- migrations/2024-08-19-105140_create_tasks/up.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/migrations/2024-08-19-105140_create_tasks/up.sql b/migrations/2024-08-19-105140_create_tasks/up.sql index d9e7b2c..c14683b 100644 --- a/migrations/2024-08-19-105140_create_tasks/up.sql +++ b/migrations/2024-08-19-105140_create_tasks/up.sql @@ -6,6 +6,6 @@ CREATE TABLE "tasks"( "deadline" DATE, "category" JSONB NOT NULL, "project_id" INT4, - FOREIGN KEY ("project_id") REFERENCES "projects"("id") + FOREIGN KEY ("project_id") REFERENCES "projects"("id") ON DELETE SET NULL ); -- 2.47.1