+
{move || text.get()}
};
diff --git a/crates/ascend/src/components/problem_info.rs b/crates/ascend/src/components/problem_info.rs
index 3aeb7dc..86110d4 100644
--- a/crates/ascend/src/components/problem_info.rs
+++ b/crates/ascend/src/components/problem_info.rs
@@ -11,7 +11,7 @@ pub fn ProblemInfo(#[prop(into)] problem: Signal
) -> impl IntoV
// let set_by = Signal::derive(move || problem.read().set_by.clone());
view! {
-
+
//
//
@@ -23,7 +23,7 @@ pub fn ProblemInfo(#[prop(into)] problem: Signal
) -> impl IntoV
#[tracing::instrument(skip_all)]
fn NameValue(#[prop(into)] name: Signal, #[prop(into)] value: Signal) -> impl IntoView {
view! {
- {name.get()}
+ {name.get()}
{value.get()}
}
}
diff --git a/crates/ascend/src/models.rs b/crates/ascend/src/models.rs
index 6189ce5..3879ce4 100644
--- a/crates/ascend/src/models.rs
+++ b/crates/ascend/src/models.rs
@@ -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;
diff --git a/crates/ascend/src/models/semantics.rs b/crates/ascend/src/models/semantics.rs
index 840c521..56e8746 100644
--- a/crates/ascend/src/models/semantics.rs
+++ b/crates/ascend/src/models/semantics.rs
@@ -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())
}
diff --git a/crates/ascend/src/pages/wall.rs b/crates/ascend/src/pages/wall.rs
index 2f6a5ff..03a8f71 100644
--- a/crates/ascend/src/pages/wall.rs
+++ b/crates/ascend/src/pages/wall.rs
@@ -68,6 +68,7 @@ struct Context {
cb_click_hold: Callback,
cb_remove_hold_from_filter: Callback,
cb_next_problem: Callback<()>,
+ cb_set_problem: Callback,
cb_upsert_todays_attempt: Callback,
}
@@ -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 = 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 {
-
@@ -209,17 +215,21 @@ fn Transformations() -> impl IntoView {
let ctx = use_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! {
-
+
@@ -282,10 +292,10 @@ fn Filter() -> impl IntoView {
}
let problems_counter = {
- let name = view! {
{"Problems:"}
};
+ let name = view! {
{"Problems:"}
};
let value = view! {
{ctx.filtered_problems.read().len()}
};
view! {
-
+
{name} {value}
}
@@ -387,7 +397,7 @@ fn AttemptRadioGroup() -> impl IntoView {
attempt_radio_buttons.push(view! {
});
}
- view! {
{attempt_radio_buttons}
}
+ view! {
{attempt_radio_buttons}
}
}
#[component]
@@ -473,7 +483,7 @@ fn Wall() -> impl IntoView {
};
view! {
-
+
{cells}
}
@@ -521,13 +531,13 @@ fn Hold(
#[component]
fn Separator() -> impl IntoView {
- view! {
}
+ view! {
}
}
#[component]
fn Section(children: Children, #[prop(into)] title: MaybeProp
) -> impl IntoView {
view! {
-
+
{move || title.get()}
@@ -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
) -> Signal {
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::>()
+ .filter(|problem| filter_holds.iter().all(|hold_pos| problem.pattern.pattern.contains_key(hold_pos)))
+ .map(|problem| problem.clone())
+ .collect::>()
})
})
}
diff --git a/crates/ascend/src/server/migrations.rs b/crates/ascend/src/server/migrations.rs
index 3b20e6b..7e92a16 100644
--- a/crates/ascend/src/server/migrations.rs
+++ b/crates/ascend/src/server/migrations.rs
@@ -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> {
@@ -21,11 +22,95 @@ pub async fn run_migrations(db: &Database) -> Result<(), Box Result<(), Box> {
- 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::>();
+ let problems_dump = txn
+ .open_table(db::v2::TABLE_PROBLEMS)?
+ .iter()?
+ .map(|el| {
+ let (k, v) = el.unwrap();
+ (k.value(), v.value())
+ })
+ .collect::>();
+ let user_dump = txn
+ .open_table(db::v3::TABLE_USER)?
+ .iter()?
+ .map(|el| {
+ let (k, v) = el.unwrap();
+ (k.value(), v.value())
+ })
+ .collect::>();
+
+ 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?;
diff --git a/crates/ascend/src/server_functions.rs b/crates/ascend/src/server_functions.rs
index 12b68bc..7d1bcbe 100644
--- a/crates/ascend/src/server_functions.rs
+++ b/crates/ascend/src/server_functions.rs
@@ -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)]