diff --git a/.cargo/config.toml b/.cargo/config.toml index 797a3fd..72c3818 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -1,2 +1,11 @@ [target.'cfg(target_os = "linux")'] -rustflags = ["-C", "link-arg=-fuse-ld=mold"] \ No newline at end of file +rustflags = [ + "--cfg=web_sys_unstable_apis", + "-C", "link-arg=-fuse-ld=mold" +] + +[target.wasm32-unknown-unknown] +rustflags = ["--cfg=web_sys_unstable_apis"] + +[target.'cfg(target_os = "windows")'] +rustflags = ["--cfg=web_sys_unstable_apis"] diff --git a/Cargo.lock b/Cargo.lock index 3f10111..2bc1c85 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,26 +2,11 @@ # It is not intended for manual editing. version = 4 -[[package]] -name = "addr2line" -version = "0.24.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler2" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" - [[package]] name = "aho-corasick" -version = "1.1.3" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" dependencies = [ "memchr", ] @@ -42,22 +27,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1384d3fe1eecb464229fcf6eebb72306591c56bf27b373561489458a7c73027d" dependencies = [ "futures", - "thiserror 2.0.16", + "thiserror 2.0.17", "tokio", "wasm-bindgen-futures", ] [[package]] name = "anyhow" -version = "1.0.99" +version = "1.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0674a1ddeecb70197781e945de4b3b8ffb61fa939a5597bcf48503737663100" +checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" [[package]] name = "async-lock" -version = "3.4.1" +version = "3.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fd03604047cee9b6ce9de9f70c6cd540a0520c813cbd49bae61f33ab80ed1dc" +checksum = "290f7f2596bd5b78a9fec8088ccd89180d7f9f55b94b0576823bbbdc72ee8311" dependencies = [ "event-listener", "event-listener-strategy", @@ -89,9 +74,9 @@ checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" [[package]] name = "attribute-derive" -version = "0.10.3" +version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0053e96dd3bec5b4879c23a138d6ef26f2cb936c9cdc96274ac2b9ed44b5bb54" +checksum = "05832cdddc8f2650cc2cc187cc2e952b8c133a48eb055f35211f61ee81502d77" dependencies = [ "attribute-derive-macro", "derive-where", @@ -103,9 +88,9 @@ dependencies = [ [[package]] name = "attribute-derive-macro" -version = "0.10.3" +version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "463b53ad0fd5b460af4b1915fe045ff4d946d025fb6c4dc3337752eaa980f71b" +checksum = "0a7cdbbd4bd005c5d3e2e9c885e6fa575db4f4a3572335b974d8db853b6beb61" dependencies = [ "collection_literals", "interpolator", @@ -125,9 +110,9 @@ checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "aws-config" -version = "1.8.6" +version = "1.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bc1b40fb26027769f16960d2f4a6bc20c4bb755d403e552c8c1a73af433c246" +checksum = "96571e6996817bf3d58f6b569e4b9fd2e9d2fcf9f7424eed07b2ce9bb87535e5" dependencies = [ "aws-credential-types", "aws-runtime", @@ -144,7 +129,7 @@ dependencies = [ "bytes", "fastrand", "hex", - "http 1.3.1", + "http 1.4.0", "ring", "time", "tokio", @@ -155,9 +140,9 @@ dependencies = [ [[package]] name = "aws-credential-types" -version = "1.2.6" +version = "1.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d025db5d9f52cbc413b167136afb3d8aeea708c0d8884783cf6253be5e22f6f2" +checksum = "3cd362783681b15d136480ad555a099e82ecd8e2d10a841e14dfd0078d67fee3" dependencies = [ "aws-smithy-async", "aws-smithy-runtime-api", @@ -167,9 +152,9 @@ dependencies = [ [[package]] name = "aws-lc-rs" -version = "1.13.3" +version = "1.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c953fe1ba023e6b7730c0d4b031d06f267f23a46167dcbd40316644b10a17ba" +checksum = "6a88aab2464f1f25453baa7a07c84c5b7684e274054ba06817f382357f77a288" dependencies = [ "aws-lc-sys", "zeroize", @@ -177,11 +162,10 @@ dependencies = [ [[package]] name = "aws-lc-sys" -version = "0.30.0" +version = "0.35.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbfd150b5dbdb988bcc8fb1fe787eb6b7ee6180ca24da683b61ea5405f3d43ff" +checksum = "b45afffdee1e7c9126814751f88dddc747f41d91da16c9551a0f1e8a11e788a1" dependencies = [ - "bindgen", "cc", "cmake", "dunce", @@ -190,9 +174,9 @@ dependencies = [ [[package]] name = "aws-runtime" -version = "1.5.10" +version = "1.5.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c034a1bc1d70e16e7f4e4caf7e9f7693e4c9c24cd91cf17c2a0b21abaebc7c8b" +checksum = "d81b5b2898f6798ad58f484856768bca817e3cd9de0974c24ae0f1113fe88f1b" dependencies = [ "aws-credential-types", "aws-sigv4", @@ -214,9 +198,9 @@ dependencies = [ [[package]] name = "aws-sdk-dynamodb" -version = "1.92.0" +version = "1.101.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c1d9a7084cc5b14acae411d19f33a693fdb06ac55044705deb88844c8b58aa9" +checksum = "b6f98cd9e5f2fc790aff1f393bc3c8680deea31c05d3c6f23b625cdc50b1b6b4" dependencies = [ "aws-credential-types", "aws-runtime", @@ -236,9 +220,9 @@ dependencies = [ [[package]] name = "aws-sdk-sso" -version = "1.83.0" +version = "1.91.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "643cd43af212d2a1c4dedff6f044d7e1961e5d9e7cfe773d70f31d9842413886" +checksum = "8ee6402a36f27b52fe67661c6732d684b2635152b676aa2babbfb5204f99115d" dependencies = [ "aws-credential-types", "aws-runtime", @@ -258,9 +242,9 @@ dependencies = [ [[package]] name = "aws-sdk-ssooidc" -version = "1.84.0" +version = "1.93.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20ec4a95bd48e0db7a424356a161f8d87bd6a4f0af37204775f0da03d9e39fc3" +checksum = "a45a7f750bbd170ee3677671ad782d90b894548f4e4ae168302c57ec9de5cb3e" dependencies = [ "aws-credential-types", "aws-runtime", @@ -280,9 +264,9 @@ dependencies = [ [[package]] name = "aws-sdk-sts" -version = "1.85.0" +version = "1.95.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "410309ad0df4606bc721aff0d89c3407682845453247213a0ccc5ff8801ee107" +checksum = "55542378e419558e6b1f398ca70adb0b2088077e79ad9f14eb09441f2f7b2164" dependencies = [ "aws-credential-types", "aws-runtime", @@ -303,9 +287,9 @@ dependencies = [ [[package]] name = "aws-sigv4" -version = "1.3.4" +version = "1.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "084c34162187d39e3740cb635acd73c4e3a551a36146ad6fe8883c929c9f876c" +checksum = "69e523e1c4e8e7e8ff219d732988e22bfeae8a1cafdbe6d9eca1546fa080be7c" dependencies = [ "aws-credential-types", "aws-smithy-http", @@ -316,7 +300,7 @@ dependencies = [ "hex", "hmac", "http 0.2.12", - "http 1.3.1", + "http 1.4.0", "percent-encoding", "sha2", "time", @@ -325,9 +309,9 @@ dependencies = [ [[package]] name = "aws-smithy-async" -version = "1.2.5" +version = "1.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e190749ea56f8c42bf15dd76c65e14f8f765233e6df9b0506d9d934ebef867c" +checksum = "9ee19095c7c4dda59f1697d028ce704c24b2d33c6718790c7f1d5a3015b4107c" dependencies = [ "futures-util", "pin-project-lite", @@ -336,17 +320,18 @@ dependencies = [ [[package]] name = "aws-smithy-http" -version = "0.62.3" +version = "0.62.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c4dacf2d38996cf729f55e7a762b30918229917eca115de45dfa8dfb97796c9" +checksum = "826141069295752372f8203c17f28e30c464d22899a43a0c9fd9c458d469c88b" dependencies = [ "aws-smithy-runtime-api", "aws-smithy-types", "bytes", "bytes-utils", "futures-core", + "futures-util", "http 0.2.12", - "http 1.3.1", + "http 1.4.0", "http-body 0.4.6", "percent-encoding", "pin-project-lite", @@ -356,57 +341,57 @@ dependencies = [ [[package]] name = "aws-smithy-http-client" -version = "1.1.1" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147e8eea63a40315d704b97bf9bc9b8c1402ae94f89d5ad6f7550d963309da1b" +checksum = "59e62db736db19c488966c8d787f52e6270be565727236fd5579eaa301e7bc4a" dependencies = [ "aws-smithy-async", "aws-smithy-runtime-api", "aws-smithy-types", "h2 0.3.27", - "h2 0.4.12", + "h2 0.4.13", "http 0.2.12", - "http 1.3.1", + "http 1.4.0", "http-body 0.4.6", "hyper 0.14.32", - "hyper 1.7.0", + "hyper 1.8.1", "hyper-rustls 0.24.2", "hyper-rustls 0.27.7", "hyper-util", "pin-project-lite", "rustls 0.21.12", - "rustls 0.23.31", - "rustls-native-certs 0.8.1", + "rustls 0.23.36", + "rustls-native-certs", "rustls-pki-types", "tokio", - "tokio-rustls 0.26.2", + "tokio-rustls 0.26.4", "tower", "tracing", ] [[package]] name = "aws-smithy-json" -version = "0.61.5" +version = "0.61.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eaa31b350998e703e9826b2104dd6f63be0508666e1aba88137af060e8944047" +checksum = "49fa1213db31ac95288d981476f78d05d9cbb0353d22cdf3472cc05bb02f6551" dependencies = [ "aws-smithy-types", ] [[package]] name = "aws-smithy-observability" -version = "0.1.3" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9364d5989ac4dd918e5cc4c4bdcc61c9be17dcd2586ea7f69e348fc7c6cab393" +checksum = "17f616c3f2260612fe44cede278bafa18e73e6479c4e393e2c4518cf2a9a228a" dependencies = [ "aws-smithy-runtime-api", ] [[package]] name = "aws-smithy-query" -version = "0.60.7" +version = "0.60.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2fbd61ceb3fe8a1cb7352e42689cec5335833cd9f94103a61e98f9bb61c64bb" +checksum = "ae5d689cf437eae90460e944a58b5668530d433b4ff85789e69d2f2a556e057d" dependencies = [ "aws-smithy-types", "urlencoding", @@ -414,9 +399,9 @@ dependencies = [ [[package]] name = "aws-smithy-runtime" -version = "1.9.1" +version = "1.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3946acbe1ead1301ba6862e712c7903ca9bb230bdf1fbd1b5ac54158ef2ab1f" +checksum = "a392db6c583ea4a912538afb86b7be7c5d8887d91604f50eb55c262ee1b4a5f5" dependencies = [ "aws-smithy-async", "aws-smithy-http", @@ -427,7 +412,7 @@ dependencies = [ "bytes", "fastrand", "http 0.2.12", - "http 1.3.1", + "http 1.4.0", "http-body 0.4.6", "http-body 1.0.1", "pin-project-lite", @@ -438,15 +423,15 @@ dependencies = [ [[package]] name = "aws-smithy-runtime-api" -version = "1.9.0" +version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07f5e0fc8a6b3f2303f331b94504bbf754d85488f402d6f1dd7a6080f99afe56" +checksum = "ab0d43d899f9e508300e587bf582ba54c27a452dd0a9ea294690669138ae14a2" dependencies = [ "aws-smithy-async", "aws-smithy-types", "bytes", "http 0.2.12", - "http 1.3.1", + "http 1.4.0", "pin-project-lite", "tokio", "tracing", @@ -455,16 +440,16 @@ dependencies = [ [[package]] name = "aws-smithy-types" -version = "1.3.2" +version = "1.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d498595448e43de7f4296b7b7a18a8a02c61ec9349128c80a368f7c3b4ab11a8" +checksum = "905cb13a9895626d49cf2ced759b062d913834c7482c38e49557eac4e6193f01" dependencies = [ "base64-simd", "bytes", "bytes-utils", "futures-core", "http 0.2.12", - "http 1.3.1", + "http 1.4.0", "http-body 0.4.6", "http-body 1.0.1", "http-body-util", @@ -481,18 +466,18 @@ dependencies = [ [[package]] name = "aws-smithy-xml" -version = "0.60.10" +version = "0.60.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3db87b96cb1b16c024980f133968d52882ca0daaee3a086c6decc500f6c99728" +checksum = "11b2f670422ff42bf7065031e72b45bc52a3508bd089f743ea90731ca2b6ea57" dependencies = [ "xmlparser", ] [[package]] name = "aws-types" -version = "1.3.8" +version = "1.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b069d19bf01e46298eaedd7c6f283fe565a59263e53eebec945f3e6398f42390" +checksum = "1d980627d2dd7bfc32a3c025685a033eeab8d365cc840c631ef59d1b8f428164" dependencies = [ "aws-credential-types", "aws-smithy-async", @@ -504,19 +489,19 @@ dependencies = [ [[package]] name = "axum" -version = "0.8.4" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "021e862c184ae977658b36c4500f7feac3221ca5da43e3f25bd04ab6c79a29b5" +checksum = "8b52af3cb4058c895d37317bb27508dccc8e5f2d39454016b297bf4a400597b8" dependencies = [ "axum-core", "base64 0.22.1", "bytes", "form_urlencoded", "futures-util", - "http 1.3.1", + "http 1.4.0", "http-body 1.0.1", "http-body-util", - "hyper 1.7.0", + "hyper 1.8.1", "hyper-util", "itoa", "matchit", @@ -525,8 +510,7 @@ dependencies = [ "multer", "percent-encoding", "pin-project-lite", - "rustversion", - "serde", + "serde_core", "serde_json", "serde_path_to_error", "serde_urlencoded", @@ -542,39 +526,23 @@ dependencies = [ [[package]] name = "axum-core" -version = "0.5.2" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68464cd0412f486726fb3373129ef5d2993f90c34bc2bc1c1e9943b2f4fc7ca6" +checksum = "08c78f31d7b1291f7ee735c1c6780ccde7785daae9a9206026862dab7d8792d1" dependencies = [ "bytes", "futures-core", - "http 1.3.1", + "http 1.4.0", "http-body 1.0.1", "http-body-util", "mime", "pin-project-lite", - "rustversion", "sync_wrapper", "tower-layer", "tower-service", "tracing", ] -[[package]] -name = "backtrace" -version = "0.3.75" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002" -dependencies = [ - "addr2line", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", - "windows-targets 0.52.6", -] - [[package]] name = "base16" version = "0.2.1" @@ -603,34 +571,11 @@ dependencies = [ "vsimd", ] -[[package]] -name = "bindgen" -version = "0.69.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271383c67ccabffb7381723dea0672a673f292304fcb45c01cc648c7a8d58088" -dependencies = [ - "bitflags", - "cexpr", - "clang-sys", - "itertools 0.12.1", - "lazy_static", - "lazycell", - "log", - "prettyplease", - "proc-macro2", - "quote", - "regex", - "rustc-hash 1.1.0", - "shlex", - "syn", - "which", -] - [[package]] name = "bitflags" -version = "2.9.4" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394" +checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" [[package]] name = "block-buffer" @@ -642,16 +587,41 @@ dependencies = [ ] [[package]] -name = "bumpalo" -version = "3.19.0" +name = "bon" +version = "3.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" +checksum = "234655ec178edd82b891e262ea7cf71f6584bcd09eff94db786be23f1821825c" +dependencies = [ + "bon-macros", + "rustversion", +] + +[[package]] +name = "bon-macros" +version = "3.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89ec27229c38ed0eb3c0feee3d2c1d6a4379ae44f418a29a658890e062d8f365" +dependencies = [ + "darling 0.23.0", + "ident_case", + "prettyplease", + "proc-macro2", + "quote", + "rustversion", + "syn", +] + +[[package]] +name = "bumpalo" +version = "3.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510" [[package]] name = "bytes" -version = "1.10.1" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" +checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3" [[package]] name = "bytes-utils" @@ -665,15 +635,15 @@ dependencies = [ [[package]] name = "camino" -version = "1.1.12" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd0b03af37dad7a14518b7691d81acb0f8222604ad3d1b02f6b4bed5188c0cd5" +checksum = "e629a66d692cb9ff1a1c664e41771b3dcaf961985a9774c0eb0bd1b51cf60a48" [[package]] name = "cc" -version = "1.2.35" +version = "1.2.52" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "590f9024a68a8c40351881787f1934dc11afd69090f5edb6831464694d836ea3" +checksum = "cd4932aefd12402b36c60956a4fe0035421f544799057659ff86f923657aada3" dependencies = [ "find-msvc-tools", "jobserver", @@ -681,20 +651,11 @@ dependencies = [ "shlex", ] -[[package]] -name = "cexpr" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" -dependencies = [ - "nom", -] - [[package]] name = "cfg-if" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "chrono" @@ -707,45 +668,34 @@ dependencies = [ "num-traits", "serde", "wasm-bindgen", - "windows-link 0.2.0", -] - -[[package]] -name = "clang-sys" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" -dependencies = [ - "glob", - "libc", - "libloading", + "windows-link", ] [[package]] name = "cmake" -version = "0.1.54" +version = "0.1.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7caa3f9de89ddbe2c607f4101924c5abec803763ae9534e4f4d7d8f84aa81f0" +checksum = "75443c44cd6b379beb8c5b45d85d0773baf31cce901fe7bb252f4eff3008ef7d" dependencies = [ "cc", ] [[package]] name = "codee" -version = "0.3.2" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd8bbfdadf2f8999c6e404697bc08016dce4a3d77dec465b36c9a0652fdb3327" +checksum = "a9dbbdc4b4d349732bc6690de10a9de952bd39ba6a065c586e26600b6b0b91f5" dependencies = [ "serde", "serde_json", - "thiserror 2.0.16", + "thiserror 2.0.17", ] [[package]] name = "collection_literals" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b3f65b8fb8e88ba339f7d23a390fe1b0896217da05e2a66c584c9b29a91df8" +checksum = "2550f75b8cfac212855f6b1885455df8eaee8fe8e246b647d69146142e016084" [[package]] name = "concurrent-queue" @@ -758,13 +708,13 @@ dependencies = [ [[package]] name = "config" -version = "0.15.15" +version = "0.15.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0faa974509d38b33ff89282db9c3295707ccf031727c0de9772038ec526852ba" +checksum = "b30fa8254caad766fc03cb0ccae691e14bf3bd72bfff27f72802ce729551b3d6" dependencies = [ "convert_case 0.6.0", "pathdiff", - "serde", + "serde_core", "toml", "winnow", ] @@ -781,15 +731,15 @@ dependencies = [ [[package]] name = "const-str" -version = "0.6.4" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "451d0640545a0553814b4c646eb549343561618838e9b42495f466131fe3ad49" +checksum = "b0664d2867b4a32697dfe655557f5c3b187e9b605b38612a748e5ec99811d160" [[package]] name = "const_format" -version = "0.2.34" +version = "0.2.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "126f97965c8ad46d6d9163268ff28432e8f6a1196a55578867832e3049df63dd" +checksum = "7faa7469a93a566e9ccc1c73fe783b4a65c274c5ace346038dca9c39fe0030ad" dependencies = [ "const_format_proc_macros", ] @@ -830,13 +780,12 @@ dependencies = [ ] [[package]] -name = "core-foundation" -version = "0.9.4" +name = "convert_case" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +checksum = "633458d4ef8c78b72454de2d54fd6ab2e60f9e02be22f3c6104cdc8a4e0fceb9" dependencies = [ - "core-foundation-sys", - "libc", + "unicode-segmentation", ] [[package]] @@ -872,9 +821,9 @@ checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "crypto-common" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" dependencies = [ "generic-array", "typenum", @@ -886,8 +835,18 @@ version = "0.20.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" dependencies = [ - "darling_core", - "darling_macro", + "darling_core 0.20.11", + "darling_macro 0.20.11", +] + +[[package]] +name = "darling" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25ae13da2f202d56bd7f91c25fba009e7717a1e4a1cc98a76d844b65ae912e9d" +dependencies = [ + "darling_core 0.23.0", + "darling_macro 0.23.0", ] [[package]] @@ -904,13 +863,37 @@ dependencies = [ "syn", ] +[[package]] +name = "darling_core" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9865a50f7c335f53564bb694ef660825eb8610e0a53d3e11bf1b0d3df31e03b0" +dependencies = [ + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn", +] + [[package]] name = "darling_macro" version = "0.20.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" dependencies = [ - "darling_core", + "darling_core 0.20.11", + "quote", + "syn", +] + +[[package]] +name = "darling_macro" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d" +dependencies = [ + "darling_core 0.23.0", "quote", "syn", ] @@ -941,7 +924,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e0df63c21a4383f94bd5388564829423f35c316aed85dc4f8427aded372c7c0d" dependencies = [ - "darling", + "darling 0.20.11", "proc-macro2", "quote", "syn", @@ -949,9 +932,9 @@ dependencies = [ [[package]] name = "deranged" -version = "0.5.3" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d630bccd429a5bb5a64b5e94f693bfc48c9f8566418fda4c494cc94f911f87cc" +checksum = "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587" dependencies = [ "powerfmt", ] @@ -1040,12 +1023,12 @@ checksum = "a1731451909bde27714eacba19c2566362a7f35224f52b153d3f42cf60f72472" [[package]] name = "errno" -version = "0.3.13" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "778e2ac28f6c47af28e4907f13ffd1e1ddbd400980a9abd7c8df189bf578a5ad" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -1077,9 +1060,9 @@ checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" [[package]] name = "find-msvc-tools" -version = "0.1.0" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e178e4fba8a2726903f6ba98a6d221e76f9c12c650d5dc0e6afdc50677b49650" +checksum = "f449e6c6c08c865631d4890cfacf252b3d396c9bcc83adb6623cdb02a8336c41" [[package]] name = "fnv" @@ -1211,36 +1194,24 @@ dependencies = [ "cfg-if", "js-sys", "libc", - "wasi 0.11.1+wasi-snapshot-preview1", + "wasi", "wasm-bindgen", ] [[package]] name = "getrandom" -version = "0.3.3" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" dependencies = [ "cfg-if", "js-sys", "libc", "r-efi", - "wasi 0.14.3+wasi-0.2.4", + "wasip2", "wasm-bindgen", ] -[[package]] -name = "gimli" -version = "0.31.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" - -[[package]] -name = "glob" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" - [[package]] name = "gloo-net" version = "0.6.0" @@ -1251,7 +1222,7 @@ dependencies = [ "futures-core", "futures-sink", "gloo-utils", - "http 1.3.1", + "http 1.4.0", "js-sys", "pin-project", "serde", @@ -1302,16 +1273,16 @@ dependencies = [ [[package]] name = "h2" -version = "0.4.12" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3c0b69cfcb4e1b9f1bf2f53f95f766e4661169728ec61cd3fe5a0166f2d1386" +checksum = "2f44da3a8150a6703ed5d34e164b875fd14c2cdab9af1252a9a1020bde2bdc54" dependencies = [ "atomic-waker", "bytes", "fnv", "futures-core", "futures-sink", - "http 1.3.1", + "http 1.4.0", "indexmap", "slab", "tokio", @@ -1327,9 +1298,9 @@ checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" [[package]] name = "hashbrown" -version = "0.15.5" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" [[package]] name = "hermit-abi" @@ -1352,15 +1323,6 @@ dependencies = [ "digest", ] -[[package]] -name = "home" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf" -dependencies = [ - "windows-sys 0.59.0", -] - [[package]] name = "html-escape" version = "0.2.13" @@ -1383,12 +1345,11 @@ dependencies = [ [[package]] name = "http" -version = "1.3.1" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" +checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" dependencies = [ "bytes", - "fnv", "itoa", ] @@ -1410,7 +1371,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", - "http 1.3.1", + "http 1.4.0", ] [[package]] @@ -1421,7 +1382,7 @@ checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" dependencies = [ "bytes", "futures-core", - "http 1.3.1", + "http 1.4.0", "http-body 1.0.1", "pin-project-lite", ] @@ -1486,16 +1447,16 @@ dependencies = [ [[package]] name = "hyper" -version = "1.7.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb3aa54a13a0dfe7fbe3a59e0c76093041720fdc77b110cc0fc260fafb4dc51e" +checksum = "2ab2d4f250c3d7b1c9fcdff1cece94ea4e2dfbec68614f7b87cb205f24ca9d11" dependencies = [ "atomic-waker", "bytes", "futures-channel", "futures-core", - "h2 0.4.12", - "http 1.3.1", + "h2 0.4.13", + "http 1.4.0", "http-body 1.0.1", "httparse", "httpdate", @@ -1518,7 +1479,6 @@ dependencies = [ "hyper 0.14.32", "log", "rustls 0.21.12", - "rustls-native-certs 0.6.3", "tokio", "tokio-rustls 0.24.1", ] @@ -1529,36 +1489,36 @@ version = "0.27.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" dependencies = [ - "http 1.3.1", - "hyper 1.7.0", + "http 1.4.0", + "hyper 1.8.1", "hyper-util", - "rustls 0.23.31", - "rustls-native-certs 0.8.1", + "rustls 0.23.36", + "rustls-native-certs", "rustls-pki-types", "tokio", - "tokio-rustls 0.26.2", + "tokio-rustls 0.26.4", "tower-service", ] [[package]] name = "hyper-util" -version = "0.1.16" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d9b05277c7e8da2c93a568989bb6207bef0112e8d17df7a6eda4a3cf143bc5e" +checksum = "727805d60e7938b76b826a6ef209eb70eaa1812794f9424d4a4e2d740662df5f" dependencies = [ "base64 0.22.1", "bytes", "futures-channel", "futures-core", "futures-util", - "http 1.3.1", + "http 1.4.0", "http-body 1.0.1", - "hyper 1.7.0", + "hyper 1.8.1", "ipnet", "libc", "percent-encoding", "pin-project-lite", - "socket2 0.6.0", + "socket2 0.6.1", "tokio", "tower-service", "tracing", @@ -1566,9 +1526,9 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.63" +version = "0.1.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8" +checksum = "33e57f83510bb73707521ebaffa789ec8caf86f9657cad665b092b581d40e9fb" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -1590,9 +1550,9 @@ dependencies = [ [[package]] name = "icu_collections" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" +checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" dependencies = [ "displaydoc", "potential_utf", @@ -1603,9 +1563,9 @@ dependencies = [ [[package]] name = "icu_locale_core" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" +checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" dependencies = [ "displaydoc", "litemap", @@ -1616,11 +1576,10 @@ dependencies = [ [[package]] name = "icu_normalizer" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" +checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" dependencies = [ - "displaydoc", "icu_collections", "icu_normalizer_data", "icu_properties", @@ -1631,42 +1590,38 @@ dependencies = [ [[package]] name = "icu_normalizer_data" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" +checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" [[package]] name = "icu_properties" -version = "2.0.1" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b" +checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec" dependencies = [ - "displaydoc", "icu_collections", "icu_locale_core", "icu_properties_data", "icu_provider", - "potential_utf", "zerotrie", "zerovec", ] [[package]] name = "icu_properties_data" -version = "2.0.1" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" +checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af" [[package]] name = "icu_provider" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" +checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" dependencies = [ "displaydoc", "icu_locale_core", - "stable_deref_trait", - "tinystr", "writeable", "yoke", "zerofrom", @@ -1703,12 +1658,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.11.0" +version = "2.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2481980430f9f78649238835720ddccc57e52df14ffce1c6f37391d61b563e9" +checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" dependencies = [ "equivalent", - "hashbrown 0.15.5", + "hashbrown 0.16.1", ] [[package]] @@ -1726,17 +1681,6 @@ dependencies = [ "rustversion", ] -[[package]] -name = "io-uring" -version = "0.7.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "046fa2d4d00aea763528b4950358d0ead425372445dc8ff86312b3c69ff7727b" -dependencies = [ - "bitflags", - "cfg-if", - "libc", -] - [[package]] name = "ipnet" version = "2.11.0" @@ -1745,23 +1689,14 @@ checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" [[package]] name = "iri-string" -version = "0.7.8" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbc5ebe9c3a1a7a5127f920a418f7585e9e758e911d0466ed004f393b0e380b2" +checksum = "c91338f0783edbd6195decb37bae672fd3b165faffb89bf7b9e6942f8b1a731a" dependencies = [ "memchr", "serde", ] -[[package]] -name = "itertools" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" -dependencies = [ - "either", -] - [[package]] name = "itertools" version = "0.14.0" @@ -1773,9 +1708,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.15" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" +checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" [[package]] name = "jobserver" @@ -1783,15 +1718,15 @@ version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" dependencies = [ - "getrandom 0.3.3", + "getrandom 0.3.4", "libc", ] [[package]] name = "js-sys" -version = "0.3.77" +version = "0.3.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" +checksum = "464a3709c7f55f1f721e5389aa6ea4e3bc6aba669353300af094b29ffbdde1d8" dependencies = [ "once_cell", "wasm-bindgen", @@ -1816,24 +1751,18 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" -[[package]] -name = "lazycell" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" - [[package]] name = "leptos" -version = "0.8.8" +version = "0.8.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7a8710b4908a0e7b693113b906e4cf1bc87123b685404d090cdcd3e220bcab4" +checksum = "5f9569fc37575a5d64c0512145af7630bf651007237ef67a8a77328199d315bb" dependencies = [ "any_spawner", "base64 0.22.1", "cfg-if", "either_of", "futures", - "getrandom 0.3.3", + "getrandom 0.3.4", "hydration_context", "leptos_config", "leptos_dom", @@ -1845,7 +1774,7 @@ dependencies = [ "paste", "rand 0.9.2", "reactive_graph", - "rustc-hash 2.1.1", + "rustc-hash", "rustc_version", "send_wrapper", "serde", @@ -1854,10 +1783,10 @@ dependencies = [ "server_fn", "slotmap", "tachys", - "thiserror 2.0.16", + "thiserror 2.0.17", "throw_error", - "typed-builder", - "typed-builder-macro", + "typed-builder 0.23.2", + "typed-builder-macro 0.23.2", "wasm-bindgen", "wasm-bindgen-futures", "wasm_split_helpers", @@ -1866,9 +1795,9 @@ dependencies = [ [[package]] name = "leptos-use" -version = "0.16.2" +version = "0.16.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6eac17e7d306b4ad67158aba97c1490884ba304add4321069cb63fe0834c3b1" +checksum = "ce2162c453100c7d6bc0b6f188ef1df582e35c2458caf6cb69fcddc87619c0db" dependencies = [ "cfg-if", "codee", @@ -1878,7 +1807,26 @@ dependencies = [ "leptos", "paste", "send_wrapper", - "thiserror 2.0.16", + "thiserror 2.0.17", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "leptos_animate" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6225b975174171dff7b70563d08901fa7ec8d794615e6c8d6f14b23a613c40" +dependencies = [ + "anyhow", + "bon", + "futures", + "leptos", + "paste", + "reactive_stores 0.2.5", + "reactive_stores_macro", + "send_wrapper", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", @@ -1886,9 +1834,9 @@ dependencies = [ [[package]] name = "leptos_axum" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ba0d920d78828a8811bc52bdb25c7982d3c707f3497c3bdbb8a6c796d843a9c" +checksum = "f0caa95760f87f3067e05025140becefdbdfd36cbc2adac4519f06e1f1edf4af" dependencies = [ "any_spawner", "axum", @@ -1910,22 +1858,22 @@ dependencies = [ [[package]] name = "leptos_config" -version = "0.8.7" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240b4cb96284256a44872563cf029f24d6fe14bc341dcf0f4164e077cb5a1471" +checksum = "071fc40aeb9fcab885965bad1887990477253ad51f926cd19068f45a44c59e89" dependencies = [ "config", "regex", "serde", - "thiserror 2.0.16", - "typed-builder", + "thiserror 2.0.17", + "typed-builder 0.21.2", ] [[package]] name = "leptos_dom" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e920c8b2fd202b25786b0c72a00c745a6962fa923e600df6f3ec352d844be91" +checksum = "78f4330c88694c5575e0bfe4eecf81b045d14e76a4f8b00d5fd2a63f8779f895" dependencies = [ "js-sys", "or_poisoned", @@ -1956,9 +1904,9 @@ dependencies = [ [[package]] name = "leptos_integration_utils" -version = "0.8.5" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea02f77bee8de1e9dd4c7ef1c401dd3a1afef8dab6e240af6f7d6f73403a259f" +checksum = "13cccc9305df53757bae61bf15641bfa6a667b5f78456ace4879dfe0591ae0e8" dependencies = [ "futures", "hydration_context", @@ -1971,15 +1919,15 @@ dependencies = [ [[package]] name = "leptos_macro" -version = "0.8.8" +version = "0.8.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a84c7e53895c786f1128e91c36a708435e301f487338d19f2f6b5b67bb39ece2" +checksum = "c86ffd2e9cf3e264e9b3e16bdb086cefa26bd0fa7bc6a26b0cc5f6c1fd3178ed" dependencies = [ "attribute-derive", "cfg-if", - "convert_case 0.8.0", + "convert_case 0.10.0", "html-escape", - "itertools 0.14.0", + "itertools", "leptos_hot_reload", "prettyplease", "proc-macro-error2", @@ -2023,15 +1971,15 @@ dependencies = [ "reqwest", "serde", "serde_json", - "thiserror 2.0.16", + "thiserror 2.0.17", "tracing", ] [[package]] name = "leptos_router" -version = "0.8.6" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f13e0e0a70f40e4717da84415f6f1002091146ef247246b6a447d76947ab2e30" +checksum = "01e573711f2fb9ab5d655ec38115220d359eaaf1dcb93cc0ea624543b6dba959" dependencies = [ "any_spawner", "either_of", @@ -2046,7 +1994,7 @@ dependencies = [ "rustc_version", "send_wrapper", "tachys", - "thiserror 2.0.16", + "thiserror 2.0.17", "url", "wasm-bindgen", "web-sys", @@ -2054,9 +2002,9 @@ dependencies = [ [[package]] name = "leptos_router_macro" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "571042420d79f4f5b6b0d149dc1561b03f47e08c37c8fa0dfc80c73ad67be8af" +checksum = "409c0bd99f986c3cfa1a4db2443c835bc602ded1a12784e22ecb28c3ed5a2ae2" dependencies = [ "proc-macro-error2", "proc-macro2", @@ -2066,9 +2014,9 @@ dependencies = [ [[package]] name = "leptos_server" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38acbf32649a4b127c8d4ccaed8fb388e19a746430a0ea8f8160e51e28c36e2d" +checksum = "dbf1045af93050bf3388d1c138426393fc131f6d9e46a65519da884c033ed730" dependencies = [ "any_spawner", "base64 0.22.1", @@ -2086,19 +2034,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.175" +version = "0.2.180" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543" - -[[package]] -name = "libloading" -version = "0.8.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667" -dependencies = [ - "cfg-if", - "windows-targets 0.53.3", -] +checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc" [[package]] name = "linear-map" @@ -2106,33 +2044,26 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfae20f6b19ad527b550c223fddc3077a547fc70cda94b9b566575423fd303ee" -[[package]] -name = "linux-raw-sys" -version = "0.4.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" - [[package]] name = "litemap" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" +checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" [[package]] name = "lock_api" -version = "0.4.13" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" dependencies = [ - "autocfg", "scopeguard", ] [[package]] name = "log" -version = "0.4.28" +version = "0.4.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" [[package]] name = "macros" @@ -2174,9 +2105,9 @@ checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" [[package]] name = "memchr" -version = "2.7.5" +version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" [[package]] name = "mime" @@ -2194,30 +2125,15 @@ dependencies = [ "unicase", ] -[[package]] -name = "minimal-lexical" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" - -[[package]] -name = "miniz_oxide" -version = "0.8.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" -dependencies = [ - "adler2", -] - [[package]] name = "mio" -version = "1.0.4" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" +checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc" dependencies = [ "libc", - "wasi 0.11.1+wasi-snapshot-preview1", - "windows-sys 0.59.0", + "wasi", + "windows-sys 0.61.2", ] [[package]] @@ -2229,7 +2145,7 @@ dependencies = [ "bytes", "encoding_rs", "futures-util", - "http 1.3.1", + "http 1.4.0", "httparse", "memchr", "mime", @@ -2243,16 +2159,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60993920e071b0c9b66f14e2b32740a4e27ffc82854dcd72035887f336a09a28" -[[package]] -name = "nom" -version = "7.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" -dependencies = [ - "memchr", - "minimal-lexical", -] - [[package]] name = "num-conv" version = "0.1.0" @@ -2296,7 +2202,7 @@ dependencies = [ "base64 0.22.1", "chrono", "getrandom 0.2.16", - "http 1.3.1", + "http 1.4.0", "rand 0.8.5", "serde", "serde_json", @@ -2306,15 +2212,6 @@ dependencies = [ "url", ] -[[package]] -name = "object" -version = "0.36.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" -dependencies = [ - "memchr", -] - [[package]] name = "oco_ref" version = "0.2.1" @@ -2322,7 +2219,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed0423ff9973dea4d6bd075934fdda86ebb8c05bdf9d6b0507067d4a1226371d" dependencies = [ "serde", - "thiserror 2.0.16", + "thiserror 2.0.17", ] [[package]] @@ -2333,9 +2230,9 @@ checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] name = "openssl-probe" -version = "0.1.6" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" +checksum = "9f50d9b3dabb09ecd771ad0aa242ca6894994c130308ca3d7684634df8037391" [[package]] name = "or_poisoned" @@ -2357,9 +2254,9 @@ checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" [[package]] name = "parking_lot" -version = "0.12.4" +version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" dependencies = [ "lock_api", "parking_lot_core", @@ -2367,15 +2264,15 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.11" +version = "0.9.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", - "windows-targets 0.52.6", + "windows-link", ] [[package]] @@ -2430,9 +2327,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "potential_utf" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84df19adbe5b5a0782edcab45899906947ab039ccf4573713735ee7de1e6b08a" +checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" dependencies = [ "zerovec", ] @@ -2497,9 +2394,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.101" +version = "1.0.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" +checksum = "535d180e0ecab6268a3e718bb9fd44db66bbbc256257165fc699dadf70d16fe7" dependencies = [ "unicode-ident", ] @@ -2519,9 +2416,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.40" +version = "1.0.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +checksum = "dc74d9a594b72ae6656596548f56f667211f8a97b3d4c3d467150794690dc40a" dependencies = [ "proc-macro2", ] @@ -2610,14 +2507,14 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" dependencies = [ - "getrandom 0.3.3", + "getrandom 0.3.4", ] [[package]] name = "reactive_graph" -version = "0.2.6" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27e4f808d01701256dc220e398d518684781bcd1b3b1a6c1c107fd41374f0624" +checksum = "17f0df355582937223ea403e52490201d65295bd6981383c69bfae5a1f8730c2" dependencies = [ "any_spawner", "async-lock", @@ -2626,13 +2523,14 @@ dependencies = [ "hydration_context", "indexmap", "or_poisoned", + "paste", "pin-project-lite", - "rustc-hash 2.1.1", + "rustc-hash", "rustc_version", "send_wrapper", "serde", "slotmap", - "thiserror 2.0.16", + "thiserror 2.0.17", "web-sys", ] @@ -2644,12 +2542,29 @@ checksum = "79983e88dfd1a2925e29a4853ab9161b234ea78dd0d44ed33a706c9cd5e35762" dependencies = [ "dashmap", "guardian", - "itertools 0.14.0", + "itertools", "or_poisoned", "paste", "reactive_graph", "reactive_stores_macro", - "rustc-hash 2.1.1", + "rustc-hash", + "send_wrapper", +] + +[[package]] +name = "reactive_stores" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35372f05664a62a3dd389503371a15b8feb3396f99f6ec000de651fddb030942" +dependencies = [ + "dashmap", + "guardian", + "itertools", + "or_poisoned", + "paste", + "reactive_graph", + "reactive_stores_macro", + "rustc-hash", "send_wrapper", ] @@ -2668,18 +2583,18 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.17" +version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5407465600fb0548f1442edf71dd20683c6ed326200ace4b1ef0763521bb3b77" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ "bitflags", ] [[package]] name = "regex" -version = "1.11.2" +version = "1.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23d7fd106d8c02486a8d64e778353d1cffe08ce79ac2e82f540c86d0facf6912" +checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4" dependencies = [ "aho-corasick", "memchr", @@ -2689,9 +2604,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.10" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b9458fa0bfeeac22b5ca447c63aaf45f28439a709ccd244698632f9aa6394d6" +checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" dependencies = [ "aho-corasick", "memchr", @@ -2700,29 +2615,29 @@ dependencies = [ [[package]] name = "regex-lite" -version = "0.1.7" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "943f41321c63ef1c92fd763bfe054d2668f7f225a5c29f0105903dc2fc04ba30" +checksum = "8d942b98df5e658f56f20d592c7f868833fe38115e65c33003d8cd224b0155da" [[package]] name = "regex-syntax" -version = "0.8.6" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "caf4aa5b0f434c91fe5c7f1ecb6a5ece2130b02ad2a590589dda5146df959001" +checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" [[package]] name = "reqwest" -version = "0.12.23" +version = "0.12.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d429f34c8092b2d42c7c93cec323bb4adeb7c67698f70839adec842ec10c7ceb" +checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147" dependencies = [ "base64 0.22.1", "bytes", "futures-core", - "http 1.3.1", + "http 1.4.0", "http-body 1.0.1", "http-body-util", - "hyper 1.7.0", + "hyper 1.8.1", "hyper-util", "js-sys", "log", @@ -2768,21 +2683,9 @@ dependencies = [ "quote", "syn", "syn_derive", - "thiserror 2.0.16", + "thiserror 2.0.17", ] -[[package]] -name = "rustc-demangle" -version = "0.1.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" - -[[package]] -name = "rustc-hash" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" - [[package]] name = "rustc-hash" version = "2.1.1" @@ -2798,19 +2701,6 @@ dependencies = [ "semver", ] -[[package]] -name = "rustix" -version = "0.38.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" -dependencies = [ - "bitflags", - "errno", - "libc", - "linux-raw-sys", - "windows-sys 0.59.0", -] - [[package]] name = "rustls" version = "0.21.12" @@ -2825,56 +2715,35 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.31" +version = "0.23.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0ebcbd2f03de0fc1122ad9bb24b127a5a6cd51d72604a3f3c50ac459762b6cc" +checksum = "c665f33d38cea657d9614f766881e4d510e0eda4239891eea56b4cadcf01801b" dependencies = [ "aws-lc-rs", "once_cell", "rustls-pki-types", - "rustls-webpki 0.103.4", + "rustls-webpki 0.103.8", "subtle", "zeroize", ] [[package]] name = "rustls-native-certs" -version = "0.6.3" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9aace74cb666635c918e9c12bc0d348266037aa8eb599b5cba565709a8dff00" -dependencies = [ - "openssl-probe", - "rustls-pemfile", - "schannel", - "security-framework 2.11.1", -] - -[[package]] -name = "rustls-native-certs" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcff2dd52b58a8d98a70243663a0d234c4e2b79235637849d15913394a247d3" +checksum = "612460d5f7bea540c490b2b6395d8e34a953e52b491accd6c86c8164c5932a63" dependencies = [ "openssl-probe", "rustls-pki-types", "schannel", - "security-framework 3.3.0", -] - -[[package]] -name = "rustls-pemfile" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" -dependencies = [ - "base64 0.21.7", + "security-framework", ] [[package]] name = "rustls-pki-types" -version = "1.12.0" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79" +checksum = "21e6f2ab2928ca4291b86736a8bd920a277a399bba1589409d72154ff87c1282" dependencies = [ "zeroize", ] @@ -2891,9 +2760,9 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.103.4" +version = "0.103.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a17884ae0c1b773f1ccd2bd4a8c72f16da897310a98b0e84bf349ad5ead92fc" +checksum = "2ffdfa2f5286e2247234e03f680868ac2815974dc39e00ea15adc445d0aafe52" dependencies = [ "aws-lc-rs", "ring", @@ -2909,9 +2778,9 @@ checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] name = "ryu" -version = "1.0.20" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" +checksum = "a50f4cf475b65d88e057964e0e9bb1f0aa9bbb2036dc65c64596b42932536984" [[package]] name = "same-file" @@ -2924,11 +2793,11 @@ dependencies = [ [[package]] name = "schannel" -version = "0.1.27" +version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" +checksum = "891d81b926048e76efe18581bf793546b4c0eaf8448d72be8de2bbee5fd166e1" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -2942,6 +2811,7 @@ dependencies = [ "chrono", "console_error_panic_hook", "leptos", + "leptos_animate", "leptos_axum", "leptos_meta", "leptos_oidc", @@ -2974,25 +2844,12 @@ dependencies = [ [[package]] name = "security-framework" -version = "2.11.1" +version = "3.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" +checksum = "b3297343eaf830f66ede390ea39da1d462b6b0c1b000f420d0a83f898bbbe6ef" dependencies = [ "bitflags", - "core-foundation 0.9.4", - "core-foundation-sys", - "libc", - "security-framework-sys", -] - -[[package]] -name = "security-framework" -version = "3.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80fb1d92c5028aa318b4b8bd7302a5bfcf48be96a37fc6fc790f806b0004ee0c" -dependencies = [ - "bitflags", - "core-foundation 0.10.1", + "core-foundation", "core-foundation-sys", "libc", "security-framework-sys", @@ -3000,9 +2857,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.14.0" +version = "2.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32" +checksum = "cc1f0cbffaac4852523ce30d8bd3c5cdc873501d96ff467ca09b6767bb8cd5c0" dependencies = [ "core-foundation-sys", "libc", @@ -3010,9 +2867,9 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.26" +version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" [[package]] name = "send_wrapper" @@ -3025,18 +2882,28 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.219" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.219" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", @@ -3045,35 +2912,38 @@ dependencies = [ [[package]] name = "serde_dynamo" -version = "4.2.14" +version = "4.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e36c1b1792cfd9de29eb373ee6a4b74650369c096f55db7198ceb7b8921d1f7f" +checksum = "873a97c3f7a67dd042bceb47d056d288424b82d4c66b0a25e1a3b34675620951" dependencies = [ "aws-sdk-dynamodb", "base64 0.21.7", "serde", + "serde_core", ] [[package]] name = "serde_json" -version = "1.0.143" +version = "1.0.149" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d401abef1d108fbd9cbaebc3e46611f4b1021f714a0597a71f41ee463f5f4a5a" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" dependencies = [ "itoa", "memchr", - "ryu", "serde", + "serde_core", + "zmij", ] [[package]] name = "serde_path_to_error" -version = "0.1.17" +version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59fab13f937fa393d08645bf3a84bdfe86e296747b506ada67bb15f10f218b2a" +checksum = "10a9ff822e371bb5403e391ecd83e182e0e77ba7f6fe0160b795797109d1b457" dependencies = [ "itoa", "serde", + "serde_core", ] [[package]] @@ -3084,16 +2954,16 @@ checksum = "f3faaf9e727533a19351a43cc5a8de957372163c7d35cc48c90b75cdda13c352" dependencies = [ "percent-encoding", "serde", - "thiserror 2.0.16", + "thiserror 2.0.17", ] [[package]] name = "serde_spanned" -version = "1.0.0" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40734c41988f7306bb04f0ecf60ec0f3f1caa34290e4e8ea471dcd3346483b83" +checksum = "f8bbf91e5a4d6315eee45e704372590b30e260ee83af6639d64557f51b067776" dependencies = [ - "serde", + "serde_core", ] [[package]] @@ -3110,9 +2980,9 @@ dependencies = [ [[package]] name = "server_fn" -version = "0.8.6" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4efa7bb741386fb31a68269c81b1469c917d9adb1f4102a2d2684f11e3235389" +checksum = "353d02fa2886cd8dae0b8da0965289fa8f2ecc7df633d1ce965f62fdf9644d29" dependencies = [ "axum", "base64 0.22.1", @@ -3122,9 +2992,9 @@ dependencies = [ "dashmap", "futures", "gloo-net", - "http 1.3.1", + "http 1.4.0", "http-body-util", - "hyper 1.7.0", + "hyper 1.8.1", "inventory", "js-sys", "pin-project-lite", @@ -3135,7 +3005,7 @@ dependencies = [ "serde_json", "serde_qs", "server_fn_macro_default", - "thiserror 2.0.16", + "thiserror 2.0.17", "throw_error", "tokio", "tower", @@ -3150,9 +3020,9 @@ dependencies = [ [[package]] name = "server_fn_macro" -version = "0.8.7" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d1a916793571234d1c4622153d42495d26605ed7b9d5d38a2699666cfef46b3" +checksum = "950b8cfc9ff5f39ca879c5a7c5e640de2695a199e18e424c3289d0964cabe642" dependencies = [ "const_format", "convert_case 0.8.0", @@ -3203,10 +3073,11 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "signal-hook-registry" -version = "1.4.6" +version = "1.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2a4719bff48cee6b39d12c020eeb490953ad2443b7055bd0b21fca26bd8c28b" +checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" dependencies = [ + "errno", "libc", ] @@ -3218,9 +3089,9 @@ checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" [[package]] name = "slotmap" -version = "1.0.7" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbff4acf519f630b3a3ddcfaea6c06b42174d9a44bc70c620e9ed1649d58b82a" +checksum = "bdd58c3c93c3d278ca835519292445cb4b0d4dc59ccfdf7ceadaab3f8aeb4038" dependencies = [ "version_check", ] @@ -3243,12 +3114,12 @@ dependencies = [ [[package]] name = "socket2" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "233504af464074f9d066d7b5416c5f9b894a5862a6506e306f7b816cdd6f1807" +checksum = "17129e116933cf371d018bb80ae557e889637989d8638274fb25622827b03881" dependencies = [ "libc", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] @@ -3259,9 +3130,9 @@ checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" [[package]] name = "stable_deref_trait" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" [[package]] name = "strsim" @@ -3277,9 +3148,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" -version = "2.0.106" +version = "2.0.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" +checksum = "d4d107df263a3013ef9b1879b0df87d706ff80f65a86ea879bd9c31f9b307c2a" dependencies = [ "proc-macro2", "quote", @@ -3320,9 +3191,9 @@ dependencies = [ [[package]] name = "tachys" -version = "0.2.7" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dacbb26ffb2bbe6743702ee27c3e994c0caae86c92137278de9a9d92d383765c" +checksum = "f2b2db11e455f7e84e2cc3e76f8a3f3843f7956096265d5ecff781eabe235077" dependencies = [ "any_spawner", "async-trait", @@ -3333,7 +3204,7 @@ dependencies = [ "futures", "html-escape", "indexmap", - "itertools 0.14.0", + "itertools", "js-sys", "linear-map", "next_tuple", @@ -3342,8 +3213,8 @@ dependencies = [ "parking_lot", "paste", "reactive_graph", - "reactive_stores", - "rustc-hash 2.1.1", + "reactive_stores 0.3.1", + "rustc-hash", "rustc_version", "send_wrapper", "slotmap", @@ -3363,11 +3234,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.16" +version = "2.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3467d614147380f2e4e374161426ff399c91084acd2363eaf549172b3d5e60c0" +checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" dependencies = [ - "thiserror-impl 2.0.16", + "thiserror-impl 2.0.17", ] [[package]] @@ -3383,9 +3254,9 @@ dependencies = [ [[package]] name = "thiserror-impl" -version = "2.0.16" +version = "2.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c5e1be1c48b9172ee610da68fd9cd2770e7a4056cb3fc98710ee6906f0c7960" +checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" dependencies = [ "proc-macro2", "quote", @@ -3394,18 +3265,18 @@ dependencies = [ [[package]] name = "throw_error" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41e42a6afdde94f3e656fae18f837cb9bbe500a5ac5de325b09f3ec05b9c28e3" +checksum = "dc0ed6038fcbc0795aca7c92963ddda636573b956679204e044492d2b13c8f64" dependencies = [ "pin-project-lite", ] [[package]] name = "time" -version = "0.3.43" +version = "0.3.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83bde6f1ec10e72d583d91623c939f623002284ef622b87de38cfd546cbf2031" +checksum = "91e7d9e3bb61134e77bde20dd4825b97c010155709965fedf0f49bb138e52a9d" dependencies = [ "deranged", "num-conv", @@ -3433,9 +3304,9 @@ dependencies = [ [[package]] name = "tinystr" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" +checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" dependencies = [ "displaydoc", "zerovec", @@ -3443,28 +3314,25 @@ dependencies = [ [[package]] name = "tokio" -version = "1.47.1" +version = "1.49.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89e49afdadebb872d3145a5638b59eb0691ea23e46ca484037cfab3b76b95038" +checksum = "72a2903cd7736441aac9df9d7688bd0ce48edccaadf181c3b90be801e81d3d86" dependencies = [ - "backtrace", "bytes", - "io-uring", "libc", "mio", "pin-project-lite", "signal-hook-registry", - "slab", - "socket2 0.6.0", + "socket2 0.6.1", "tokio-macros", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] name = "tokio-macros" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" +checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" dependencies = [ "proc-macro2", "quote", @@ -3483,19 +3351,19 @@ dependencies = [ [[package]] name = "tokio-rustls" -version = "0.26.2" +version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e727b36a1a0e8b74c376ac2211e40c2c8af09fb4013c60d910495810f008e9b" +checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" dependencies = [ - "rustls 0.23.31", + "rustls 0.23.36", "tokio", ] [[package]] name = "tokio-tungstenite" -version = "0.26.2" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a9daff607c6d2bf6c16fd681ccb7eecc83e4e2cdc1ca067ffaadfca5de7f084" +checksum = "d25a406cddcc431a75d3d9afc6a7c0f7428d4891dd973e4d54c56b46127bf857" dependencies = [ "futures-util", "log", @@ -3505,9 +3373,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.16" +version = "0.7.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14307c986784f72ef81c89db7d9e28d6ac26d16213b109ea501696195e6e3ce5" +checksum = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098" dependencies = [ "bytes", "futures-core", @@ -3518,11 +3386,11 @@ dependencies = [ [[package]] name = "toml" -version = "0.9.5" +version = "0.9.11+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75129e1dc5000bfbaa9fee9d1b21f974f9fbad9daec557a521ee6e080825f6e8" +checksum = "f3afc9a848309fe1aaffaed6e1546a7a14de1f935dc9d89d32afd9a44bab7c46" dependencies = [ - "serde", + "serde_core", "serde_spanned", "toml_datetime", "toml_parser", @@ -3531,18 +3399,18 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.7.0" +version = "0.7.5+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bade1c3e902f58d73d3f294cd7f20391c1cb2fbcb643b73566bc773971df91e3" +checksum = "92e1cfed4a3038bc5a127e35a2d360f145e1f4b971b551a2ba5fd7aedf7e1347" dependencies = [ - "serde", + "serde_core", ] [[package]] name = "toml_parser" -version = "1.0.2" +version = "1.0.6+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b551886f449aa90d4fe2bdaa9f4a2577ad2dde302c61ecf262d80b116db95c10" +checksum = "a3198b4b0a8e11f09dd03e133c0280504d0801269e9afa46362ffde1cbeebf44" dependencies = [ "winnow", ] @@ -3565,15 +3433,15 @@ dependencies = [ [[package]] name = "tower-http" -version = "0.6.6" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2" +checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8" dependencies = [ "bitflags", "bytes", "futures-core", "futures-util", - "http 1.3.1", + "http 1.4.0", "http-body 1.0.1", "http-body-util", "http-range-header", @@ -3605,9 +3473,9 @@ checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" -version = "0.1.41" +version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" dependencies = [ "log", "pin-project-lite", @@ -3617,9 +3485,9 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.30" +version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" dependencies = [ "proc-macro2", "quote", @@ -3628,9 +3496,9 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.34" +version = "0.1.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" dependencies = [ "once_cell", ] @@ -3647,18 +3515,18 @@ checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "tungstenite" -version = "0.26.2" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4793cb5e56680ecbb1d843515b23b6de9a75eb04b66643e256a396d43be33c13" +checksum = "8628dcc84e5a09eb3d8423d6cb682965dea9133204e8fb3efee74c2a0c259442" dependencies = [ "bytes", "data-encoding", - "http 1.3.1", + "http 1.4.0", "httparse", "log", "rand 0.9.2", "sha1", - "thiserror 2.0.16", + "thiserror 2.0.17", "utf-8", ] @@ -3668,7 +3536,16 @@ version = "0.21.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fef81aec2ca29576f9f6ae8755108640d0a86dd3161b2e8bca6cfa554e98f77d" dependencies = [ - "typed-builder-macro", + "typed-builder-macro 0.21.2", +] + +[[package]] +name = "typed-builder" +version = "0.23.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31aa81521b70f94402501d848ccc0ecaa8f93c8eb6999eb9747e72287757ffda" +dependencies = [ + "typed-builder-macro 0.23.2", ] [[package]] @@ -3683,22 +3560,33 @@ dependencies = [ ] [[package]] -name = "typenum" -version = "1.18.0" +name = "typed-builder-macro" +version = "0.23.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" +checksum = "076a02dc54dd46795c2e9c8282ed40bcfb1e22747e955de9389a1de28190fb26" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "typenum" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" [[package]] name = "unicase" -version = "2.8.1" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539" +checksum = "dbc4bc3a9f746d862c45cb89d705aa10f187bb96c76001afab07a0d35ce60142" [[package]] name = "unicode-ident" -version = "1.0.18" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" +checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" [[package]] name = "unicode-segmentation" @@ -3720,14 +3608,15 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "url" -version = "2.5.7" +version = "2.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08bc136a29a3d1758e07a9cca267be308aeebf5cfd5a10f3f67ab2097683ef5b" +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" dependencies = [ "form_urlencoded", "idna", "percent-encoding", "serde", + "serde_derive", ] [[package]] @@ -3744,9 +3633,9 @@ checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" [[package]] name = "utf8-width" -version = "0.1.7" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86bd8d4e895da8537e5315b8254664e6b769c4ff3db18321b297a1e7004392e3" +checksum = "1292c0d970b54115d14f2492fe0170adf21d68a1de108eebc51c1df4f346a091" [[package]] name = "utf8_iter" @@ -3756,13 +3645,13 @@ checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" [[package]] name = "uuid" -version = "1.18.1" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f87b8aa10b915a06587d0dec516c282ff295b475d94abf425d62b57710070a2" +checksum = "e2e054861b4bd027cd373e18e8d8d8e6548085000e41290d95ce0c373a654b4a" dependencies = [ - "getrandom 0.3.3", + "getrandom 0.3.4", "js-sys", - "serde", + "serde_core", "wasm-bindgen", ] @@ -3804,45 +3693,32 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] -name = "wasi" -version = "0.14.3+wasi-0.2.4" +name = "wasip2" +version = "1.0.1+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a51ae83037bdd272a9e28ce236db8c07016dd0d50c27038b3f407533c030c95" +checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" dependencies = [ "wit-bindgen", ] [[package]] name = "wasm-bindgen" -version = "0.2.100" +version = "0.2.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" +checksum = "0d759f433fa64a2d763d1340820e46e111a7a5ab75f993d1852d70b03dbb80fd" dependencies = [ "cfg-if", "once_cell", "rustversion", "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" -dependencies = [ - "bumpalo", - "log", - "proc-macro2", - "quote", - "syn", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.50" +version = "0.4.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61" +checksum = "836d9622d604feee9e5de25ac10e3ea5f2d65b41eac0d9ce72eb5deae707ce7c" dependencies = [ "cfg-if", "js-sys", @@ -3853,9 +3729,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.100" +version = "0.2.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" +checksum = "48cb0d2638f8baedbc542ed444afc0644a29166f1595371af4fecf8ce1e7eeb3" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -3863,22 +3739,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.100" +version = "0.2.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" +checksum = "cefb59d5cd5f92d9dcf80e4683949f15ca4b511f4ac0a6e14d4e1ac60c6ecd40" dependencies = [ + "bumpalo", "proc-macro2", "quote", "syn", - "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.100" +version = "0.2.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +checksum = "cbc538057e648b67f72a982e708d485b2efa771e1ac05fec311f9f63e5800db4" dependencies = [ "unicode-ident", ] @@ -3898,78 +3774,63 @@ dependencies = [ [[package]] name = "wasm_split_helpers" -version = "0.1.2" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c50e0e45d0d871605a21fc4ee93a5380b7bdc41b5eda22e42f0777a4ce79b65c" +checksum = "a114b3073258dd5de3d812cdd048cca6842342755e828a14dbf15f843f2d1b84" dependencies = [ "async-once-cell", - "or_poisoned", "wasm_split_macros", ] [[package]] name = "wasm_split_macros" -version = "0.1.2" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f8a7f0bf54b0129a337aadfe8b716d843689f69c75b2a6413a0cff2e0d00982" +checksum = "56481f8ed1a9f9ae97ea7b08a5e2b12e8adf9a7818a6ba952b918e09c7be8bf0" dependencies = [ "base16", - "digest", "quote", "sha2", "syn", - "wasm-bindgen", ] [[package]] name = "web-sys" -version = "0.3.77" +version = "0.3.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" +checksum = "9b32828d774c412041098d182a8b38b16ea816958e07cf40eec2bc080ae137ac" dependencies = [ "js-sys", "wasm-bindgen", ] -[[package]] -name = "which" -version = "4.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" -dependencies = [ - "either", - "home", - "once_cell", - "rustix", -] - [[package]] name = "winapi-util" -version = "0.1.10" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0978bf7171b3d90bac376700cb56d606feb40f251a475a5d6634613564460b22" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] name = "windows-core" -version = "0.61.2" +version = "0.62.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" dependencies = [ "windows-implement", "windows-interface", - "windows-link 0.1.3", + "windows-link", "windows-result", "windows-strings", ] [[package]] name = "windows-implement" -version = "0.60.0" +version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", @@ -3978,9 +3839,9 @@ dependencies = [ [[package]] name = "windows-interface" -version = "0.59.1" +version = "0.59.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", @@ -3989,32 +3850,26 @@ dependencies = [ [[package]] name = "windows-link" -version = "0.1.3" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" - -[[package]] -name = "windows-link" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45e46c0661abb7180e7b9c281db115305d49ca1709ab8242adf09666d2173c65" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" [[package]] name = "windows-result" -version = "0.3.4" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" dependencies = [ - "windows-link 0.1.3", + "windows-link", ] [[package]] name = "windows-strings" -version = "0.4.2" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" dependencies = [ - "windows-link 0.1.3", + "windows-link", ] [[package]] @@ -4026,22 +3881,22 @@ dependencies = [ "windows-targets 0.52.6", ] -[[package]] -name = "windows-sys" -version = "0.59.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" -dependencies = [ - "windows-targets 0.52.6", -] - [[package]] name = "windows-sys" version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" dependencies = [ - "windows-targets 0.53.3", + "windows-targets 0.53.5", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", ] [[package]] @@ -4062,19 +3917,19 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.53.3" +version = "0.53.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" dependencies = [ - "windows-link 0.1.3", - "windows_aarch64_gnullvm 0.53.0", - "windows_aarch64_msvc 0.53.0", - "windows_i686_gnu 0.53.0", - "windows_i686_gnullvm 0.53.0", - "windows_i686_msvc 0.53.0", - "windows_x86_64_gnu 0.53.0", - "windows_x86_64_gnullvm 0.53.0", - "windows_x86_64_msvc 0.53.0", + "windows-link", + "windows_aarch64_gnullvm 0.53.1", + "windows_aarch64_msvc 0.53.1", + "windows_i686_gnu 0.53.1", + "windows_i686_gnullvm 0.53.1", + "windows_i686_msvc 0.53.1", + "windows_x86_64_gnu 0.53.1", + "windows_x86_64_gnullvm 0.53.1", + "windows_x86_64_msvc 0.53.1", ] [[package]] @@ -4085,9 +3940,9 @@ checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_gnullvm" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" [[package]] name = "windows_aarch64_msvc" @@ -4097,9 +3952,9 @@ checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_aarch64_msvc" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" [[package]] name = "windows_i686_gnu" @@ -4109,9 +3964,9 @@ checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] name = "windows_i686_gnu" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" [[package]] name = "windows_i686_gnullvm" @@ -4121,9 +3976,9 @@ checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_gnullvm" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" [[package]] name = "windows_i686_msvc" @@ -4133,9 +3988,9 @@ checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_i686_msvc" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" [[package]] name = "windows_x86_64_gnu" @@ -4145,9 +4000,9 @@ checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnu" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" [[package]] name = "windows_x86_64_gnullvm" @@ -4157,9 +4012,9 @@ checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_gnullvm" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" [[package]] name = "windows_x86_64_msvc" @@ -4169,30 +4024,30 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "windows_x86_64_msvc" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" [[package]] name = "winnow" -version = "0.7.13" +version = "0.7.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf" +checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829" dependencies = [ "memchr", ] [[package]] name = "wit-bindgen" -version = "0.45.0" +version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "052283831dbae3d879dc7f51f3d92703a316ca49f91540417d38591826127814" +checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" [[package]] name = "writeable" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" +checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" [[package]] name = "xmlparser" @@ -4214,11 +4069,10 @@ checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" [[package]] name = "yoke" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" +checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" dependencies = [ - "serde", "stable_deref_trait", "yoke-derive", "zerofrom", @@ -4226,9 +4080,9 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" +checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" dependencies = [ "proc-macro2", "quote", @@ -4238,18 +4092,18 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.8.26" +version = "0.8.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1039dd0d3c310cf05de012d8a39ff557cb0d23087fd44cad61df08fc31907a2f" +checksum = "668f5168d10b9ee831de31933dc111a459c97ec93225beb307aed970d1372dfd" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.26" +version = "0.8.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181" +checksum = "2c7962b26b0a8685668b671ee4b54d007a67d4eaf05fda79ac0ecf41e32270f1" dependencies = [ "proc-macro2", "quote", @@ -4279,15 +4133,15 @@ dependencies = [ [[package]] name = "zeroize" -version = "1.8.1" +version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" [[package]] name = "zerotrie" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" +checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" dependencies = [ "displaydoc", "yoke", @@ -4296,9 +4150,9 @@ dependencies = [ [[package]] name = "zerovec" -version = "0.11.4" +version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7aa2bd55086f1ab526693ecbe444205da57e25f4489879da80635a46d90e73b" +checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" dependencies = [ "yoke", "zerofrom", @@ -4307,11 +4161,17 @@ dependencies = [ [[package]] name = "zerovec-derive" -version = "0.11.1" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" +checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" dependencies = [ "proc-macro2", "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fc5a66a20078bf1251bde995aa2fdcc4b800c70b5d92dd2c62abc5c60f679f8" diff --git a/Cargo.toml b/Cargo.toml index 3bd7f60..55b2f80 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,7 +14,7 @@ console_error_panic_hook = { version = "0.1", optional = true} leptos_axum = { version = "0.8", optional = true } leptos_meta = { version = "0.8" } tokio = { version = "1", features = ["rt-multi-thread"], optional = true } -wasm-bindgen = { version = "=0.2.100", optional = true } +wasm-bindgen = { version = "=0.2.106", optional = true } aws-sdk-dynamodb = { version = "1", optional = true } aws-config = { version = "1.6.2", optional = true } serde = "1.0.219" @@ -24,11 +24,13 @@ leptos_oidc = "0.9.0" base64 = "0.22.1" chrono = "0.4.42" regex = "1.11.2" +leptos_animate = "0.1.9" macros = { path = "./macros" } traits = { path = "./traits" } [features] +default = ["ssr"] hydrate = [ "leptos/hydrate", "dep:console_error_panic_hook", diff --git a/signup-lambda/.gitignore b/signup-lambda/.gitignore new file mode 100644 index 0000000..1de5659 --- /dev/null +++ b/signup-lambda/.gitignore @@ -0,0 +1 @@ +target \ No newline at end of file diff --git a/signup-lambda/Cargo.toml b/signup-lambda/Cargo.toml new file mode 100644 index 0000000..3915e3d --- /dev/null +++ b/signup-lambda/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "signup-lambda" +version = "0.1.0" +edition = "2021" + +[dependencies] + +lambda_runtime = "1.0.1" +aws-sdk-cognitoidentityprovider = "1.105.0" +serde = "1" +tokio = { version = "1", features = ["macros"] } +aws-config = "1.8.12" diff --git a/signup-lambda/README.md b/signup-lambda/README.md new file mode 100644 index 0000000..fb024e8 --- /dev/null +++ b/signup-lambda/README.md @@ -0,0 +1,52 @@ +# Introduction + +signup-lambda is a Rust project that implements an AWS Lambda function in Rust. + +## Prerequisites + +- [Rust](https://www.rust-lang.org/tools/install) +- [Cargo Lambda](https://www.cargo-lambda.info/guide/installation.html) + +## Building + +To build the project for production, run `cargo lambda build --release`. Remove the `--release` flag to build for development. + +Read more about building your lambda function in [the Cargo Lambda documentation](https://www.cargo-lambda.info/commands/build.html). + +## Testing + +You can run regular Rust unit tests with `cargo test`. + +If you want to run integration tests locally, you can use the `cargo lambda watch` and `cargo lambda invoke` commands to do it. + +First, run `cargo lambda watch` to start a local server. When you make changes to the code, the server will automatically restart. + +Second, you'll need a way to pass the event data to the lambda function. + +You can use the existent [event payloads](https://github.com/awslabs/aws-lambda-rust-runtime/tree/main/lambda-events/src/fixtures) in the Rust Runtime repository if your lambda function is using one of the supported event types. + +You can use those examples directly with the `--data-example` flag, where the value is the name of the file in the [lambda-events](https://github.com/awslabs/aws-lambda-rust-runtime/tree/main/lambda-events/src/fixtures) repository without the `example_` prefix and the `.json` extension. + +```bash +cargo lambda invoke --data-example apigw-request +``` + +For generic events, where you define the event data structure, you can create a JSON file with the data you want to test with. For example: + +```json +{ + "command": "test" +} +``` + +Then, run `cargo lambda invoke --data-file ./data.json` to invoke the function with the data in `data.json`. + + +Read more about running the local server in [the Cargo Lambda documentation for the `watch` command](https://www.cargo-lambda.info/commands/watch.html). +Read more about invoking the function in [the Cargo Lambda documentation for the `invoke` command](https://www.cargo-lambda.info/commands/invoke.html). + +## Deploying + +To deploy the project, run `cargo lambda deploy`. This will create an IAM role and a Lambda function in your AWS account. + +Read more about deploying your lambda function in [the Cargo Lambda documentation](https://www.cargo-lambda.info/commands/deploy.html). diff --git a/signup-lambda/src/handler.rs b/signup-lambda/src/handler.rs new file mode 100644 index 0000000..01bb2ba --- /dev/null +++ b/signup-lambda/src/handler.rs @@ -0,0 +1,76 @@ +use lambda_runtime::LambdaEvent; +use aws_sdk_cognitoidentityprovider::Client; +use aws_config::BehaviorVersion; +use serde::{Serialize, Deserialize}; +use std::collections::HashMap; +use aws_sdk_cognitoidentityprovider::error::ProvideErrorMetadata; + +#[derive(Serialize, Deserialize, Debug)] +#[serde(rename_all = "camelCase")] +pub(crate) struct PostConfirmationEvent { + version: String, + trigger_source: String, + region: String, + user_pool_id: String, + user_name: String, + caller_context: CallerContext, + request: Request, + response: Response +} + +#[derive(Serialize, Deserialize, Debug)] +#[serde(rename_all = "camelCase")] +pub(crate) struct CallerContext { + client_id: String, +} + +#[derive(Serialize, Deserialize, Debug)] +#[serde(rename_all = "camelCase")] +pub(crate) struct Request { + user_attributes: HashMap, +} + +#[derive(Serialize, Deserialize, Debug)] +#[serde(rename_all = "camelCase")] +pub(crate) struct Response {} + +fn get_error_message(err: impl ProvideErrorMetadata) -> String { + err.message().unwrap_or("An unknown error occurred").to_string() +} + +async fn add_user_to_group(provider: Client, user_id: String, group_name: impl Into) -> Result<(), String> { + let group_name = group_name.into(); + println!("Adding user {} to group {}", user_id, group_name); + match provider + .admin_add_user_to_group() + .user_pool_id("us-east-1_Lfjuy5zaM") + .username(user_id) + .group_name(group_name) + .send() + .await + { + Ok(_) => Ok(()), + Err(err) => Err(get_error_message(err)), + } +} + +pub(crate) async fn handler(event: LambdaEvent) -> Result { + println!("Found event: {:?}", event.payload); + + let user_id = event.payload.request.user_attributes.get("sub").unwrap().to_string(); + let config = aws_config::load_defaults(BehaviorVersion::latest()).await; + let client = Client::new(&config); + + // Check the client ID of the request to assign the user to the correct location. + let res = match event.payload.caller_context.client_id.as_str() { + "10jr2h3vtpu9n7gj46pvg5qo2q" => add_user_to_group(client, user_id, "ScholarshipStudents").await, + "56c2bqvl021rv8d5mq36blt7jv" => add_user_to_group(client, user_id, "ScholarshipProviders").await, + _ => Err("Invalid client ID, denying all user access.".to_string()), + }; + + if res.is_ok() { + Ok(event.payload) + } else { + Err(res.unwrap_err()) + } +} diff --git a/signup-lambda/src/main.rs b/signup-lambda/src/main.rs new file mode 100644 index 0000000..8204be7 --- /dev/null +++ b/signup-lambda/src/main.rs @@ -0,0 +1,11 @@ +use lambda_runtime::{run, service_fn, tracing, Error}; +mod handler; + +use handler::handler as function_handler; + +#[tokio::main] +async fn main() -> Result<(), Error> { + tracing::init_default_subscriber(); + + run(service_fn(function_handler)).await +} diff --git a/src/app.rs b/src/app.rs index b3b1aa6..fcd99b6 100644 --- a/src/app.rs +++ b/src/app.rs @@ -1,9 +1,9 @@ -use crate::pages::{AboutPage, HomePage, LoanerPage, ProviderPortal, ComparisonTestPage, ScholarshipInfoPage, TestPage}; -use leptos::leptos_dom::log; +use crate::pages::{AboutPage, HomePage, ProviderPortal, ComparisonTestPage, ScholarshipInfoPage, TestPage, ProviderContactPage, LoanerShell, LoanerFallback, LoanerBorrowForm, LoanerReturnForm}; use leptos::prelude::*; use leptos_meta::{MetaTags, Stylesheet, Title, provide_meta_context}; use leptos_oidc::{Auth, AuthParameters, AuthSignal, Challenge}; use leptos_router::{components::{Route, Router, Routes, ParentRoute}, path}; +use crate::components::ToastList; pub fn shell(options: LeptosOptions) -> impl IntoView { view! { @@ -65,15 +65,12 @@ pub fn AppWithRoutes() -> impl IntoView { provide_meta_context(); let current_origin = use_origin(); - log!("Current origin: {}", current_origin); // Authentication setup let parameters = AuthParameters { issuer: "https://cognito-idp.us-east-1.amazonaws.com/us-east-1_Lfjuy5zaM".into(), client_id: "10jr2h3vtpu9n7gj46pvg5qo2q".into(), redirect_uri: format!("{}/", use_origin()), - // redirect_uri: Url::parse(format!("{}", current_origin).as_str()).unwrap().to_string(), - // redirect_uri: Url::parse("http://localhost:3000").unwrap().to_string(), post_logout_redirect_uri: current_origin, scope: Some("openid%20profile%20email".into()), audience: None, @@ -98,22 +95,26 @@ pub fn AppWithRoutes() -> impl IntoView { <main> - // TODO Create a 404 page - <Routes fallback=|| "Page not found.".into_view()> - <Route path=path!("") view=HomePage/> - <Route path=path!("/about") view=AboutPage/> - <Route path=path!("/test_page") view=TestPage/> - <Route path=path!("/comparison") view=ComparisonTestPage /> - <Route path=path!("/providers") view=ProviderPortal/> - <ParentRoute path=path!("/providers/scholarships") view=ScholarshipInfoPage> - <Route path=path!(":id") view=ScholarshipInfoPage/> - <Route path=path!("") view=ScholarshipInfoPage/> - </ParentRoute> - <ParentRoute path=path!("loaners") view=LoanerPage> - <Route path=path!("") view=LoanerPage /> - <Route path=path!(":form_name") view=LoanerPage /> - </ParentRoute> - </Routes> + <ToastList> + // TODO Create a 404 page + <Routes fallback=|| "Page not found.".into_view()> + <Route path=path!("") view=HomePage/> + <Route path=path!("/about") view=AboutPage/> + <Route path=path!("/test_page") view=TestPage/> + <Route path=path!("/comparison") view=ComparisonTestPage /> + <Route path=path!("/providers") view=ProviderPortal/> + <Route path=path!("/providers/profile") view=ProviderContactPage /> + <ParentRoute path=path!("/providers/scholarships") view=ScholarshipInfoPage> + <Route path=path!(":id") view=ScholarshipInfoPage/> + <Route path=path!("") view=ScholarshipInfoPage/> + </ParentRoute> + <ParentRoute path=path!("loaners") view=LoanerShell> + <Route path=path!("") view=LoanerFallback /> + <Route path=path!("borrowing") view=LoanerBorrowForm /> + <Route path=path!("returning") view=LoanerReturnForm /> + </ParentRoute> + </Routes> + </ToastList> </main> } } diff --git a/src/common/animations.rs b/src/common/animations.rs new file mode 100644 index 0000000..53ba72e --- /dev/null +++ b/src/common/animations.rs @@ -0,0 +1,14 @@ +use leptos_animate::animations::classes::{In, Out}; + +pub fn pop_in_out() -> (In, Out) { + ( + In::default() + .source("opacity-0 -translate-y-2 scale-90") + .active("transition-all duration-150 transform-gpu") + .target("opacity-100 translate-y-0 scale-100"), + Out::default() + .source("opacity-100 translate-y-0 scale-100") + .active("transition-all duration-150 transform-gpu") + .target("opacity-0 -translate-y-2 scale-90"), + ) +} diff --git a/src/common/mod.rs b/src/common/mod.rs index a34a9ec..5f68c9d 100644 --- a/src/common/mod.rs +++ b/src/common/mod.rs @@ -5,5 +5,6 @@ mod form_schema; mod user; mod value_type; mod submit_status; +pub mod animations; pub use self::{comparison::*, expandable_info::*, form_schema::*, user::*, value_type::*, form_params::*, submit_status::*}; diff --git a/src/common/value_type.rs b/src/common/value_type.rs index 982df27..ceb6a36 100644 --- a/src/common/value_type.rs +++ b/src/common/value_type.rs @@ -113,3 +113,31 @@ impl Display for ValueType { write!(f, "{}", str) } } + +#[cfg(feature = "ssr")] +use aws_sdk_dynamodb::types::AttributeValue; + +#[cfg(feature = "ssr")] +impl From<&AttributeValue> for ValueType { + fn from(attr: &AttributeValue) -> Self { + match attr { + AttributeValue::S(s) => ValueType::String(Some(s.clone())), + AttributeValue::N(n) => ValueType::Number(Some(n.clone())), + AttributeValue::L(l) => ValueType::List(Some(l.iter().map(|v| v.into()).collect())), + AttributeValue::M(m) => ValueType::Map(Some(m.iter().map(|(k, v)| (k.clone(), v.into())).collect())), + _ => ValueType::default(), + } + } +} + +#[cfg(feature = "ssr")] +impl Into<AttributeValue> for ValueType { + fn into(self) -> AttributeValue { + match self { + ValueType::String(s) => AttributeValue::S(s.unwrap_or_default()), + ValueType::Number(n) => AttributeValue::N(n.unwrap_or_default()), + ValueType::List(l) => AttributeValue::L(l.unwrap_or_default().into_iter().map(|v| v.into()).collect()), + ValueType::Map(m) => AttributeValue::M(m.unwrap_or_default().into_iter().map(|(k, v)| (k, v.into())).collect()), + } + } +} diff --git a/src/components/action_button.rs b/src/components/action_button.rs index 9207d84..cafd0b3 100644 --- a/src/components/action_button.rs +++ b/src/components/action_button.rs @@ -8,8 +8,8 @@ pub fn ActionButton( ) -> impl IntoView { view! { <button - class="m-1.5 p-2.5 rounded-lg font-semibold text-white transition-all duration-400" - class=(["bg-red-700", "hover:bg-red-800"], move || !disabled.get()) + class="m-1.5 p-2.5 rounded-lg font-semibold text-white transition-all duration-400 cursor-pointer" + class=(["bg-red-800", "hover:bg-red-900"], move || !disabled.get()) class=(["bg-gray-600", "pointer-events-none"], move || disabled.get()) r#type=button_type disabled=move || disabled.get() diff --git a/src/components/header.rs b/src/components/header.rs new file mode 100644 index 0000000..c6055a0 --- /dev/null +++ b/src/components/header.rs @@ -0,0 +1,40 @@ +use leptos::prelude::*; + +/// # Header Component +/// +/// A simple header that may also contain a description. Should be used to annotate sections and +/// forms, with extra information about how that section/form will work. +/// +/// Example usage: +/// ``` +/// view! { +/// <Header +/// title: "Example header" +/// description: "Example description" +/// /> +/// } +/// ``` +#[component] +pub fn Header( + /// The title of the header. Must always be present. + #[prop(into)] title: Signal<String>, + /// The description of the header. Hidden when nothing i s + #[prop(optional, into)] description: Signal<String>, +) -> impl IntoView { + let show_description = Signal::derive(move || { + !description.get().is_empty() + }); + + view! { + <div class="m-1.5 mb-5"> + <div class="text-3xl font-bold"> + {title} + </div> + <Show when=move || show_description.get()> + <div> + {description} + </div> + </Show> + </div> + } +} diff --git a/src/components/lists/multi/chips.rs b/src/components/lists/multi/chips.rs index 35197ad..904cbb6 100644 --- a/src/components/lists/multi/chips.rs +++ b/src/components/lists/multi/chips.rs @@ -70,13 +70,22 @@ pub fn Chip( /// passed to the `on_change` prop for each individual `Chip` component. #[component] pub fn ChipsList( + /// The member in the data map that this input affects. #[prop(into)] data_member: String, + /// The data map that contains the list of values. This will be edited as the input changes. #[prop()] data_map: RwSignal<HashMap<String, ValueType>>, + /// The list of strings that should be displayed in the list. #[prop(into)] displayed_text: Signal<Vec<String>>, + /// The list of values that should be displayed in the list. #[prop(into)] values: Signal<Vec<String>>, + /// Indicates if the input should be disabled. #[prop(optional, into)] disabled: Signal<bool>, + /// The label for the header of the input. #[prop(optional, into)] label: String, - #[prop(optional, into)] required: Signal<bool> + /// Indicates if this input is required. + #[prop(optional, into)] required: Signal<bool>, + /// Determines if this list behaves like a checkbox or radio list. + #[prop(default = true.into(), into)] allows_multiple: Signal<bool>, ) -> impl IntoView { let controller = use_selectable_list( data_member.clone(), @@ -88,41 +97,49 @@ pub fn ChipsList( <div class="flex flex-col"> <div class="m-1.5 mt-0 mb-0"> <span class="font-bold">{label}</span> - {displayed_text.get().into_iter().zip(values.get()) - .into_iter() - .map(|(text, value)| { - let value = RwSignal::new(value); + <div class="flex flex-row flex-wrap gap-2 mb-1"> + {move || displayed_text.get().into_iter().zip(values.get()) + .into_iter() + .map(|(text, value)| { + let value = RwSignal::new(value); - let checked = Signal::derive(move || { - controller.selected_list.get().contains(&value.get()) - }); - - let on_change = move || { - // Update the data list by checking if the value is present in it. If so, - // remove it. If not, add it. - controller.selected_list.update(|list| { - let value = value.get(); - if list.contains(&value) { - list.retain(|val| *val != value); - } else { - list.push(value.clone()); - } + let checked = Signal::derive(move || { + controller.selected_list.get().contains(&value.get()) }); - controller.dirty.set(true); - }; - view! { - <Chip - checked=checked - on_change=on_change - value=value - display_text=text - name=data_member.clone() - disabled=disabled - /> - } - }) - .collect_view()} + let on_change = move || { + // Update the data list by checking if the value is present in it. If so, + // remove it. If not, add it. + let value = value.get(); + let list = controller.selected_list.get(); + + if list.contains(&value) { + allows_multiple.get() + .then(|| controller.selected_list.update(|list| list.retain(|v| v != &value))) + .or_else(|| Some(controller.selected_list.set(Vec::new()))); + } else { + allows_multiple.get() + .then(|| controller.selected_list.update(|list| list.push(value.clone()))) + .or_else(|| Some(controller.selected_list.set(vec![value.clone()]))); + } + + controller.dirty.set(true); + }; + + view! { + <Chip + checked=checked + on_change=on_change + value=value + display_text=text + name=data_member.clone() + disabled=disabled + /> + } + }) + .collect_view() + } + </div> </div> <Show when=move || controller.show_errors.get()> <div class="text-red-600 text-sm mr-1.5 ml-1.5"> diff --git a/src/components/lists/single/select.rs b/src/components/lists/single/select.rs index fa5a732..7ccc217 100644 --- a/src/components/lists/single/select.rs +++ b/src/components/lists/single/select.rs @@ -98,7 +98,7 @@ pub fn Select( value="" disabled hidden - selected=raw_value.get().is_empty() + selected={move || raw_value.get().is_empty()} >"Select one..."</option> {move || { value_list.iter().map( diff --git a/src/components/mod.rs b/src/components/mod.rs index d9d9084..a5f210f 100644 --- a/src/components/mod.rs +++ b/src/components/mod.rs @@ -9,9 +9,11 @@ mod text_field; mod utils; mod validated_form; mod lists; +mod toasts; +mod header; pub use self::{ action_button::*, banner::*, dashboard_button::*, lists::*, loading::*, multi_entry::*, panel::*, row::*, text_field::*, - validated_form::* + validated_form::*, toasts::*, header::* }; diff --git a/src/components/text_field.rs b/src/components/text_field.rs index 173ee5a..5e831c1 100644 --- a/src/components/text_field.rs +++ b/src/components/text_field.rs @@ -57,8 +57,8 @@ pub fn OutlinedTextField( #[prop(optional, into)] placeholder: String, #[prop(into)] data_member: String, // should this be an RwSignal?? #[prop()] data_map: RwSignal<HashMap<String, ValueType>>, - #[prop(optional)] input_type: TextFieldType, - #[prop(into, optional)] disabled: Signal<bool>, + #[prop(optional, into)] input_type: Signal<TextFieldType>, + #[prop(optional, into)] disabled: Signal<bool>, #[prop(optional, into)] name: String, #[prop(optional, into)] label: String, #[prop(optional, into)] required: Signal<bool> @@ -69,13 +69,20 @@ pub fn OutlinedTextField( let validator_context = use_validation_context() .expect("FormValidSignal was not found"); - let raw_value = RwSignal::new(data_map.get_untracked() - .get(&data_member) - .unwrap_or(&ValueType::String(None)) - .to_string()); + let raw_value = Signal::derive({ + let data_member = data_member.clone(); + move || + data_map + .get() + .get(&data_member) + .unwrap_or(&ValueType::String(None)) + .to_string() + }); let dirty = RwSignal::new(false); - let error = RwSignal::new(validate(required.get_untracked(), &raw_value.get_untracked(), &input_type)); + let error = Signal::derive(move || + validate(required.get(), &raw_value.get(), &input_type.get()) + ); let show_errors = Signal::derive(move || { dirty.get() && matches!(error.get(), ValidationState::Invalid(_)) }); @@ -90,10 +97,10 @@ pub fn OutlinedTextField( }); }); - let str_type = match input_type { + let str_type = Signal::derive(move || match input_type.get_untracked() { TextFieldType::Number => "number", _ => "text" // This is fine even for emails, as we're doing our own validation. - }; + }); let on_blur = move |_| { // Check validity of input's current value. The value will be updated by on_input, @@ -107,9 +114,7 @@ pub fn OutlinedTextField( let data_member = data_member.clone(); move |e| { let to_parse = event_target_value(&e); - raw_value.set(to_parse.clone()); - error.set(validate(required.get(), &to_parse, &input_type)); - let into_map = match input_type { + let into_map = match input_type.get() { TextFieldType::Number => ValueType::Number(Some(to_parse)), _ => ValueType::String(Some(to_parse)) }; @@ -137,11 +142,7 @@ pub fn OutlinedTextField( disabled={disabled} placeholder={placeholder} prop:name=name - prop:value=move || data_map - .get() // HashMap - .get(&data_member) // Option<ValueType> - .unwrap_or(&ValueType::String(None)) // ValueType - .to_string() + prop:value=raw_value on:input=on_input on:blur=on_blur /> diff --git a/src/components/toasts/mod.rs b/src/components/toasts/mod.rs new file mode 100644 index 0000000..2102229 --- /dev/null +++ b/src/components/toasts/mod.rs @@ -0,0 +1,4 @@ +mod toast_list; +mod toast; + +pub use toast_list::*; \ No newline at end of file diff --git a/src/components/toasts/toast.rs b/src/components/toasts/toast.rs new file mode 100644 index 0000000..7cfeee9 --- /dev/null +++ b/src/components/toasts/toast.rs @@ -0,0 +1,37 @@ +use std::time::Duration; +use leptos::prelude::*; +use leptos_animate::animate; +use leptos_animate::animations::classes::{In, Out}; + +#[component] +pub fn Toast( + #[prop(into)] on_close: Callback<()>, + #[prop(into)] message: Signal<String>, + #[prop(into)] title: Signal<String> +) -> impl IntoView { + set_timeout( + move || { + on_close.run(()) + }, + Duration::from_secs(3) + ); + + view! { + <div + class="flex flex-col rounded-md shadow-lg/33 bg-white p-3 m-1.5 mx-auto min-w-lg max-w-lg" + use:animate=( + In::default() + .source("opacity-0 -translate-y-2 scale-90") + .active("transition-all duration-150 transform-gpu") + .target("opacity-100 translate-y-0 scale-100"), + Out::default() + .source("opacity-100 translate-y-0 scale-100") + .active("transition-all duration-150 transform-gpu") + .target("opacity-0 -translate-y-2 scale-90"), + ) + > + <h3 class="font-bold text-lg">{title}</h3> + <p>{message}</p> + </div> + } +} diff --git a/src/components/toasts/toast_list.rs b/src/components/toasts/toast_list.rs new file mode 100644 index 0000000..94f9dcc --- /dev/null +++ b/src/components/toasts/toast_list.rs @@ -0,0 +1,91 @@ +use leptos::prelude::*; +use crate::components::toasts::toast::Toast; + +#[derive(Clone, Debug)] +pub struct Toast { + id: String, + header: String, + message: String, +} + +impl Toast { + pub fn new() -> Self { + Toast { + id: "".to_owned(), + header: "".to_owned(), + message: "".to_owned(), + } + } + + pub fn header(mut self, header: impl Into<String>) -> Self { + self.header = header.into(); + self + } + + pub fn msg(mut self, msg: impl Into<String>) -> Self { + self.message = msg.into(); + self + } + + pub fn id(mut self, id: impl Into<String>) -> Self { + self.id = id.into(); + self + } +} + +#[derive(Clone, Copy)] +pub struct ToastContext { + messages: RwSignal<Vec<Toast>>, +} + +impl ToastContext { + pub fn new() -> Self { + Self { + messages: RwSignal::new(vec![]), + } + } + + pub fn toast(&mut self, toast: Toast) { + self.messages.update(|list| list.push(toast)); + } +} + +/// # Toast List Component +/// Displays a list of toasts. They must be queued using the [`ToastContext`]. +#[component] +pub fn ToastList( + children: Children, +) -> impl IntoView { + // This context should be used wherever the application might need to use a toast. + // That specific component should also be wrapped in a ToastList component, otherwise + // this context won't exist. + let context = use_context::<ToastContext>() + .unwrap_or_else(provide_toast_context); + + view! { + {children()} + <div class="fixed top-1 left-1/2 right-1/2 -translate-x-1/2 w-full"> + <For + each=move || context.messages.get() + key=|toast| toast.id.clone() + let(Toast { id, header, message }) + > + <Toast + message=message + title=header + on_close=move || { + context.messages.update(|list| + list.retain(|v| v.id != id) + ); + } + /> + </For> + </div> + } +} + +fn provide_toast_context() -> ToastContext { + let context = ToastContext::new(); + provide_context(context); + context +} \ No newline at end of file diff --git a/src/components/validated_form.rs b/src/components/validated_form.rs index c862459..ffdd0c2 100644 --- a/src/components/validated_form.rs +++ b/src/components/validated_form.rs @@ -1,7 +1,7 @@ use leptos::logging::log; use leptos::prelude::*; use leptos::web_sys::SubmitEvent; -use crate::components::ActionButton; +use crate::components::{ActionButton, Header}; /// Indicates the current state of an input. #[derive(Default, Debug, Clone)] @@ -71,7 +71,11 @@ pub fn use_validation_context() -> Option<FormValidationRegistry> { /// Example usage in the view macro: /// ``` /// view! { -/// <ValidatedForm on_submit=Callback::new(move || {/* something here */})> +/// <ValidatedForm +/// on_submit=Callback::new(move || {/* something here */}) +/// title="Example Title" +/// description="Example description." +/// > /// {/* As many input components as you want */} /// </ValidatedForm> /// } @@ -102,6 +106,10 @@ pub fn ValidatedForm( children: Children, /// A callback that runs when the form successfully validates. #[prop(into)] on_submit: Callback<()>, + /// The title of the included header. + #[prop(into)] title: Signal<String>, + /// The description for the included header. + #[prop(optional, into)] description: Signal<String>, ) -> impl IntoView { let validators = RwSignal::new(vec![]); @@ -142,6 +150,10 @@ pub fn ValidatedForm( view! { <form novalidate on:submit=submit_success_event> + <Header + title=title + description=description + /> {children()} <ActionButton on:click=move |_| { @@ -149,7 +161,7 @@ pub fn ValidatedForm( } button_type="submit" > - "Submit form (but actually)" + "Submit" </ActionButton> </form> } diff --git a/src/pages/api/comparisons.rs b/src/pages/api/comparisons.rs index 6691efb..a037abb 100644 --- a/src/pages/api/comparisons.rs +++ b/src/pages/api/comparisons.rs @@ -1,9 +1,13 @@ +use std::collections::HashMap; #[cfg(feature = "ssr")] use crate::pages::utils::server_utils::create_dynamo_client; #[cfg(feature = "ssr")] use aws_sdk_dynamodb::error::ProvideErrorMetadata; +#[cfg(feature = "ssr")] +use leptos::logging::log; + use crate::common::{ ComparisonData, ComparisonType, MapListComparison, NumberComparison, NumberListComparison, TextComparison, TextListComparison, ValueType, @@ -186,6 +190,15 @@ fn create_sports_comparisons() -> Vec<ComparisonData> { #[allow(unused)] fn make_comp_list() -> Vec<ComparisonData> { + let gpa_3 = ComparisonData::new( + "gpa_3", + "weighted_gpa", + ComparisonType::Number(NumberComparison::GreaterThanOrEqual), + ValueType::Number(Some(3.0.to_string())), + "GPA Limits", + "GPA >= 3.0", + ); + let test_comp = ComparisonData::new( "math_sat_comp", "math_sat", @@ -194,21 +207,7 @@ fn make_comp_list() -> Vec<ComparisonData> { "Academic Information", "Math SAT Score > 650", ); - - let service_hours_25 = ComparisonData::new( - "map_sum_comp", - "community_involvement", - ComparisonType::MapList(MapListComparison::FlattenToNumberList( - "service_hours".to_string(), - Box::new(NumberListComparison::Sum(Box::new( - NumberComparison::GreaterThanOrEqual, - ))), - )), - ValueType::Number(Some(25.to_string())), - "Community Involvement", - "25 service hours", - ); - + let service_hours_20 = ComparisonData::new( "service_hours_20", "community_involvement", @@ -219,8 +218,22 @@ fn make_comp_list() -> Vec<ComparisonData> { ))), )), ValueType::Number(Some(20.to_string())), - "Community Involvement", - "20 service hours", + "Community Service", + "20+ service hours", + ); + + let service_hours_25 = ComparisonData::new( + "service_hours_25", + "community_involvement", + ComparisonType::MapList(MapListComparison::FlattenToNumberList( + "service_hours".to_string(), + Box::new(NumberListComparison::Sum(Box::new( + NumberComparison::GreaterThanOrEqual, + ))), + )), + ValueType::Number(Some(25.to_string())), + "Community Service", + "25+ service hours", ); let service_hours_30 = ComparisonData::new( @@ -233,8 +246,8 @@ fn make_comp_list() -> Vec<ComparisonData> { ))), )), ValueType::Number(Some(30.to_string())), - "Community Involvement", - "30 service hours", + "Community Service", + "30+ service hours", ); let residency_southbury = ComparisonData::new( @@ -260,7 +273,7 @@ fn make_comp_list() -> Vec<ComparisonData> { "attended_bas", ComparisonType::Text(TextComparison::Matches), ValueType::String(Some("Yes".to_string())), - "Miscellaneous", + "Additional Eligibility Factors", "Attended BAS", ); @@ -269,7 +282,7 @@ fn make_comp_list() -> Vec<ComparisonData> { "middsouth_church", ComparisonType::Text(TextComparison::Matches), ValueType::String(Some("Yes".to_string())), - "Miscellaneous", + "Additional Eligibility Factors", "Member of Midd-South Church", ); @@ -278,7 +291,7 @@ fn make_comp_list() -> Vec<ComparisonData> { "family_military_service", ComparisonType::Text(TextComparison::Matches), ValueType::String(Some("Yes".to_string())), - "Miscellaneous", + "Additional Eligibility Factors", "Family with Military Service", ); @@ -286,6 +299,7 @@ fn make_comp_list() -> Vec<ComparisonData> { let mut major_comps = Vec::<ComparisonData>::new(); let mut comp_list = vec![ + gpa_3, test_comp, service_hours_20, service_hours_25, @@ -305,8 +319,6 @@ fn make_comp_list() -> Vec<ComparisonData> { #[server(CreateTestComparisons, endpoint = "/comparisons/create-test")] pub async fn create_test_comparisons() -> Result<(), ServerFnError> { - use leptos::logging::log; - let client = create_dynamo_client().await; log!("Creating test comparisons"); @@ -331,8 +343,6 @@ pub async fn create_test_comparisons() -> Result<(), ServerFnError> { #[server] pub async fn get_comparison_info() -> Result<Vec<ComparisonData>, ServerFnError> { - use leptos::logging::log; - let client = create_dynamo_client().await; log!("Getting all comparisons from the database"); @@ -359,3 +369,43 @@ pub async fn get_comparison_info() -> Result<Vec<ComparisonData>, ServerFnError> } } } + +#[server] +pub async fn get_comparisons_categorized() -> Result<HashMap<String, Vec<ComparisonData>>, ServerFnError> { + let client = create_dynamo_client().await; + log!("Getting all comparisons from the database, by category."); + + match client + .scan() + .table_name("leptos-comparison-test") + .send() + .await + { + Ok(output) => { + if let Some(items) = output.items { + log!("Found comparisons, categorizing."); + + let items: Vec<ComparisonData> = serde_dynamo::from_items(items)?; + + let categorized = items.iter().fold( + HashMap::<String, Vec<ComparisonData>>::new(), |mut map, comp| { + // Load each comparison into a map, then return that map. + map.entry(comp.category.clone()) + .and_modify(|vec| vec.push(comp.clone())) + .or_insert(vec![comp.clone()]); + + map + } + ); + + Ok(categorized) + } else { + Err(ServerFnError::new("Couldn't find any comparisons.")) + } + } + Err(err) => { + let msg = err.message().unwrap_or("An unknown error occurred"); + Err(ServerFnError::new(msg)) + } + } +} diff --git a/src/pages/home_page.rs b/src/pages/home_page.rs index 40555b7..b708f36 100644 --- a/src/pages/home_page.rs +++ b/src/pages/home_page.rs @@ -8,7 +8,7 @@ use std::process::{Command, Stdio}; #[cfg(feature = "ssr")] use std::io::Write; -use crate::common::ExpandableInfo; +use crate::common::{ComparisonData, ExpandableInfo}; use crate::pages::UnauthenticatedPage; use crate::pages::utils::get_user_claims; use crate::components::{ActionButton, CheckboxList, Loading, MultiEntry, OutlinedTextField, Panel, RadioList, Row, Select, TextFieldType, ValidatedForm}; @@ -22,6 +22,7 @@ use leptos::task::spawn_local; use leptos::web_sys::HtmlAnchorElement; use leptos::wasm_bindgen::JsCast; use std::collections::HashMap; +use crate::pages::api::get_comparisons_categorized; /// # Get Student Info /// Gets a student's information given their `subject`. @@ -209,6 +210,28 @@ pub fn HomePage() -> impl IntoView { }; //#endregion + let comparison_resource = Resource::new( + move || user_subject.get(), + async move |_| get_comparisons_categorized().await + ); + + let comparison_info = RwSignal::new(HashMap::<String, Vec<ComparisonData>>::new()); + + Effect::new(move || { + match comparison_resource.get() { + Some(Ok(comparisons)) => { + log!("Found comparison info: {:?}", comparisons); + comparison_info.set(comparisons); + } + Some(Err(err)) => { + log!("Error while getting comparisons: {:?}", err); + } + _ => { + log!("An unknown error occurred."); + } + } + }); + view! { <AuthLoaded fallback=Loading> <Authenticated unauthenticated=UnauthenticatedPage> @@ -222,7 +245,11 @@ pub fn HomePage() -> impl IntoView { <Row> <div class="flex flex-col flex-1" /> <Panel> - <ValidatedForm on_submit=Callback::new(on_submit)> + <ValidatedForm + on_submit=Callback::new(on_submit) + title="Home Page Test Form" + description="This really is just a test." + > <Row> <h1 class="text-3xl font-bold"> "Region 15 Scholarship Application (DEMO)" diff --git a/src/pages/loaner_page.rs b/src/pages/loaner_page.rs index 095ed8e..f165956 100644 --- a/src/pages/loaner_page.rs +++ b/src/pages/loaner_page.rs @@ -8,7 +8,7 @@ use serde_dynamo::{from_item, to_item}; use crate::common::ValueType; use crate::common::ExpandableInfo; -use crate::components::{ActionButton, Banner, DashboardButton, OutlinedTextField, Panel, Row, Select, TextFieldType, ValidatedForm}; +use crate::components::{ActionButton, Banner, DashboardButton, OutlinedTextField, Panel, Row, Select, TextFieldType, Toast, ToastContext, ToastList, ValidatedForm}; use chrono::{FixedOffset, TimeZone}; use leptos::Params; use leptos::either::{Either, EitherOf3}; @@ -19,6 +19,13 @@ use leptos_router::hooks::{use_navigate, use_params}; use leptos_router::params::Params; use serde::{Deserialize, Serialize}; use std::collections::HashMap; +use leptos_router::components::Outlet; +use leptos_animate::animate; +use crate::common::animations::pop_in_out; +// Loaner page creates a single page that contains the borrowing/returning buttons +// and a panel for a form. At first, it will show a fallback view. At the borrowing +// path it will show the borrow form, and at the returning path it will show the +// return form. #[derive(Params, PartialEq)] struct LoanerParams { @@ -191,7 +198,7 @@ async fn create_borrow_entry(input: ExpandableInfo) -> Result<(), ServerFnError> /// create a true admin page for this, simply to be able to survey and override/remove information /// from the lists. #[component] -pub fn LoanerPage() -> impl IntoView { +pub fn LoanerShell() -> impl IntoView { // Check URL params. Depending on what string is visible here, we'll display a different form. let params = use_params::<LoanerParams>(); let form_passed = move || { @@ -203,12 +210,6 @@ pub fn LoanerPage() -> impl IntoView { .unwrap_or_default() }; - let form_view = move || match form_passed().as_str() { - "borrowing" => EitherOf3::A(LoanerBorrowForm), - "returning" => EitherOf3::B(LoanerReturnForm), - _ => EitherOf3::C("Choose something from the left.".into_view()), - }; - // We'll create the page here - the sidebar contains all the buttons, while the form // container either shows forms or shows placeholder text. view! { @@ -234,15 +235,36 @@ pub fn LoanerPage() -> impl IntoView { /> </div> <div class="flex flex-2"> - <Panel>{form_view}</Panel> + <Panel> + <Outlet /> + </Panel> </div> </div> </div> } } +#[component] +pub fn LoanerFallback() -> impl IntoView { + view! { + <div + class="flex flex-col items-center justify-center" + use:animate=pop_in_out() + > + <div class="text-3xl font-bold mb-2"> + "Chromebook Loaner Form" + </div> + <div class="text-lg"> + "Select an option from the left to begin." + </div> + </div> + } +} + #[component] pub fn LoanerBorrowForm() -> impl IntoView { + let navigate = use_navigate(); + // Register server actions. let create_entry_action = ServerAction::<CreateBorrowEntry>::new(); @@ -258,12 +280,29 @@ pub fn LoanerBorrowForm() -> impl IntoView { }); }; + //#region Toast Logic + let mut toast_context = expect_context::<ToastContext>(); + Effect::new(move || { + if let Some(Ok(_)) = create_entry_action.value().get() { + create_entry_action.clear(); + toast_context.toast( + Toast::new() + .id(uuid::Uuid::new_v4().to_string()) + .header("Borrower Added!") + .msg("You can take your loaner now.") + ); + navigate("/loaners", Default::default()); + } + }); + //#endregion + view! { - <ValidatedForm on_submit=Callback::new(on_submit)> - <div class="flex flex-col justify-center gap-2 mb-1 py-3 px-2"> - <h2 class="text-2xl font-bold">"Borrower Information"</h2> - <p class="text-lg">"Please fill out the form below."</p> - </div> + <ValidatedForm + use:animate=pop_in_out() + on_submit=Callback::new(on_submit) + title="Borrower Information" + description="Please fill out the form below." + > <Row> <OutlinedTextField label="First Name:" @@ -330,7 +369,7 @@ pub fn LoanerBorrowForm() -> impl IntoView { #[component] pub fn LoanerReturnForm() -> impl IntoView { let navigate = use_navigate(); - + // Register server actions let check_in_action = ServerAction::<CheckInLoaner>::new(); @@ -352,12 +391,19 @@ pub fn LoanerReturnForm() -> impl IntoView { // Create an effect to run after check-in - refreshes the list with another scan request. // This could be beneficial if we ever decided to make multiple loaner kiosks (think SAT days) + let mut toasts = expect_context::<ToastContext>(); Effect::new(move || { if let Some(Ok(_)) = check_in_action.value().get() { // Return to the main page. if let Some(dialog) = dialog_ref.get() { dialog.close(); } + toasts.toast( + Toast::new() + .id(uuid::Uuid::new_v4()) + .header("Check in successful!") + .msg("Don't forget to take your collateral.") + ); navigate("/loaners", Default::default()); check_in_action.clear(); } @@ -383,6 +429,7 @@ pub fn LoanerReturnForm() -> impl IntoView { view! { <dialog + use:animate=pop_in_out() class="p-3 m-auto rounded-md shadow-lg/33 backdrop:backdrop-blur-xs backdrop:transition-backdrop-filter" node_ref=dialog_ref> <h2 class="text-2xl font-bold">"Confirmation"</h2> @@ -398,12 +445,16 @@ pub fn LoanerReturnForm() -> impl IntoView { <ActionButton on:click=close_dialog disabled=dialog_disabled>"Close"</ActionButton> <ActionButton on:click=dialog_check_in disabled=dialog_disabled>"Check In"</ActionButton> </dialog> - <div class="flex flex-col justify-center gap-2 mb-3 py-3 px-2"> - <h2 class="text-2xl font-bold">"Student List"</h2> - <p class="text-lg">"Please select your name from the list."</p> - </div> - <Suspense fallback=move || "Loading...".into_view()> - <div class="flex flex-col gap-2 m-2"> + + <div + class="flex flex-col gap-2 m-2" + use:animate=pop_in_out() + > + <div class="flex flex-col justify-center gap-2 mb-3 py-3 px-2"> + <h2 class="text-2xl font-bold">"Student List"</h2> + <p class="text-lg">"Please select your name from the list."</p> + </div> + <Suspense fallback=move || "Loading...".into_view()> {move || { match return_list_resource.get() { Some(loaner_list) => { @@ -445,7 +496,7 @@ pub fn LoanerReturnForm() -> impl IntoView { None => Either::Right("No loaners found.".into_view()) } }} - </div> - </Suspense> + </Suspense> + </div> } } diff --git a/src/pages/mod.rs b/src/pages/mod.rs index b3d9f41..4da8c68 100644 --- a/src/pages/mod.rs +++ b/src/pages/mod.rs @@ -8,8 +8,9 @@ mod scholarship_info; mod test_page; mod unauthenticated_page; mod utils; +mod provider_contact; pub use self::{ about_page::*, comparison_test::*, home_page::*, loaner_page::*, provider_portal::*, - test_page::*, unauthenticated_page::*, scholarship_info::* + test_page::*, unauthenticated_page::*, scholarship_info::*, provider_contact::* }; diff --git a/src/pages/provider_contact.rs b/src/pages/provider_contact.rs new file mode 100644 index 0000000..98a83d4 --- /dev/null +++ b/src/pages/provider_contact.rs @@ -0,0 +1,224 @@ +use std::collections::HashMap; +use leptos::logging::log; +use leptos::prelude::*; +use leptos_oidc::{AuthLoaded, Authenticated}; +use crate::common::ValueType; +use crate::components::{Banner, Loading, OutlinedTextField, Panel, Row, TextFieldType, Toast, ToastContext, ToastList, ValidatedForm}; +use crate::pages::UnauthenticatedPage; +use crate::pages::utils::get_user_claims; + +#[cfg(feature = "ssr")] +use crate::pages::utils::server_utils::create_dynamo_client; + +#[server] +async fn get_provider_contact(id: String) -> Result<HashMap<String, ValueType>, ServerFnError> { + use aws_sdk_dynamodb::types::AttributeValue; + use aws_sdk_dynamodb::error::ProvideErrorMetadata; + + let client = create_dynamo_client().await; + + log!("Getting contact info for provider {}", id); + + match client + .get_item() + .table_name("leptos-provider-contacts") + .key("subject", AttributeValue::S(id)) + .send() + .await + { + Ok(output) => { + let Some(item) = output.item else { + return Ok(HashMap::new()); + }; + + let map = item.iter().map(|(key, val)| { + let val_type = ValueType::from(val); + + (key.clone(), val_type) + }).collect::<HashMap<String, ValueType>>(); + + Ok(map) + } + Err(err) => { + let msg = err.message().unwrap_or("An unknown error occurred."); + Err(ServerFnError::new(msg)) + } + } +} + +#[server] +async fn put_provider_contact(id: String, contact_info: HashMap<String, ValueType>) -> Result<(), ServerFnError> { + use aws_sdk_dynamodb::error::ProvideErrorMetadata; + use crate::pages::utils::server_utils::into_attr_map; + + let client = create_dynamo_client().await; + + let mut item = into_attr_map(contact_info); + item.insert("subject".to_owned(), aws_sdk_dynamodb::types::AttributeValue::S(id)); + + match client + .put_item() + .table_name("leptos-provider-contacts") + .set_item(Some(item)) + .send() + .await + { + Ok(_) => Ok(()), + Err(err) => { + let msg = err.message().unwrap_or("An unknown error occurred."); + Err(ServerFnError::new(msg)) + } + } +} + +#[component] +pub fn ProviderContactPage() -> impl IntoView { + // Get user claims + let user_claims = get_user_claims(); + let user_id = Memo::new(move |_| { + user_claims.get() + .map(|info| info.claims.subject.clone()) + }); + + // Get contact information + let contact_info = RwSignal::new(HashMap::new()); + let contact_resource = Resource::new( + move || user_id.get(), + async move |id| { + let Some(id) = id else { + return Ok(HashMap::new()); + }; + + get_provider_contact(id).await + } + ); + + Effect::new(move || { + match contact_resource.get() { + Some(Ok(map)) => contact_info.set(map), + Some(Err(e)) => log!("Error getting contact info: {}", e), + None => log!("Contact info resource is not ready yet."), + } + }); + + // Set up submit action + let submit_action = ServerAction::<PutProviderContact>::new(); + + let on_submit = move || { + // Submit the form by reading the contact_info. + submit_action.dispatch(PutProviderContact { + id: user_id.get().unwrap_or_default(), + contact_info: contact_info.get() + }); + }; + + let elements_disabled = Signal::derive(move || { + submit_action.pending().get() + }); + + let mut toasts_context = expect_context::<ToastContext>(); + Effect::new(move || { + submit_action.value().get().is_some() + .then(|| { + toasts_context.toast( + Toast::new() + .id(uuid::Uuid::new_v4()) + .header("Submission Successful") + .msg("You can go back or continue editing your responses.") + ); + + submit_action.clear(); + }); + }); + + // Display contact form. + view! { + <Banner title="R15 Scholarships" logo="/PHS_Stacked_Acronym.png" path="/" /> + <AuthLoaded fallback=Loading> + <Authenticated unauthenticated=UnauthenticatedPage> + <Suspense fallback=Loading> + <div class="flex flex-row"> + <div class="flex flex-col flex-1" /> + <Panel> + <ValidatedForm + on_submit=on_submit + title="Contact Form" + description="Enter your contact information and click submit." + > + {move || { + contact_resource + .get() + .map(|_| { + view! { + <Row> + <OutlinedTextField + label="First Name:" + placeholder="John" + disabled=elements_disabled + data_member="first_name" + data_map=contact_info + required=true + /> + <OutlinedTextField + label="Last Name:" + placeholder="Smith" + disabled=elements_disabled + data_member="last_name" + data_map=contact_info + required=true + /> + </Row> + <Row> + <OutlinedTextField + label="Contact Email:" + placeholder="student@region15.org" + disabled=elements_disabled + data_member="contact_email" + data_map=contact_info + input_type=TextFieldType::Email + required=true + /> + </Row> + <Row> + <OutlinedTextField + label="Phone Number:" + placeholder="123-456-7890" + disabled=elements_disabled + data_member="phone_number" + data_map=contact_info + required=true + /> + </Row> + <Row> + <OutlinedTextField + label="Street Address:" + placeholder="123 Fake Street" + disabled=elements_disabled + data_member="address" + data_map=contact_info + required=true + /> + </Row> + <Row> + <OutlinedTextField + label="Testing Number" + placeholder="Just put a number" + disabled=elements_disabled + data_member="testing_number" + data_map=contact_info + input_type=TextFieldType::Number + required=true + /> + </Row> + } + }) + }} + </ValidatedForm> + </Panel> + <div class="flex flex-col flex-1" /> + </div> + </Suspense> + </Authenticated> + </AuthLoaded> + } +} \ No newline at end of file diff --git a/src/pages/provider_portal.rs b/src/pages/provider_portal.rs index ea833c0..145901b 100644 --- a/src/pages/provider_portal.rs +++ b/src/pages/provider_portal.rs @@ -17,7 +17,7 @@ pub fn ProviderPortal() -> impl IntoView { title="Profile" description="Edit user profile" icon="/Person_Black.png" - path="/" + path="/providers/profile" /> <DashboardButton title="Create Scholarship" diff --git a/src/pages/scholarship_info.rs b/src/pages/scholarship_info.rs index 8cc196d..64a9a60 100644 --- a/src/pages/scholarship_info.rs +++ b/src/pages/scholarship_info.rs @@ -6,11 +6,10 @@ use leptos::prelude::*; use leptos_oidc::{AuthLoaded, Authenticated}; use leptos_router::hooks::{use_navigate, use_params}; use crate::common::{ExpandableInfo, ScholarshipFormParams, SubmitStatus, ValueType}; -use crate::components::{ActionButton, Banner, ChipsList, Loading, OutlinedTextField, Panel, RadioList, Row, TextFieldType, ValidatedForm}; +use crate::components::{ActionButton, Banner, ChipsList, Loading, OutlinedTextField, Panel, RadioList, Row, TextFieldType, Toast, ToastContext, ToastList, ValidatedForm}; use super::UnauthenticatedPage; -use crate::common::ComparisonData; use crate::pages::utils::get_user_claims; -use super::api::{get_comparison_info, get_provider_scholarships, get_scholarship_info, CreateScholarshipInfo, RegisterScholarship, DeleteProviderScholarship}; +use super::api::{get_provider_scholarships, get_scholarship_info, CreateScholarshipInfo, RegisterScholarship, DeleteProviderScholarship, get_comparisons_categorized, CreateTestComparisons}; /// # Scholarship Info Page @@ -41,31 +40,26 @@ pub fn ScholarshipInfoPage() -> impl IntoView { // Remember that we only want to show the page after we've got authentication information // and if there's data for us to use. view! { - <Banner - title="R15 Scholarships" - logo="/PHS_Stacked_Acronym.png" - path="/" - /> - <AuthLoaded fallback=Loading> - <Authenticated unauthenticated=UnauthenticatedPage> - <div class="flex flex-row align-top items-start"> - <div class="flex flex-col flex-1" /> - <ScholarshipList - refresh_token=list_refresh - on_delete=on_delete - /> - <Transition fallback=Loading> - <ScholarshipForm - scholarship_id=scholarship_id - on_submit=move || { - list_refresh.update(|n| *n += 1); - } - /> - </Transition> - <div class="flex flex-col flex-1" /> - </div> - </Authenticated> - </AuthLoaded> + <Banner title="R15 Scholarships" logo="/PHS_Stacked_Acronym.png" path="/" /> + <ToastList> + <AuthLoaded fallback=Loading> + <Authenticated unauthenticated=UnauthenticatedPage> + <div class="flex flex-row align-top items-start"> + <div class="flex flex-col flex-1" /> + <ScholarshipList refresh_token=list_refresh on_delete=on_delete /> + <Transition fallback=Loading> + <ScholarshipForm + scholarship_id=scholarship_id + on_submit=move || { + list_refresh.update(|n| *n += 1); + } + /> + </Transition> + <div class="flex flex-col flex-1" /> + </div> + </Authenticated> + </AuthLoaded> + </ToastList> } } @@ -182,37 +176,41 @@ fn ScholarshipList( }); view! { - <dialog - node_ref=delete_dialog_ref - class="m-auto p-2" - > + <dialog node_ref=delete_dialog_ref class="m-auto p-2"> <h2 class="text-2xl font-bold">"Confirm Deletion"</h2> <p> "Are you sure you want to delete " {move || { - pending_delete.get().map(|s| { - s.data.get("name").unwrap_or(&ValueType::String(None)) - .as_string() - .unwrap_or_default() - .unwrap_or("<no name found>".to_string()) - }) - }} - "?" + pending_delete + .get() + .map(|s| { + s.data + .get("name") + .unwrap_or(&ValueType::String(None)) + .as_string() + .unwrap_or_default() + .unwrap_or("<no name found>".to_string()) + }) + }} "?" </p> <ActionButton on:click=move |_| { - let subject = pending_delete.get().map(|s| s.subject.clone()).unwrap_or_default(); + let subject = pending_delete + .get() + .map(|s| s.subject.clone()) + .unwrap_or_default(); log!("Deleting scholarship with subject {}", subject); - delete_action.dispatch(DeleteProviderScholarship { - scholarship_id: subject, - provider_id: provider_id.get().unwrap_or_default() - }); + delete_action + .dispatch(DeleteProviderScholarship { + scholarship_id: subject, + provider_id: provider_id.get().unwrap_or_default(), + }); } disabled=modal_disabled - >"Confirm"</ActionButton> - <ActionButton - on:click=move |_| pending_delete.set(None) - >"Cancel"</ActionButton> + > + "Confirm" + </ActionButton> + <ActionButton on:click=move |_| pending_delete.set(None)>"Cancel"</ActionButton> </dialog> <div class="w-75"> <Panel> @@ -222,31 +220,42 @@ fn ScholarshipList( <Transition fallback=Loading> <div class="flex flex-col gap-2"> {move || { - scholarships.get().map(|result| { - match result { - Ok(list) => { - let views = list.iter().map(|entry| { - view! { - <ScholarshipListEntry scholarship=entry.clone() - on_delete=Callback::new(on_item_delete)/> - } - }); - Either::Left(views.collect_view()) + scholarships + .get() + .map(|result| { + match result { + Ok(list) => { + let views = list + .iter() + .map(|entry| { + view! { + <ScholarshipListEntry + scholarship=entry.clone() + on_delete=Callback::new(on_item_delete) + /> + } + }); + Either::Left(views.collect_view()) + } + Err(err) => { + Either::Right( + view! { + <div> + <p>"Failed to load scholarship list: "{err.to_string()}</p> + </div> + }, + ) + } } - Err(err) => { - Either::Right(view! { - <div> - <p>"Failed to load scholarship list: "{err.to_string()}</p> - </div> - }) - } - } - }).collect_view() + }) + .collect_view() }} </div> <div> - <div class="p-2 bg-red-800 rounded-md text-center text-white hover:bg-red-900 transition-all" - on:click=create_on_click> + <div + class="p-2 bg-red-800 rounded-md text-center text-white hover:bg-red-900 transition-all cursor-pointer" + on:click=create_on_click + > "Create New" </div> </div> @@ -306,13 +315,15 @@ fn ScholarshipListEntry( <span>{name}</span> </div> <div class="flex flex-row"> - <div class="p-2 flex-1 bg-red-800 border-r border-white rounded-bl-md text-white text-center + <div + class="p-2 flex-1 bg-red-800 border-r border-white rounded-bl-md text-white text-center hover:bg-red-900 cursor-pointer transition-all" on:click=edit_click > "Edit" </div> - <div class="p-2 flex-1 bg-red-800 border-l border-white rounded-br-md text-white text-center + <div + class="p-2 flex-1 bg-red-800 border-l border-white rounded-br-md text-white text-center hover:bg-red-900 cursor-pointer transition-all" on:click=move |_| on_delete.run(scholarship.clone()) > @@ -350,15 +361,6 @@ fn ScholarshipForm( /// submission fails, this function is not run. #[prop(into)] on_submit: Callback<()> ) -> impl IntoView { - // let result_msg = Signal::derive(move || { - // match submit_status.get() { - // SubmitStatus::Idle => "".into(), - // SubmitStatus::Sending => "Sending submission...".into(), - // SubmitStatus::Success => "Success".into(), - // SubmitStatus::Error(msg) => format!("Error: {}", msg), - // } - // }); - let submit_action = ServerAction::<CreateScholarshipInfo>::new(); let submit_status = RwSignal::new(SubmitStatus::Idle); @@ -382,18 +384,20 @@ fn ScholarshipForm( } } }); - - let comparison_list: Resource<Vec<ComparisonData>> = Resource::new( - move || scholarship_id.get(), // There's no input to this function. + + let comparison_lists = Resource::new( + move || scholarship_id.get().is_some(), async move |_| { - get_comparison_info().await - .unwrap_or_else(|e| { - log!("Failed to get comparison info: {:?}", e); - Vec::new() - }) + get_comparisons_categorized().await } ); + Effect::new(move || { + if let Some(Ok(map)) = comparison_lists.get() { + log!("Available categories: {:?}", map.keys()); + } + }); + let scholarship_info = Resource::new( move || scholarship_id.get(), async move |opt_id| { @@ -406,31 +410,66 @@ fn ScholarshipForm( ); let form_data = RwSignal::new(HashMap::new()); + let chips_data = RwSignal::new(HashMap::new()); Effect::new(move || { if let Some(Ok(scholarship)) = scholarship_info.get() { + // Get the default chips data. + let chips_default = if let Some(ValueType::Map(Some(map))) = scholarship.data.get("requirements") { + map.clone() + } else { + HashMap::new() + }; + + chips_data.set(chips_default); form_data.set(scholarship.data); } }); - - let comparison_ids = Memo::new(move |_| { - comparison_list.get().map(|list| list.iter() - .map(|comp| comp.clone().id) + + let get_comp_category = move |category: &str| { + if let Some(Ok(map)) = comparison_lists.get() { + map.get(category).unwrap_or(&Vec::new()).clone() + } else { + Vec::new() + } + }; + + let get_comp_ids = move |category: &str| { + get_comp_category(category) + .into_iter() + .map(|comp| comp.id) .collect::<Vec<String>>() - ).unwrap_or_default() - }); - - let comparison_text = Memo::new(move |_| { - comparison_list.get().map(|list| list.iter() - .map(|comp| comp.clone().display_text) + }; + + let get_comp_text = move |category: &str| { + get_comp_category(category) + .into_iter() + .map(|comp| comp.display_text) .collect::<Vec<String>>() - ).unwrap_or_default() - }); + }; + + // Get comparison lists. + let sports_ids = Signal::derive(move || get_comp_ids("Sports Participation")); + let sports_text = Signal::derive(move || get_comp_text("Sports Participation")); + + let misc_ids = Signal::derive(move || get_comp_ids("Additional Eligibility Factors")); + let misc_text = Signal::derive(move || get_comp_text("Additional Eligibility Factors")); + + let comm_ids = Signal::derive(move || get_comp_ids("Community Service")); + let comm_text = Signal::derive(move || get_comp_text("Community Service")); + + let res_ids = Signal::derive(move || get_comp_ids("Residency")); + let res_text = Signal::derive(move || get_comp_text("Residency")); + + let gpa_ids = Signal::derive(move || get_comp_ids("GPA Limits")); + let gpa_text = Signal::derive(move || get_comp_text("GPA Limits")); // We'll collect the scholarship's name, num_awards, amount_per_award, total_awards, // fafsa_required, award_to, transcript_required, recipient_selection, essay_requirement (and prompt) // award_night_remarks + let mut toasts = expect_context::<ToastContext>(); + let on_submit = move |_| { let mut info = ExpandableInfo::new(scholarship_id.get().unwrap_or_default()); info.data = form_data.get(); @@ -440,130 +479,200 @@ fn ScholarshipForm( info }); }; + + Effect::new(move || { + submit_action.value().get().is_some() + .then(|| { + log!("Displaying toasts!"); + toasts.toast( + Toast::new() + .id(uuid::Uuid::new_v4()) + .msg("Succesfully submitted.") + ); + + submit_action.clear(); + }); + }); + + let create_comps = ServerAction::<CreateTestComparisons>::new(); view! { <Panel> <Show when=move || scholarship_id.get().is_some() - fallback=|| view! { <p>"Choose a scholarship from the right, or create a new one."</p> } + fallback=|| { + view! { <p>"Choose a scholarship from the right, or create a new one."</p> } + } > <Suspense fallback=Loading> - <ValidatedForm on_submit=Callback::new(on_submit)> + <ValidatedForm + on_submit=Callback::new(on_submit) + title="Scholarship Info Form" + description="Create or edit a scholarship. Input all information and click Submit." + > {move || { - scholarship_info.get() + scholarship_info + .get() .map(|res_scholarship| { match res_scholarship { Ok(_) => { - Either::Left(view! { - <Row> - <h1 class="text-3xl font-bold"> - "Scholarship Info Form (test)" - </h1> - </Row> - <Row> - <OutlinedTextField - label="Scholarship Name" - placeholder="Example Scholarship Name" - disabled=elements_disabled - data_member="name" - data_map=form_data - /> - </Row> - <Row> - <OutlinedTextField - label="Amount per award: (if multiple, enter the highest value)" - placeholder="Enter an amount..." - disabled=elements_disabled - data_member="amount_per_award" - data_map=form_data - input_type=TextFieldType::Number - /> - </Row> - <Row> - <OutlinedTextField - label="Total number of awards:" - placeholder="Enter an amount..." - disabled=elements_disabled - data_member="num_awards" - data_map=form_data - input_type=TextFieldType::Number - /> - </Row> - <Row> - <OutlinedTextField - label="Total amount of all awards:" - placeholder="Enter an amount..." - disabled=elements_disabled - data_member="total_awards" - data_map=form_data - input_type=TextFieldType::Number - /> - </Row> - <Row> - <RadioList - data_member="fafsa_required" - data_map=form_data - items=vec!["Yes".to_string(), "No".to_string()] - disabled=elements_disabled - label="Do you require student financial information?" - /> - </Row> - <Row> - <RadioList - data_member="transcript_required" - data_map=form_data - items=vec!["Yes".to_string(), "No".to_string()] - disabled=elements_disabled - label="Do you require a student transcript?" - /> - </Row> - <Row> - <RadioList - data_member="award_to" - data_map=form_data - items=vec!["School".to_string(), "Student".to_string()] - disabled=elements_disabled - label="Will the award be made to the school or the student?" - /> - </Row> - <Row> - <RadioList - data_member="essay_required" - data_map=form_data - items=vec!["Yes".to_string(), "No".to_string()] - disabled=elements_disabled - label="Do you require a student essay?" - /> - </Row> - <Row> - <RadioList - data_member="essay_prompt" - data_map=form_data - items=vec!["Test 1", "Test 2", "Test 3"].iter().map(|s| s.to_string()).collect() - disabled=elements_disabled - label="If so, select a prompt from the list below." - /> - </Row> - <Row> - <ChipsList - label="Scholarship Requirements" - data_member="requirements" - data_map=form_data - values=comparison_ids - displayed_text=comparison_text - /> - </Row> - }) + Either::Left( + view! { + <Row> + <h1 class="text-3xl font-bold"> + "Scholarship Info Form (test)" + </h1> + </Row> + <Row> + <OutlinedTextField + label="Scholarship Name" + placeholder="Example Scholarship Name" + disabled=elements_disabled + data_member="name" + data_map=form_data + /> + </Row> + <Row> + <OutlinedTextField + label="Amount per award: (if multiple, enter the highest value)" + placeholder="Enter an amount..." + disabled=elements_disabled + data_member="amount_per_award" + data_map=form_data + input_type=TextFieldType::Number + /> + </Row> + <Row> + <OutlinedTextField + label="Total number of awards:" + placeholder="Enter an amount..." + disabled=elements_disabled + data_member="num_awards" + data_map=form_data + input_type=TextFieldType::Number + /> + </Row> + <Row> + <OutlinedTextField + label="Total amount of all award(s): (estimates are acceptable)" + placeholder="Enter an amount..." + disabled=elements_disabled + data_member="total_awards" + data_map=form_data + input_type=TextFieldType::Number + /> + </Row> + <Row> + <RadioList + data_member="fafsa_required" + data_map=form_data + items=vec!["Yes".to_string(), "No".to_string()] + disabled=elements_disabled + label="Do you require student FAFSA information?" + /> + </Row> + <Row> + <RadioList + data_member="transcript_required" + data_map=form_data + items=vec!["Yes".to_string(), "No".to_string()] + disabled=elements_disabled + label="Do you require a student transcript?" + /> + </Row> + <Row> + <RadioList + data_member="award_to" + data_map=form_data + items=vec!["School".to_string(), "Student".to_string()] + disabled=elements_disabled + label="Will the award be made to the school or the student?" + /> + </Row> + <Row> + <RadioList + data_member="essay_required" + data_map=form_data + items=vec!["Yes".to_string(), "No".to_string()] + disabled=elements_disabled + label="Do you require a student essay?" + /> + </Row> + <Row> + <RadioList + data_member="essay_prompt" + data_map=form_data + items=vec!["Test 1", "Test 2", "Test 3"] + .iter() + .map(|s| s.to_string()) + .collect() + disabled=elements_disabled + label="If so, select a prompt from the list below." + /> + </Row> + <Row> + <ChipsList + label="GPA Requirements" + data_member="gpa" + data_map=chips_data + values=gpa_ids + displayed_text=gpa_text + /> + </Row> + <Row> + <ChipsList + label="Sports Participation" + data_member="sports_participation" + data_map=chips_data + values=sports_ids + displayed_text=sports_text + /> + </Row> + <Row> + <ChipsList + label="Community Service" + data_member="community_service" + data_map=chips_data + values=comm_ids + displayed_text=comm_text + /> + </Row> + <Row> + <ChipsList + label="Residency" + data_member="residency" + data_map=chips_data + values=res_ids + displayed_text=res_text + /> + </Row> + <Row> + <ChipsList + label="Additional Eligibility Factors" + data_member="misc" + data_map=chips_data + values=misc_ids + displayed_text=misc_text + /> + </Row> + }, + ) } Err(err) => { - Either::Right(view! { - <p>"Error while getting scholarship: "{err.to_string()}</p> - }) + Either::Right( + view! { + <p>"Error while getting scholarship: "{err.to_string()}</p> + }, + ) } } - }).collect_view() + }) + .collect_view() }} </ValidatedForm> + <ActionButton on:click=move |_| { + create_comps.dispatch(CreateTestComparisons {}); + }>"Create Comparisons"</ActionButton> </Suspense> </Show> </Panel> diff --git a/src/pages/utils.rs b/src/pages/utils.rs index 03cf49e..898ed2f 100644 --- a/src/pages/utils.rs +++ b/src/pages/utils.rs @@ -9,7 +9,9 @@ use crate::common::UserClaims; /// dependencies cannot be compiled for WASM (nor should they be). #[cfg(feature = "ssr")] pub mod server_utils { + use std::collections::HashMap; use aws_config::SdkConfig; + use crate::common::ValueType; /// Creates an [`SdkConfig`] struct for use with AWS SDK structs. pub async fn create_aws_config() -> SdkConfig { @@ -20,6 +22,10 @@ pub mod server_utils { pub async fn create_dynamo_client() -> aws_sdk_dynamodb::Client { aws_sdk_dynamodb::Client::new(&create_aws_config().await) } + + pub fn into_attr_map(map: HashMap<String, ValueType>) -> HashMap<String, aws_sdk_dynamodb::types::AttributeValue> { + map.into_iter().map(|(k, v)| (k, v.into())).collect() + } } /// Gets the current user claims. This function should only be used in an area that has