feat: international string sorting #58

Merged
matous-volf merged 3 commits from feat/international-string-sorting into main 2024-09-19 20:19:11 +00:00
5 changed files with 82 additions and 26 deletions

31
Cargo.lock generated
View File

@ -387,6 +387,17 @@ dependencies = [
"piper", "piper",
] ]
[[package]]
name = "bstr"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "40723b8fb387abc38f4f4a37c09073622e41dd12327033091ef8950659e6dc0c"
dependencies = [
"memchr",
"regex-automata",
"serde",
]
[[package]] [[package]]
name = "bumpalo" name = "bumpalo"
version = "3.16.0" version = "3.16.0"
@ -1258,6 +1269,19 @@ version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a"
[[package]]
name = "feruca"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "25789ad6dfe8de73de0d96ea93ea8270dd15e2c51c3ee9212241da3701a343ee"
dependencies = [
"bincode",
"bstr",
"once_cell",
"rustc-hash",
"unicode-canonical-combining-class",
]
[[package]] [[package]]
name = "fixedbitset" name = "fixedbitset"
version = "0.4.2" version = "0.4.2"
@ -2991,6 +3015,7 @@ dependencies = [
"dioxus-query", "dioxus-query",
"dioxus-sdk", "dioxus-sdk",
"dotenvy", "dotenvy",
"feruca",
"serde", "serde",
"serde_json", "serde_json",
"serde_with", "serde_with",
@ -3295,6 +3320,12 @@ version = "0.3.15"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75"
[[package]]
name = "unicode-canonical-combining-class"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6925586af9268182c711e47c0853ed84131049efaca41776d0ca97f983865c32"
[[package]] [[package]]
name = "unicode-ident" name = "unicode-ident"
version = "1.0.12" version = "1.0.12"

View File

@ -28,6 +28,7 @@ dioxus-sdk = { version = "0.5.0", features = ["i18n"] }
unic-langid-impl = "0.9.5" unic-langid-impl = "0.9.5"
voca_rs = "1.15.2" voca_rs = "1.15.2"
diesel_migrations = { version = "2.2.0", features = ["postgres"] } diesel_migrations = { version = "2.2.0", features = ["postgres"] }
feruca = "0.10.0"
[features] [features]
default = [] default = []

View File

@ -6,15 +6,15 @@ use crate::models::task::NewTask;
use crate::models::task::Task; use crate::models::task::Task;
use crate::query::{QueryErrors, QueryKey, QueryValue}; use crate::query::{QueryErrors, QueryKey, QueryValue};
use crate::route::Route; use crate::route::Route;
use crate::server::projects::get_projects;
use crate::server::tasks::{create_task, delete_task, edit_task}; use crate::server::tasks::{create_task, delete_task, edit_task};
use chrono::Duration; use chrono::Duration;
use dioxus::core_macro::{component, rsx}; use dioxus::core_macro::{component, rsx};
use dioxus::dioxus_core::Element; use dioxus::dioxus_core::Element;
use dioxus::prelude::*; use dioxus::prelude::*;
use dioxus_query::prelude::use_query_client; use dioxus_query::prelude::{use_query_client, QueryResult};
use dioxus_sdk::i18n::use_i18; use dioxus_sdk::i18n::use_i18;
use dioxus_sdk::translate; use dioxus_sdk::translate;
use crate::query::projects::use_projects_query;
const REMINDER_OFFSETS: [Option<Duration>; 17] = [ const REMINDER_OFFSETS: [Option<Duration>; 17] = [
None, None,
@ -38,7 +38,7 @@ const REMINDER_OFFSETS: [Option<Duration>; 17] = [
#[component] #[component]
pub(crate) fn TaskForm(task: Option<Task>, on_successful_submit: EventHandler<()>) -> Element { pub(crate) fn TaskForm(task: Option<Task>, on_successful_submit: EventHandler<()>) -> Element {
let projects = use_server_future(get_projects)?.unwrap().unwrap(); let projects_query = use_projects_query();
let route = use_route::<Route>(); let route = use_route::<Route>();
let selected_category = use_signal(|| if let Some(task) = &task { let selected_category = use_signal(|| if let Some(task) = &task {
@ -178,6 +178,12 @@ pub(crate) fn TaskForm(task: Option<Task>, on_successful_submit: EventHandler<()
value: 0, value: 0,
{translate!(i18, "none")} {translate!(i18, "none")}
}, },
match projects_query.result().value() {
QueryResult::Ok(QueryValue::Projects(projects))
| QueryResult::Loading(Some(QueryValue::Projects(projects))) => {
let mut projects = projects.clone();
projects.sort();
rsx! {
for project in projects { for project in projects {
option { option {
value: project.id().to_string(), value: project.id().to_string(),
@ -187,6 +193,18 @@ pub(crate) fn TaskForm(task: Option<Task>, on_successful_submit: EventHandler<()
{project.title()} {project.title()}
} }
} }
}
},
QueryResult::Loading(None) => rsx! {
// TODO: Add a loading indicator.
},
QueryResult::Err(errors) => rsx! {
div {
"Errors occurred: {errors:?}"
}
},
value => panic!("Unexpected query result: {value:?}")
}
}, },
}, },
div { div {

View File

@ -1,12 +1,17 @@
use std::ops::Deref; use std::ops::Deref;
use std::str::FromStr; use std::str::FromStr;
use std::sync::Mutex;
use chrono::Locale; use chrono::Locale;
use dioxus::fullstack::once_cell::sync::Lazy;
use dioxus_sdk::i18n::Language; use dioxus_sdk::i18n::Language;
use feruca::Collator;
use unic_langid_impl::LanguageIdentifier; use unic_langid_impl::LanguageIdentifier;
const EN_US: &str = include_str!("en_us.json"); const EN_US: &str = include_str!("en_us.json");
const CS_CZ: &str = include_str!("cs_cz.json"); const CS_CZ: &str = include_str!("cs_cz.json");
pub(crate) static COLLATOR: Lazy<Mutex<Collator>> = Lazy::new(|| Mutex::new(Collator::default()));
coderabbitai[bot] commented 2024-09-19 20:14:48 +00:00 (Migrated from github.com)
Review

Excellent addition of the COLLATOR for internationalization support!

The introduction of the COLLATOR static variable is a great step towards enabling locale-aware string comparisons and sorting within the crate. The use of Lazy and Mutex ensures efficient initialization and thread safety.

Consider adding some documentation or comments to explain the purpose and usage of COLLATOR for future maintainers. Additionally, ensure that the feruca crate is properly versioned in the Cargo.toml file to avoid potential breaking changes in the future.

**Excellent addition of the `COLLATOR` for internationalization support!** The introduction of the `COLLATOR` static variable is a great step towards enabling locale-aware string comparisons and sorting within the crate. The use of `Lazy` and `Mutex` ensures efficient initialization and thread safety. Consider adding some documentation or comments to explain the purpose and usage of `COLLATOR` for future maintainers. Additionally, ensure that the `feruca` crate is properly versioned in the `Cargo.toml` file to avoid potential breaking changes in the future. <!-- This is an auto-generated comment by CodeRabbit -->
pub(crate) fn get_languages() -> Vec<Language> { pub(crate) fn get_languages() -> Vec<Language> {
Vec::from([EN_US, CS_CZ]).into_iter().map(|texts| Language::from_str(texts).unwrap()).collect() Vec::from([EN_US, CS_CZ]).into_iter().map(|texts| Language::from_str(texts).unwrap()).collect()
} }

View File

@ -4,6 +4,7 @@ use crate::schema::projects;
use diesel::prelude::*; use diesel::prelude::*;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use validator::Validate; use validator::Validate;
use crate::internationalization::COLLATOR;
const TITLE_LENGTH_MIN: u64 = 1; const TITLE_LENGTH_MIN: u64 = 1;
const TITLE_LENGTH_MAX: u64 = 255; const TITLE_LENGTH_MAX: u64 = 255;
@ -46,7 +47,7 @@ impl PartialOrd<Self> for Project {
impl Ord for Project { impl Ord for Project {
fn cmp(&self, other: &Self) -> Ordering { fn cmp(&self, other: &Self) -> Ordering {
self.title().cmp(other.title()) COLLATOR.lock().unwrap().collate(self.title(), other.title())
} }
} }