wip
This commit is contained in:
parent
0a95aca872
commit
c15db2847d
@ -52,7 +52,7 @@ error_reporter = { version = "1" }
|
||||
getrandom = { version = "0.3.1" }
|
||||
|
||||
[dev-dependencies]
|
||||
test-try= "0.1"
|
||||
test-try = "0.1"
|
||||
|
||||
[dev-dependencies.serde_json]
|
||||
version = "1"
|
||||
|
@ -19,9 +19,9 @@ use leptos::prelude::*;
|
||||
#[component]
|
||||
pub fn OnHoverRed(children: Children) -> impl IntoView {
|
||||
view! {
|
||||
<div class="group relative">
|
||||
<div class="relative group">
|
||||
<div>{children()}</div>
|
||||
<div class="absolute inset-0 bg-red-500 opacity-0 group-hover:opacity-50"></div>
|
||||
<div class="absolute inset-0 bg-red-500 opacity-0 group-hover:opacity-50" />
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ pub fn Checkbox(checked: RwSignal<bool>, #[prop(into)] text: Signal<String>, #[p
|
||||
let unique_id = Oco::from(format!("checkbox-{}", uuid::Uuid::new_v4()));
|
||||
|
||||
let checkbox_view = view! {
|
||||
<div class="self-center text-white bg-white rounded-xs aspect-square mx-5 my-2.5">
|
||||
<div class="self-center my-2.5 mx-5 text-white bg-white rounded-xs aspect-square">
|
||||
<span class=("text-gray-950", move || checked.get())>
|
||||
<icons::Check />
|
||||
</span>
|
||||
@ -25,7 +25,7 @@ pub fn Checkbox(checked: RwSignal<bool>, #[prop(into)] text: Signal<String>, #[p
|
||||
};
|
||||
|
||||
let text_view = view! {
|
||||
<div class="self-center mx-5 my-2.5 uppercase w-full text-lg font-thin">
|
||||
<div class="self-center my-2.5 mx-5 w-full text-lg font-thin uppercase">
|
||||
{move || text.get()}
|
||||
</div>
|
||||
};
|
||||
|
@ -11,7 +11,7 @@ pub fn ProblemInfo(#[prop(into)] problem: Signal<models::Problem>) -> impl IntoV
|
||||
// let set_by = Signal::derive(move || problem.read().set_by.clone());
|
||||
|
||||
view! {
|
||||
<div class="grid grid-rows-none gap-y-1 gap-x-0.5 grid-cols-[auto_1fr]">
|
||||
<div class="grid grid-rows-none gap-x-0.5 gap-y-1 grid-cols-[auto_1fr]">
|
||||
<NameValue name="Method:" value=method />
|
||||
// <NameValue name="Name:" value=name />
|
||||
// <NameValue name="Set By:" value=set_by />
|
||||
@ -23,7 +23,7 @@ pub fn ProblemInfo(#[prop(into)] problem: Signal<models::Problem>) -> impl IntoV
|
||||
#[tracing::instrument(skip_all)]
|
||||
fn NameValue(#[prop(into)] name: Signal<String>, #[prop(into)] value: Signal<String>) -> impl IntoView {
|
||||
view! {
|
||||
<p class="font-light mr-4 text-right text-orange-300">{name.get()}</p>
|
||||
<p class="mr-4 font-light text-right text-orange-300">{name.get()}</p>
|
||||
<p class="text-white">{value.get()}</p>
|
||||
}
|
||||
}
|
||||
|
@ -27,8 +27,6 @@ pub mod v4 {
|
||||
use super::v3;
|
||||
use chrono::DateTime;
|
||||
use chrono::Utc;
|
||||
use derive_more::Display;
|
||||
use derive_more::FromStr;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
use std::collections::BTreeMap;
|
||||
|
@ -132,9 +132,11 @@ impl WallUid {
|
||||
pub(crate) fn create() -> Self {
|
||||
Self(uuid::Uuid::new_v4())
|
||||
}
|
||||
#[expect(dead_code)]
|
||||
pub(crate) fn min() -> Self {
|
||||
Self(uuid::Uuid::nil())
|
||||
}
|
||||
#[expect(dead_code)]
|
||||
pub(crate) fn max() -> Self {
|
||||
Self(uuid::Uuid::max())
|
||||
}
|
||||
|
@ -68,6 +68,7 @@ struct Context {
|
||||
cb_click_hold: Callback<models::HoldPosition>,
|
||||
cb_remove_hold_from_filter: Callback<models::HoldPosition>,
|
||||
cb_next_problem: Callback<()>,
|
||||
cb_set_problem: Callback<models::Problem>,
|
||||
cb_upsert_todays_attempt: Callback<server_functions::UpsertTodaysAttempt>,
|
||||
}
|
||||
|
||||
@ -91,7 +92,6 @@ fn Controller(
|
||||
});
|
||||
|
||||
// Derive signals
|
||||
let wall_uid = signals::wall_uid(wall);
|
||||
let user_interaction = signals::user_interaction(user_interactions.into(), problem.into());
|
||||
let filtered_problems = signals::filtered_problems(wall, filter_holds.into());
|
||||
let todays_attempt = signals::todays_attempt(user_interaction);
|
||||
@ -103,6 +103,11 @@ fn Controller(
|
||||
upsert_todays_attempt.dispatch(RonEncoded(attempt));
|
||||
});
|
||||
|
||||
// Callback: Set specific problem
|
||||
let cb_set_problem: Callback<models::Problem> = Callback::new(move |problem| {
|
||||
set_problem.set(Some(problem));
|
||||
});
|
||||
|
||||
// Callback: Set next problem to a random problem
|
||||
let cb_set_random_problem: Callback<()> = Callback::new(move |_| {
|
||||
// TODO: remove current problem from population
|
||||
@ -152,6 +157,7 @@ fn Controller(
|
||||
cb_upsert_todays_attempt,
|
||||
cb_remove_hold_from_filter,
|
||||
cb_next_problem: cb_set_random_problem,
|
||||
cb_set_problem,
|
||||
todays_attempt,
|
||||
filter_holds: filter_holds.into(),
|
||||
filtered_problems: filtered_problems.into(),
|
||||
@ -194,7 +200,7 @@ fn View() -> impl IntoView {
|
||||
</Section>
|
||||
</div>
|
||||
|
||||
<div class="flex-auto flex flex-row justify-end items-start px-2 pt-3">
|
||||
<div class="flex flex-row flex-auto justify-end items-start px-2 pt-3">
|
||||
<HoldsButton />
|
||||
</div>
|
||||
</div>
|
||||
@ -209,17 +215,21 @@ fn Transformations() -> impl IntoView {
|
||||
let ctx = use_context::<Context>().unwrap();
|
||||
|
||||
let on_left = Callback::new(move |()| {
|
||||
tracing::info!("left");
|
||||
tracing::debug!("left");
|
||||
});
|
||||
let on_mirror = Callback::new(move |()| {
|
||||
tracing::info!("mirror");
|
||||
tracing::debug!("mirror");
|
||||
if let Some(mut problem) = ctx.problem.get() {
|
||||
problem.pattern = problem.pattern.mirror();
|
||||
ctx.cb_set_problem.run(problem);
|
||||
}
|
||||
});
|
||||
let on_right = Callback::new(move |()| {
|
||||
tracing::info!("right");
|
||||
tracing::debug!("right");
|
||||
});
|
||||
|
||||
view! {
|
||||
<div class="flex flex-row justify-center gap-2">
|
||||
<div class="flex flex-row gap-2 justify-center">
|
||||
<Button icon=Icon::ChevronLeft disabled=true on_click=on_left />
|
||||
<Button icon=Icon::CodeBracketSquare on_click=on_mirror />
|
||||
<Button icon=Icon::ChevronRight on_click=on_right />
|
||||
@ -282,10 +292,10 @@ fn Filter() -> impl IntoView {
|
||||
}
|
||||
|
||||
let problems_counter = {
|
||||
let name = view! { <p class="font-light mr-4 text-right text-orange-300">{"Problems:"}</p> };
|
||||
let name = view! { <p class="mr-4 font-light text-right text-orange-300">{"Problems:"}</p> };
|
||||
let value = view! { <p class="text-white">{ctx.filtered_problems.read().len()}</p> };
|
||||
view! {
|
||||
<div class="grid grid-rows-none gap-y-1 gap-x-0.5 grid-cols-[auto_1fr]">
|
||||
<div class="grid grid-rows-none gap-x-0.5 gap-y-1 grid-cols-[auto_1fr]">
|
||||
{name} {value}
|
||||
</div>
|
||||
}
|
||||
@ -387,7 +397,7 @@ fn AttemptRadioGroup() -> impl IntoView {
|
||||
attempt_radio_buttons.push(view! { <AttemptRadioButton on:click=onclick variant selected=ui_toggle /> });
|
||||
}
|
||||
|
||||
view! { <div class="gap-2 flex flex-col justify-evenly 2xl:flex-row">{attempt_radio_buttons}</div> }
|
||||
view! { <div class="flex flex-col gap-2 justify-evenly 2xl:flex-row">{attempt_radio_buttons}</div> }
|
||||
}
|
||||
|
||||
#[component]
|
||||
@ -473,7 +483,7 @@ fn Wall() -> impl IntoView {
|
||||
};
|
||||
|
||||
view! {
|
||||
<div style=style class="p-1 grid gap-1">
|
||||
<div style=style class="grid gap-1 p-1">
|
||||
{cells}
|
||||
</div>
|
||||
}
|
||||
@ -521,13 +531,13 @@ fn Hold(
|
||||
|
||||
#[component]
|
||||
fn Separator() -> impl IntoView {
|
||||
view! { <div class="m-2 sm:m-3 md:m-4 h-4" /> }
|
||||
view! { <div class="m-2 h-4 sm:m-3 md:m-4" /> }
|
||||
}
|
||||
|
||||
#[component]
|
||||
fn Section(children: Children, #[prop(into)] title: MaybeProp<String>) -> impl IntoView {
|
||||
view! {
|
||||
<div class="bg-neutral-900 px-5 pt-3 pb-8 rounded-lg">
|
||||
<div class="px-5 pt-3 pb-8 rounded-lg bg-neutral-900">
|
||||
<div class="py-3 text-lg text-center text-orange-400 border-t border-orange-400">
|
||||
{move || title.get()}
|
||||
</div>
|
||||
@ -550,6 +560,7 @@ mod signals {
|
||||
Signal::derive(move || latest_attempt.read().as_ref().and_then(models::UserInteraction::todays_attempt))
|
||||
}
|
||||
|
||||
#[expect(dead_code)]
|
||||
pub fn wall_uid(wall: Signal<models::Wall>) -> Signal<models::WallUid> {
|
||||
Signal::derive(move || wall.read().uid)
|
||||
}
|
||||
@ -574,9 +585,9 @@ mod signals {
|
||||
wall.with(|wall| {
|
||||
wall.problems
|
||||
.iter()
|
||||
.filter(|(_, problem)| filter_holds.iter().all(|hold_pos| problem.pattern.pattern.contains_key(hold_pos)))
|
||||
.map(|(problem_uid, problem)| (*problem_uid, problem.clone()))
|
||||
.collect::<BTreeMap<models::ProblemUid, models::Problem>>()
|
||||
.filter(|problem| filter_holds.iter().all(|hold_pos| problem.pattern.pattern.contains_key(hold_pos)))
|
||||
.map(|problem| problem.clone())
|
||||
.collect::<BTreeSet<models::Problem>>()
|
||||
})
|
||||
})
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ use super::db::DatabaseOperationError;
|
||||
use super::db::{self};
|
||||
use crate::models;
|
||||
use redb::ReadableTable;
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
#[tracing::instrument(skip_all, err)]
|
||||
pub async fn run_migrations(db: &Database) -> Result<(), Box<dyn std::error::Error>> {
|
||||
@ -21,11 +22,95 @@ pub async fn run_migrations(db: &Database) -> Result<(), Box<dyn std::error::Err
|
||||
/// remove: problems table
|
||||
#[tracing::instrument(skip_all, err)]
|
||||
pub async fn migrate_to_v4(db: &Database) -> Result<(), Box<dyn std::error::Error>> {
|
||||
use redb::ReadableTableMetadata;
|
||||
tracing::warn!("MIGRATING TO VERSION 4");
|
||||
|
||||
todo!();
|
||||
db.write(|txn| Ok(())).await?;
|
||||
db.write(|txn| {
|
||||
let walls_dump = txn
|
||||
.open_table(db::v2::TABLE_WALLS)?
|
||||
.iter()?
|
||||
.map(|el| {
|
||||
let (k, v) = el.unwrap();
|
||||
(k.value(), v.value())
|
||||
})
|
||||
.collect::<BTreeMap<_, _>>();
|
||||
let problems_dump = txn
|
||||
.open_table(db::v2::TABLE_PROBLEMS)?
|
||||
.iter()?
|
||||
.map(|el| {
|
||||
let (k, v) = el.unwrap();
|
||||
(k.value(), v.value())
|
||||
})
|
||||
.collect::<BTreeMap<_, _>>();
|
||||
let user_dump = txn
|
||||
.open_table(db::v3::TABLE_USER)?
|
||||
.iter()?
|
||||
.map(|el| {
|
||||
let (k, v) = el.unwrap();
|
||||
(k.value(), v.value())
|
||||
})
|
||||
.collect::<BTreeMap<_, _>>();
|
||||
|
||||
txn.delete_table(db::v2::TABLE_WALLS)?;
|
||||
txn.delete_table(db::v2::TABLE_PROBLEMS)?;
|
||||
txn.delete_table(db::v3::TABLE_USER)?;
|
||||
|
||||
let mut new_walls_table = txn.open_table(db::current::TABLE_WALLS)?;
|
||||
let mut new_user_table = txn.open_table(db::current::TABLE_USER)?;
|
||||
|
||||
for (wall_uid, wall) in walls_dump.into_iter() {
|
||||
let models::v2::Wall {
|
||||
uid: _,
|
||||
rows,
|
||||
cols,
|
||||
holds,
|
||||
problems,
|
||||
} = wall;
|
||||
|
||||
let problems = problems
|
||||
.into_iter()
|
||||
.map(|problem_uid| {
|
||||
let old_prob = &problems_dump[&(wall_uid, problem_uid)];
|
||||
let method = old_prob.method;
|
||||
let problem = models::Problem {
|
||||
pattern: models::Pattern {
|
||||
pattern: old_prob.holds.clone(),
|
||||
},
|
||||
method,
|
||||
};
|
||||
problem
|
||||
})
|
||||
.collect();
|
||||
let wall = models::Wall {
|
||||
uid: wall_uid,
|
||||
wall_dimensions: models::WallDimensions { rows, cols },
|
||||
holds,
|
||||
problems,
|
||||
};
|
||||
|
||||
new_walls_table.insert(wall_uid, wall)?;
|
||||
}
|
||||
|
||||
for ((wall_uid, problem_uid), user_interaction) in user_dump.into_iter() {
|
||||
let old_prob = &problems_dump[&(wall_uid, problem_uid)];
|
||||
let problem = models::Problem {
|
||||
pattern: models::Pattern {
|
||||
pattern: old_prob.holds.clone(),
|
||||
},
|
||||
method: old_prob.method,
|
||||
};
|
||||
let key = (wall_uid, problem.clone());
|
||||
let value = models::UserInteraction {
|
||||
wall_uid,
|
||||
problem,
|
||||
attempted_on: user_interaction.attempted_on,
|
||||
is_favorite: user_interaction.is_favorite,
|
||||
};
|
||||
new_user_table.insert(key, value)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
})
|
||||
.await?;
|
||||
|
||||
db.set_version(db::Version { version: db::v4::VERSION }).await?;
|
||||
|
||||
|
@ -7,10 +7,8 @@ use derive_more::Error;
|
||||
use derive_more::From;
|
||||
use leptos::prelude::*;
|
||||
use leptos::server;
|
||||
use redb::ReadableTable;
|
||||
use server_fn::ServerFnError;
|
||||
use std::collections::BTreeMap;
|
||||
use type_toppings::IteratorExt;
|
||||
|
||||
#[server(
|
||||
input = Ron,
|
||||
@ -130,6 +128,7 @@ pub(crate) async fn get_user_interactions_for_wall(
|
||||
use crate::server::db::Database;
|
||||
use crate::server::db::DatabaseOperationError;
|
||||
use leptos::prelude::expect_context;
|
||||
use redb::ReadableTable;
|
||||
tracing::trace!("Enter");
|
||||
|
||||
#[derive(Debug, derive_more::Error, derive_more::Display, derive_more::From)]
|
||||
|
Loading…
x
Reference in New Issue
Block a user