diff --git a/backend/Cargo.lock b/backend/Cargo.lock index e3e09eb..b6e26ad 100644 --- a/backend/Cargo.lock +++ b/backend/Cargo.lock @@ -82,6 +82,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "arrayvec" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" + [[package]] name = "arrayvec" version = "0.7.2" @@ -426,6 +432,7 @@ dependencies = [ "axum", "axum-extra", "booksman-orm", + "booksman-search", "clap", "dotenvy", "entity", @@ -454,6 +461,15 @@ dependencies = [ "serde", ] +[[package]] +name = "booksman-search" +version = "0.1.0" +dependencies = [ + "meilisearch-sdk", + "serde", + "tokio", +] + [[package]] name = "brotli" version = "3.3.4" @@ -505,6 +521,12 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c1db59621ec70f09c5e9b597b220c7a2b43611f4710dc03ceb8748637775692c" +[[package]] +name = "castaway" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2698f953def977c68f935bb0dfa959375ad4638570e969e2f1e9f433cbf1af6" + [[package]] name = "cc" version = "1.0.73" @@ -716,6 +738,37 @@ dependencies = [ "syn", ] +[[package]] +name = "curl" +version = "0.4.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "509bd11746c7ac09ebd19f0b17782eae80aadee26237658a6b4808afb5c11a22" +dependencies = [ + "curl-sys", + "libc", + "openssl-probe", + "openssl-sys", + "schannel", + "socket2", + "winapi", +] + +[[package]] +name = "curl-sys" +version = "0.4.59+curl-7.86.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6cfce34829f448b08f55b7db6d0009e23e2e86a34e8c2b366269bf5799b4a407" +dependencies = [ + "cc", + "libc", + "libnghttp2-sys", + "libz-sys", + "openssl-sys", + "pkg-config", + "vcpkg", + "winapi", +] + [[package]] name = "digest" version = "0.10.3" @@ -767,6 +820,9 @@ name = "either" version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" +dependencies = [ + "serde", +] [[package]] name = "encoding_rs" @@ -1292,7 +1348,43 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f0f7638c1e223529f1bfdc48c8b133b9e0b434094d1d28473161ee48b235f78" dependencies = [ - "nom", + "nom 7.1.1", +] + +[[package]] +name = "isahc" +version = "1.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "334e04b4d781f436dc315cb1e7515bd96826426345d498149e4bde36b67f8ee9" +dependencies = [ + "async-channel", + "castaway", + "crossbeam-utils", + "curl", + "curl-sys", + "encoding_rs", + "event-listener", + "futures-lite", + "http", + "log", + "mime", + "once_cell", + "polling", + "slab", + "sluice", + "tracing", + "tracing-futures", + "url", + "waker-fn", +] + +[[package]] +name = "iso8601-duration" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60b51dd97fa24074214b9eb14da518957573f4dec3189112610ae1ccec9ac464" +dependencies = [ + "nom 5.1.2", ] [[package]] @@ -1328,6 +1420,18 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "jsonwebtoken" +version = "8.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aa4b4af834c6cfd35d8763d359661b90f2e45d8f750a0849156c7f4671af09c" +dependencies = [ + "base64", + "ring", + "serde", + "serde_json", +] + [[package]] name = "kv-log-macro" version = "1.0.7" @@ -1349,12 +1453,35 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "03087c2bad5e1034e8cace5926dec053fb3790248370865f5117a7d0213354c8" +[[package]] +name = "lexical-core" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6607c62aa161d23d17a9072cc5da0be67cdfc89d3afb1e8d9c842bebc2525ffe" +dependencies = [ + "arrayvec 0.5.2", + "bitflags", + "cfg-if", + "ryu", + "static_assertions", +] + [[package]] name = "libc" version = "0.2.132" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8371e4e5341c3a96db127eb2465ac681ced4c433e01dd0e938adbef26ba93ba5" +[[package]] +name = "libnghttp2-sys" +version = "0.1.7+1.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57ed28aba195b38d5ff02b9170cbff627e336a20925e43b4945390401c5dc93f" +dependencies = [ + "cc", + "libc", +] + [[package]] name = "libsqlite3-sys" version = "0.24.2" @@ -1366,6 +1493,18 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "libz-sys" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9702761c3935f8cc2f101793272e202c72b99da8f4224a19ddcf1279a6450bbf" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + [[package]] name = "lock_api" version = "0.4.8" @@ -1416,6 +1555,30 @@ dependencies = [ "digest", ] +[[package]] +name = "meilisearch-sdk" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c0fab01f198149ac68362c48d2b332d3b0ce0a0241765fb430ea443c5d361e2" +dependencies = [ + "async-trait", + "either", + "futures", + "isahc", + "iso8601-duration", + "js-sys", + "jsonwebtoken", + "log", + "serde", + "serde_json", + "time 0.3.14", + "uuid", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "yaup", +] + [[package]] name = "memchr" version = "2.5.0" @@ -1519,6 +1682,17 @@ dependencies = [ "tempfile", ] +[[package]] +name = "nom" +version = "5.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffb4262d26ed83a1c0a33a38fe2bb15797329c85770da05e6b828ddb782627af" +dependencies = [ + "lexical-core", + "memchr", + "version_check", +] + [[package]] name = "nom" version = "7.1.1" @@ -2057,7 +2231,7 @@ version = "1.26.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ee9164faf726e4f3ece4978b25ca877ddc6802fa77f38cdccb32c7f805ecd70c" dependencies = [ - "arrayvec", + "arrayvec 0.7.2", "num-traits", "serde", ] @@ -2068,27 +2242,6 @@ version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" -[[package]] -name = "rustls" -version = "0.20.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aab8ee6c7097ed6057f43c187a62418d0c05a4bd5f18b3571db50ee0f9ce033" -dependencies = [ - "log", - "ring", - "sct", - "webpki", -] - -[[package]] -name = "rustls-pemfile" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0864aeff53f8c05aa08d86e5ef839d3dfcf07aeba2db32f12db0ef716e87bd55" -dependencies = [ - "base64", -] - [[package]] name = "rustversion" version = "1.0.9" @@ -2123,16 +2276,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" -[[package]] -name = "sct" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" -dependencies = [ - "ring", - "untrusted", -] - [[package]] name = "sea-orm" version = "0.9.2" @@ -2395,6 +2538,17 @@ dependencies = [ "autocfg", ] +[[package]] +name = "sluice" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d7400c0eff44aa2fcb5e31a5f24ba9716ed90138769e4977a2ba6014ae63eb5" +dependencies = [ + "async-channel", + "futures-core", + "futures-io", +] + [[package]] name = "smallvec" version = "1.9.0" @@ -2433,7 +2587,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4b7922be017ee70900be125523f38bdd644f4f06a1b16e8fa5a8ee8c34bffd4" dependencies = [ "itertools", - "nom", + "nom 7.1.1", "unicode_categories", ] @@ -2483,8 +2637,6 @@ dependencies = [ "paste", "percent-encoding", "rust_decimal", - "rustls", - "rustls-pemfile", "serde", "serde_json", "sha2", @@ -2497,7 +2649,6 @@ dependencies = [ "tokio-stream", "url", "uuid", - "webpki-roots", ] [[package]] @@ -2530,9 +2681,14 @@ dependencies = [ "once_cell", "tokio", "tokio-native-tls", - "tokio-rustls", ] +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + [[package]] name = "stringprep" version = "0.1.2" @@ -2670,6 +2826,7 @@ dependencies = [ "itoa", "libc", "num_threads", + "serde", "time-macros", ] @@ -2736,17 +2893,6 @@ dependencies = [ "tokio", ] -[[package]] -name = "tokio-rustls" -version = "0.23.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c43ee83903113e03984cb9e5cebe6c04a5116269e900e3ddba8f068a62adda59" -dependencies = [ - "rustls", - "tokio", - "webpki", -] - [[package]] name = "tokio-stream" version = "0.1.9" @@ -2864,6 +3010,16 @@ dependencies = [ "valuable", ] +[[package]] +name = "tracing-futures" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" +dependencies = [ + "pin-project", + "tracing", +] + [[package]] name = "tracing-log" version = "0.1.3" @@ -3107,25 +3263,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "webpki" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd" -dependencies = [ - "ring", - "untrusted", -] - -[[package]] -name = "webpki-roots" -version = "0.22.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1c760f0d366a6c24a02ed7816e23e691f5d92291f94d15e836006fd11b04daf" -dependencies = [ - "webpki", -] - [[package]] name = "weezl" version = "0.1.7" @@ -3223,3 +3360,13 @@ checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" dependencies = [ "winapi", ] + +[[package]] +name = "yaup" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a59e7d27bed43f7c37c25df5192ea9d435a8092a902e02203359ac9ce3e429d9" +dependencies = [ + "serde", + "url", +] diff --git a/backend/Cargo.toml b/backend/Cargo.toml index cf9d1cd..0cb004b 100644 --- a/backend/Cargo.toml +++ b/backend/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" [workspace] -members = [".", "entity", "migration", "orm", "api"] +members = [".", "entity", "migration", "orm", "search", "api"] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] diff --git a/backend/api/Cargo.toml b/backend/api/Cargo.toml index f1c0959..29c62b1 100644 --- a/backend/api/Cargo.toml +++ b/backend/api/Cargo.toml @@ -6,6 +6,7 @@ edition = "2021" [dependencies] booksman-orm = { path = "../orm" } +booksman-search = { path = "../search" } entity = { path = "../entity" } axum = "^0.5" axum-extra = { version = "^0.3", features = ["spa"] } diff --git a/backend/api/src/lib.rs b/backend/api/src/lib.rs index d39ea36..520ef72 100644 --- a/backend/api/src/lib.rs +++ b/backend/api/src/lib.rs @@ -269,70 +269,41 @@ async fn list_book( .await .expect("could not list books"); - let mut data_grouped: Vec<(i32,Vec)> = Vec::with_capacity(5); - for (key, group) in &books.0.into_iter().group_by(|x| x.id) { - data_grouped.push((key, group.collect())); - } - let mut resbooks: Vec = Vec::with_capacity(5); - for (id,group) in data_grouped.into_iter() { - let mut cover = group.clone().into_iter().clone().map(|u| u.cover).next(); + + for bookandmeta in books.0.into_iter() { + let mut cover = bookandmeta.clone().book.cover; if !cover.is_none() { -cover = Some(format!("http://localhost:8081/images/{}",cover.unwrap())); + cover = Some(format!("http://localhost:8081/images/{}",cover.unwrap())); } let bookui = BookUI{ - id, -title: group.clone().into_iter().map( |u| u.title).next().unwrap(), -open_library_key: group.clone().into_iter().map( |u| u.open_library_key).next(), -edition_count: group.clone().into_iter().clone().map(|u| u.edition_count).next(), -first_publish_year: group.clone().into_iter().clone().map(|u| u.first_publish_year).next(), -median_page_count: group.clone().into_iter().clone().map(|u| u.median_page_count).next(), -goodread_id: group.clone().into_iter().clone().map(|u| u.goodread_id).next(), -description: group.clone().into_iter().clone().map(|u| u.description).next(), -cover: cover.clone(), -location: group.clone().into_iter().clone().map(|u| u.location).next(), -time_added: group.clone().into_iter().clone().map(|u| u.time_added).next(), -rating: group.clone().into_iter().clone().map(|u| u.rating).next(), -comments: group.clone().into_iter().clone().map(|u| u.comments).next(), -author_name: Some(group.clone().into_iter().map(|u| u.author_name).collect()), -person: Some(group.clone().into_iter().map(|u| u.person).collect()), -place: Some(group.clone().into_iter().map(|u| u.place).collect()), -subject: Some(group.clone().into_iter().map(|u| u.subject).collect()), -time: Some(group.clone().into_iter().map(|u| u.time).collect()), -isbn: Some(group.clone().into_iter().map(|u| u.isbn).collect()), - + id: bookandmeta.clone().book.id, + title: bookandmeta.clone().book.title, + open_library_key: bookandmeta.clone().book.open_library_key, + edition_count: bookandmeta.clone().book.edition_count, + first_publish_year: bookandmeta.clone().book.first_publish_year, + median_page_count: bookandmeta.clone().book.median_page_count, + goodread_id: bookandmeta.clone().book.goodread_id, + description: bookandmeta.clone().book.description, + cover: cover.clone(), + location: bookandmeta.clone().book.location, + time_added: bookandmeta.clone().book.time_added, + rating: bookandmeta.clone().book.rating, + comments: bookandmeta.clone().book.comments, + author_name: Some(bookandmeta.clone().authors.into_iter().map(|u| u.author_name).collect() ), + person: Some(bookandmeta.clone().persons.into_iter().map(|u| u.person).collect()), + place: Some(bookandmeta.clone().places.into_iter().map(|u| u.place).collect()), + subject: Some(bookandmeta.clone().subjects.into_iter().map(|u| u.subject).collect()), + time: Some(bookandmeta.clone().times.into_iter().map(|u| u.time).collect()), + isbn: Some(bookandmeta.clone().isbns.into_iter().map(|u| u.isbn).collect()), }; resbooks.push(bookui); } let res = PaginatedBookUIList{ - num_pages: books.1 as u32, - books: resbooks + num_pages: books.1 as u32, + books: resbooks }; -/* let mut res: Vec = (books.0).iter() - .group_by(|x| (x.id, x.title.clone()) ).into_iter() - .map(|((id,title), group )| BookUI{ -id, -title, -open_library_key: group.map( |u| u.open_library_key.clone()).next(), -edition_count: group.map(|u| u.edition_count).next(), -first_publish_year: group.map(|u| u.first_publish_year).next(), -median_page_count: group.map(|u| u.median_page_count).next(), -goodread_id: group.map(|u| u.goodread_id.clone()).next(), -description: group.map(|u| u.description.clone()).next(), -cover: group.map(|u| u.cover.clone()).next(), -location: group.map(|u| u.location.clone()).next(), -time_added: group.map(|u| u.time_added.clone()).next(), -rating: group.map(|u| u.rating).next(), -comments: group.map(|u| u.comments.clone()).next(), -author_name: Some(group.map(|u| u.author_name.clone()).collect()), -person: Some(group.map(|u| u.person.clone()).collect()), -place: Some(group.map(|u| u.place.clone()).collect()), -subject: Some(group.map(|u| u.subject.clone()).collect()), -time: Some(group.map(|u| u.time.clone()).collect()), -isbn: Some(group.map(|u| u.isbn.clone()).collect()), - }).collect(); - */ return Json(res); // "success" } diff --git a/backend/migration/Cargo.toml b/backend/migration/Cargo.toml index f568183..ec4f27e 100644 --- a/backend/migration/Cargo.toml +++ b/backend/migration/Cargo.toml @@ -18,6 +18,6 @@ features = [ # Enable at least one `ASYNC_RUNTIME` and `DATABASE_DRIVER` feature if you want to run migration via CLI. # View the list of supported features at https://www.sea-ql.org/SeaORM/docs/install-and-config/database-and-async-runtime. # e.g. - "runtime-tokio-rustls", # `ASYNC_RUNTIME` feature + "runtime-tokio-native-tls", # `ASYNC_RUNTIME` feature "sqlx-sqlite", # `DATABASE_DRIVER` feature ] diff --git a/backend/orm/src/query.rs b/backend/orm/src/query.rs index e7980df..b931c68 100644 --- a/backend/orm/src/query.rs +++ b/backend/orm/src/query.rs @@ -27,6 +27,18 @@ pub struct BookAndMeta { pub time: String, pub isbn: String, } + + +#[derive(Clone)] +pub struct BookAndMetaV2 { + pub book: book::Model, + pub authors: Vec, + pub persons: Vec, + pub places: Vec, + pub subjects: Vec, + pub times: Vec, + pub isbns: Vec, +} //use ::entity::entities::prelude::Book; pub struct Query; @@ -64,33 +76,33 @@ pub async fn find_books_plus_meta_in_page( db: &DbConn, page: usize, posts_per_page: usize, - ) -> Result<(Vec, usize), DbErr> { + ) -> Result<(Vec, usize), DbErr> { // Setup paginator let books = Self::find_books_in_page(db,page,posts_per_page).await?; let book_ids: Vec = books.0.clone().into_iter().map(|b| b.id).collect(); - /* let paginator1 = Book::find().filter( - Condition::any() - .add(book::Column::Id.is_in(book_ids)) - ).find_with_related(Author).all(db).await?;*/ - let paginator2: Vec = Book::find() - .filter(Condition::any() - .add(book::Column::Id.is_in(book_ids))) - .join(JoinType::LeftJoin, book::Relation::BookAuthor.def()) - .join(JoinType::LeftJoin, book::Relation::BookPerson.def()) - .join(JoinType::LeftJoin, book::Relation::BookPlace.def()) - .join(JoinType::LeftJoin, book::Relation::BookSubject.def()) - .join(JoinType::LeftJoin, book::Relation::BookTime.def()) - .join(JoinType::LeftJoin, book::Relation::BookIsbn.def()) - .column_as(book_author::Column::AuthorName, "author_name") - .column_as(book_person::Column::Person, "person") - .column_as(book_place::Column::Place, "place") - .column_as(book_subject::Column::Subject, "subject") - .column_as(book_time::Column::Time, "time") - .column_as(book_isbn::Column::Isbn, "isbn") - .into_model::() - .all(db).await?; + let mut resbooks: Vec = Vec::with_capacity(book_ids.len()); + for book in books.0.iter() { + let bauthors: Vec = book.find_related(book_author::Entity).all(db).await?; + let bpersons: Vec = book.find_related(book_person::Entity).all(db).await?; + let bplaces: Vec = book.find_related(book_place::Entity).all(db).await?; + let bsubjects: Vec = book.find_related(book_subject::Entity).all(db).await?; + let btimes: Vec = book.find_related(book_time::Entity).all(db).await?; + let bisbns: Vec = book.find_related(book_isbn::Entity).all(db).await?; - Ok((paginator2,books.1)) + let bookandmeta = BookAndMetaV2 { + book: (book.clone()), + authors: bauthors, + persons: bpersons, + places: bplaces, + subjects: bsubjects, + times: btimes, + isbns: bisbns + }; + resbooks.push(bookandmeta); + + } + + Ok((resbooks,books.1)) } } diff --git a/backend/search/Cargo.toml b/backend/search/Cargo.toml new file mode 100644 index 0000000..bc57133 --- /dev/null +++ b/backend/search/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "booksman-search" +version = "0.1.0" +edition = "2021" +publish = false + +[dependencies] +serde = { version = "1", features = ["derive"] } +meilisearch-sdk = "0.20.1" +tokio = { version = "^1", features = ["full"] } + diff --git a/backend/search/src/lib.rs b/backend/search/src/lib.rs new file mode 100644 index 0000000..a00cede --- /dev/null +++ b/backend/search/src/lib.rs @@ -0,0 +1,30 @@ +use meilisearch_sdk::{client::*, search::*}; +use serde::{Serialize, Deserialize}; + + +#[derive(Serialize, Deserialize, Debug)] +struct Movie { + id: usize, + title: String, + genres: Vec, +} + +#[tokio::main] +async fn main() { + // Create a client (without sending any request so that can't fail) + let client = Client::new(MEILISEARCH_URL, MEILISEARCH_API_KEY); + + // An index is where the documents are stored. + let movies = client.index("movies"); + + // Add some movies in the index. If the index 'movies' does not exist, Meilisearch creates it when you first add the documents. + movies.add_documents(&[ + Movie { id: 1, title: String::from("Carol"), genres: vec!["Romance".to_string(), "Drama".to_string()] }, + Movie { id: 2, title: String::from("Wonder Woman"), genres: vec!["Action".to_string(), "Adventure".to_string()] }, + Movie { id: 3, title: String::from("Life of Pi"), genres: vec!["Adventure".to_string(), "Drama".to_string()] }, + Movie { id: 4, title: String::from("Mad Max"), genres: vec!["Adventure".to_string(), "Science Fiction".to_string()] }, + Movie { id: 5, title: String::from("Moana"), genres: vec!["Fantasy".to_string(), "Action".to_string()] }, + Movie { id: 6, title: String::from("Philadelphia"), genres: vec!["Drama".to_string()] }, + ], Some("id")).await.unwrap(); + +} diff --git a/frontend/src/main.rs b/frontend/src/main.rs index 75694c3..9eae6db 100644 --- a/frontend/src/main.rs +++ b/frontend/src/main.rs @@ -51,7 +51,9 @@ pub struct AppState { pub openlibrary: RcSignal, pub adding: RcSignal, pub updating: RcSignal, + pub displaying: RcSignal, pub addingbook: RcSignal, + pub displayingbook: RcSignal, } #[derive(Route)] @@ -413,6 +415,8 @@ fn App(cx: Scope) -> View { adding: create_rc_signal(bool::default()), updating: create_rc_signal(bool::default()), addingbook: create_rc_signal(BookUI::default()), + displaying: create_rc_signal(bool::default()), + displayingbook: create_rc_signal(BookUI::default()), }; provide_context(cx, app_state); view! {