feat: ability to delete a project (#37)

This commit is contained in:
Matouš Volf 2024-09-08 08:39:56 +02:00 committed by GitHub
commit 1c0b3a4196
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 51 additions and 16 deletions

View File

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

View File

@ -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<Project>, on_successful_submit: EventHandler<()>)
@ -25,9 +25,7 @@ pub(crate) fn ProjectForm(project: Option<Project>, 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<Project>, 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",

View File

@ -7,11 +7,17 @@ pub enum Error {
ServerInternal,
}
impl From<diesel::result::Error> 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 {
match self {
Error::ServerInternal => write!(f, "internal server error"),
Self::ServerInternal => write!(f, "internal server error"),
}
}
}
@ -22,7 +28,7 @@ impl FromStr for Error {
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(match s {
"internal server error" => Error::ServerInternal,
"internal server error" => Self::ServerInternal,
_ => return Err(()),
})
}

View File

@ -36,7 +36,7 @@ impl From<ValidationErrors> for ErrorVec<ProjectError> {
impl From<diesel::result::Error> 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<Self, Self::Err> {
Ok(ProjectError::Error(Error::ServerInternal))
Ok(Self::Error(Error::ServerInternal))
}
}

View File

@ -42,12 +42,12 @@ impl From<diesel::result::Error> 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<Self, Self::Err> {
Ok(TaskError::Error(Error::ServerInternal))
Ok(Self::Error(Error::ServerInternal))
}
}

View File

@ -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<ErrorVec<Error>>> {
use crate::schema::projects::dsl::*;
let mut connection = establish_database_connection()
.map_err::<ErrorVec<Error>, _>(|_| vec![Error::ServerInternal].into())?;
diesel::delete(projects.filter(id.eq(project_id))).execute(&mut connection)
.map_err::<ErrorVec<Error>, _>(|error| vec![error.into()].into())?;
Ok(())
}