add links
This commit is contained in:
1
migrations/20241104213550_links.down.sql
Normal file
1
migrations/20241104213550_links.down.sql
Normal file
@@ -0,0 +1 @@
|
||||
DROP TABLE IF EXISTS `links`;
|
||||
7
migrations/20241104213550_links.up.sql
Normal file
7
migrations/20241104213550_links.up.sql
Normal file
@@ -0,0 +1,7 @@
|
||||
CREATE TABLE IF NOT EXISTS links (
|
||||
id BIGINT UNSIGNED PRIMARY KEY NOT NULL AUTO_INCREMENT,
|
||||
name TEXT NOT NULL,
|
||||
link TEXT NOT NULL,
|
||||
position BIGINT NOT NULL DEFAULT 1,
|
||||
created_at DATETIME NOT NULL
|
||||
);
|
||||
@@ -2,7 +2,40 @@ use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct Link {
|
||||
id: u16,
|
||||
link: String,
|
||||
name: String,
|
||||
id: u64,
|
||||
pub link: String,
|
||||
pub name: String,
|
||||
position: i64,
|
||||
created_at: String,
|
||||
}
|
||||
|
||||
impl Link {
|
||||
#[cfg(feature = "ssr")]
|
||||
pub async fn insert(
|
||||
name: String,
|
||||
link: String,
|
||||
) -> Result<sqlx::mysql::MySqlQueryResult, sqlx::Error> {
|
||||
sqlx::query!(
|
||||
"INSERT INTO links (name, link, position, created_at) VALUES (?, ?, (SELECT COALESCE(MAX(position) + 1, 1) FROM links lin), ?)",
|
||||
name,
|
||||
link,
|
||||
chrono::Local::now().naive_local(),
|
||||
)
|
||||
.execute(crate::database::get_db())
|
||||
.await
|
||||
}
|
||||
|
||||
#[cfg(feature = "ssr")]
|
||||
pub async fn get_all() -> Result<Vec<Self>, sqlx::Error> {
|
||||
sqlx::query!("SELECT id, name, link, position, created_at FROM links ORDER BY position")
|
||||
.map(|x| Self {
|
||||
id: x.id,
|
||||
name: x.name,
|
||||
link: x.link,
|
||||
position: x.position,
|
||||
created_at: x.created_at.format("%d/%m/%Y %H:%M").to_string(),
|
||||
})
|
||||
.fetch_all(crate::database::get_db())
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
mod link;
|
||||
mod value;
|
||||
pub use link::Link;
|
||||
pub use value::Value;
|
||||
pub use value::OPTIONS;
|
||||
|
||||
@@ -1,23 +1,108 @@
|
||||
use leptos::*;
|
||||
//use leptos_meta::*;
|
||||
//use leptos_router::*;
|
||||
use leptos_router::*;
|
||||
|
||||
#[server(GetLinksAction, "/api", "GetJson")]
|
||||
#[tracing::instrument]
|
||||
pub async fn get_links() -> Result<Vec<crate::models::Link>, ServerFnError> {
|
||||
crate::models::Link::get_all().await.map_err(|x| {
|
||||
let err = format!("Error while posting a link: {x:?}");
|
||||
tracing::error!("{err}");
|
||||
ServerFnError::ServerError("Could not post a link, try again later".into())
|
||||
})
|
||||
}
|
||||
|
||||
#[server(LinkAction, "/api")]
|
||||
pub async fn add_value(name: String, link: String) -> Result<(), ServerFnError> {
|
||||
crate::models::Link::insert(name, link)
|
||||
.await
|
||||
.map(|_| ())
|
||||
.map_err(|x| {
|
||||
let err = format!("Error while posting a comment: {x:?}");
|
||||
tracing::error!("{err}");
|
||||
ServerFnError::ServerError("Could not post a comment, try again later".into())
|
||||
})
|
||||
}
|
||||
|
||||
#[component]
|
||||
pub fn Links() -> impl IntoView {
|
||||
let (show, set_show) = create_signal(false);
|
||||
let link_action = create_server_action::<LinkAction>();
|
||||
let result = link_action.version();
|
||||
let reset_form = create_rw_signal("");
|
||||
let links = create_resource(
|
||||
move || (result.get()),
|
||||
move |_| async move {
|
||||
reset_form.set("");
|
||||
set_show.set(false);
|
||||
get_links().await
|
||||
},
|
||||
);
|
||||
|
||||
let form = move || {
|
||||
show.get().then(|| {
|
||||
view! { <div class="my-0 mx-auto w-72 text-center">
|
||||
<h2 class="p-6 text-4xl">"Ajout d'un lien"</h2>
|
||||
<ActionForm action=link_action attr:class="border border-lime-500">
|
||||
<div>
|
||||
<label class="block mt-3 mb-1">"Nom"</label>
|
||||
<input type="text"
|
||||
name="name"
|
||||
prop:value=move || reset_form.get()
|
||||
class="text-center dark:bg-slate-800 focus:border-lime-500 dark:text-white px-2 py-2 w-60" />
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="block mt-3 mb-1">"Lien"</label>
|
||||
<input type="url"
|
||||
name="link"
|
||||
prop:value=move || reset_form.get()
|
||||
class="text-center dark:bg-slate-800 focus:border-lime-500 dark:text-white px-2 py-2 w-60" />
|
||||
</div>
|
||||
<div>
|
||||
<button type="submit" class="bg-lime-500 hover:bg-lime-400 text-black px-2 py-1 w-60 my-5">"Valider"</button>
|
||||
</div>
|
||||
</ActionForm>
|
||||
</div> }
|
||||
})
|
||||
};
|
||||
|
||||
view! {
|
||||
<ul class="flex gap-5 mt-5 justify-center">
|
||||
<Link link="aa".to_string() name="Mon Lien".to_string() />
|
||||
<Link link="aa".to_string() name="mon lien 2".to_string() />
|
||||
<Link link="aa".to_string() name="mon lien 3".to_string() />
|
||||
<Suspense fallback=move || view! {<p>"Loading Comments from the article"</p> }>
|
||||
<ErrorBoundary fallback=|_| {
|
||||
view! { <p class="error-messages text-xs-center">"Something went wrong."</p>}
|
||||
}>
|
||||
{move || links.get().map(move |x| x.map(move |c| {
|
||||
view! {
|
||||
<For each=move || c.clone().into_iter().enumerate()
|
||||
key=|(i, _)| *i
|
||||
children=move |(_, link)| {
|
||||
let link = create_rw_signal(link);
|
||||
view!{<Link link />}
|
||||
}/>
|
||||
}
|
||||
}))}
|
||||
</ErrorBoundary>
|
||||
</Suspense>
|
||||
</ul>
|
||||
|
||||
<div>
|
||||
<button on:click=move |_| {set_show.set(true)}>"Add"</button>
|
||||
{form}
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
#[component]
|
||||
fn Link(link: String, name: String) -> impl IntoView {
|
||||
fn Link(link: RwSignal<crate::models::Link>) -> impl IntoView {
|
||||
view! {
|
||||
<li>
|
||||
<a class="border border-lime-500 bg-lime-500 hover:bg-lime-400 text-black px-3 py-2 inline-block" href=link>{name}</a>
|
||||
<a class="border border-lime-500 bg-lime-500 hover:bg-lime-400 text-black px-3 py-2 inline-block"
|
||||
target="_blank"
|
||||
href={move || link.with(|x| x.link.to_string())}>
|
||||
{move || link.with(|x| x.name.to_string())}
|
||||
</a>
|
||||
</li>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,8 +19,14 @@ pub async fn add_value(device: String, value: String) -> Result<(), ServerFnErro
|
||||
#[component]
|
||||
pub fn FormValues() -> impl IntoView {
|
||||
let value_action = create_server_action::<ValueAction>();
|
||||
//let value = value_action.value();
|
||||
//let has_error = move || value.with(|val| matches!(val, Some(Err(_))));
|
||||
let result = value_action.version();
|
||||
let reset_value = create_rw_signal("");
|
||||
let _ = create_resource(
|
||||
move || (result.get()),
|
||||
move |_| async move {
|
||||
reset_value.set("");
|
||||
},
|
||||
);
|
||||
|
||||
view! {
|
||||
<div class="my-0 mx-auto w-72 text-center">
|
||||
@@ -37,7 +43,9 @@ pub fn FormValues() -> impl IntoView {
|
||||
</div>
|
||||
<div>
|
||||
<label class="block mt-3 mb-1">Valeur</label>
|
||||
<input type="text" name="value" type="number"
|
||||
<input name="value"
|
||||
type="number"
|
||||
prop:value=move || reset_value.get()
|
||||
class="text-center dark:bg-slate-800 focus:border-lime-500 dark:text-white px-2 py-2 w-60" />
|
||||
</div>
|
||||
<div>
|
||||
|
||||
Reference in New Issue
Block a user