diff --git a/Cargo.lock b/Cargo.lock index 13600e57e..d4f569f0c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -144,26 +144,25 @@ dependencies = [ [[package]] name = "async-global-executor" -version = "2.0.4" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c290043c9a95b05d45e952fb6383c67bcb61471f60cfa21e890dba6654234f43" +checksum = "fd8b508d585e01084059b60f06ade4cb7415cd2e4084b71dd1cb44e7d3fb9880" dependencies = [ "async-channel", "async-executor", "async-io", - "async-mutex", + "async-lock", "blocking", "futures-lite", - "num_cpus", "once_cell", "tokio", ] [[package]] name = "async-io" -version = "1.6.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a811e6a479f2439f0c04038796b5cfb3d2ad56c230e0f2d3f7b04d68cfee607b" +checksum = "e5e18f61464ae81cde0a23e713ae8fd299580c54d697a35820cfd0625b8b0e07" dependencies = [ "concurrent-queue", "futures-lite", @@ -187,15 +186,6 @@ dependencies = [ "event-listener", ] -[[package]] -name = "async-mutex" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479db852db25d9dbf6204e6cb6253698f175c15726470f78af0d918e99d6156e" -dependencies = [ - "event-listener", -] - [[package]] name = "async-std" version = "1.11.0" @@ -253,9 +243,9 @@ checksum = "30696a84d817107fc028e049980e09d5e140e8da8f1caeb17e8e950658a3cea9" [[package]] name = "async-trait" -version = "0.1.53" +version = "0.1.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed6aa3524a2dfcf9fe180c51eae2b58738348d819517ceadf95789c51fff7600" +checksum = "96cf8829f67d2eab0b2dfa42c5d0ef737e0724e4a82b01b3e292456202b19716" dependencies = [ "proc-macro2", "quote", @@ -452,9 +442,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.9.1" +version = "3.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a45a46ab1f2412e53d3a0ade76ffad2025804294569aae387231a0cd6e0899" +checksum = "37ccbd214614c6783386c1af30caf03192f17891059cecc394b4fb119e363de3" [[package]] name = "byteorder" @@ -548,9 +538,9 @@ dependencies = [ [[package]] name = "cfg-expr" -version = "0.10.2" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e068cb2806bbc15b439846dc16c5f89f8599f2c3e4d73d4449d38f9b2f0b6c5" +checksum = "0aacacf4d96c24b2ad6eb8ee6df040e4f27b0d0b39a5710c30091baa830485db" dependencies = [ "smallvec", ] @@ -864,38 +854,14 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35" -[[package]] -name = "darling" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d706e75d87e35569db781a9b5e2416cff1236a47ed380831f959382ccd5f858" -dependencies = [ - "darling_core 0.10.2", - "darling_macro 0.10.2", -] - [[package]] name = "darling" version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a01d95850c592940db9b8194bc39f4bc0e89dee5c4265e4b1807c34a9aba453c" dependencies = [ - "darling_core 0.13.4", - "darling_macro 0.13.4", -] - -[[package]] -name = "darling_core" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0c960ae2da4de88a91b2d920c2a7233b400bc33cb28453a2987822d8392519b" -dependencies = [ - "fnv", - "ident_case", - "proc-macro2", - "quote", - "strsim 0.9.3", - "syn", + "darling_core", + "darling_macro", ] [[package]] @@ -912,37 +878,27 @@ dependencies = [ "syn", ] -[[package]] -name = "darling_macro" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b5a2f4ac4969822c62224815d069952656cadc7084fdca9751e6d959189b72" -dependencies = [ - "darling_core 0.10.2", - "quote", - "syn", -] - [[package]] name = "darling_macro" version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835" dependencies = [ - "darling_core 0.13.4", + "darling_core", "quote", "syn", ] [[package]] name = "dashmap" -version = "5.3.3" +version = "5.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "391b56fbd302e585b7a9494fb70e40949567b1cf9003a8e4a6041a1687c26573" +checksum = "3495912c9c1ccf2e18976439f4443f3fee0fd61f424ff99fde6a66b15ecb448f" dependencies = [ "cfg-if", "hashbrown 0.12.1", "lock_api", + "parking_lot_core 0.9.3", ] [[package]] @@ -1202,13 +1158,11 @@ dependencies = [ [[package]] name = "flate2" -version = "1.0.23" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b39522e96686d38f4bc984b9198e3a0613264abaebaff2c5c918bfa6b6da09af" +checksum = "f82b0f4c27ad9f8bfd1f3208d882da2b09c301bc1c828fd3a00d0216d2fbbff6" dependencies = [ - "cfg-if", "crc32fast", - "libc", "miniz_oxide", ] @@ -1983,9 +1937,9 @@ dependencies = [ [[package]] name = "http-body" -version = "0.4.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ff4f84919677303da5f147645dbea6b1881f368d03ac84e1dc09031ebd7b2c6" +checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" dependencies = [ "bytes", "http", @@ -2012,9 +1966,9 @@ checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" [[package]] name = "hyper" -version = "0.14.18" +version = "0.14.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b26ae0a80afebe130861d90abf98e3814a4f28a4c6ffeb5ab8ebb2be311e0ef2" +checksum = "42dc3c131584288d375f2d07f822b0cb012d8c6fb899a5b9fdb3cb7eb9b6004f" dependencies = [ "bytes", "futures-channel", @@ -2105,9 +2059,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "1.8.1" +version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f647032dfaa1f8b6dc29bd3edb7bbef4861b8b8007ebb118d6db284fd59f6ee" +checksum = "e6012d540c5baa3589337a98ce73408de9b5a25ec9fc2c6fd6be8f0d39e0ca5a" dependencies = [ "autocfg", "hashbrown 0.11.2", @@ -2227,6 +2181,20 @@ dependencies = [ "walkdir", ] +[[package]] +name = "jni" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6df18c2e3db7e453d3c6ac5b3e9d5182664d28788126d39b91f2d1e22b017ec" +dependencies = [ + "cesu8", + "combine", + "jni-sys", + "log", + "thiserror", + "walkdir", +] + [[package]] name = "jni-sys" version = "0.3.0" @@ -2470,9 +2438,9 @@ dependencies = [ [[package]] name = "loom" -version = "0.5.5" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85eb735cf3c8ebac6cc3655c5da2f4a088b6a19133aa482471a21ba0eb5d83ab" +checksum = "ff50ecb28bb86013e935fb6683ab1f6d3a20016f123c76fd4c27470076ac30f5" dependencies = [ "cfg-if", "generator", @@ -2485,21 +2453,18 @@ dependencies = [ [[package]] name = "lru" -version = "0.7.5" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32613e41de4c47ab04970c348ca7ae7382cf116625755af070b008a15516a889" +checksum = "8015d95cb7b2ddd3c0d32ca38283ceb1eea09b4713ee380bceb942d85a244228" dependencies = [ "hashbrown 0.11.2", ] [[package]] name = "lz4_flex" -version = "0.9.2" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42c51df9d8d4842336c835df1d85ed447c4813baa237d033d95128bf5552ad8a" -dependencies = [ - "twox-hash", -] +checksum = "74141c8af4bb8136dafb5705826bdd9dce823021db897c1129191804140ddf84" [[package]] name = "mac" @@ -2614,9 +2579,9 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.5.1" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2b29bd4bc3f33391105ebee3589c19197c4271e3e5a9ec9bfe8127eeff8f082" +checksum = "6f5c75688da582b8ffc1f1799e9db273f32133c49e048f614d22ec3256773ccc" dependencies = [ "adler", ] @@ -2662,9 +2627,9 @@ dependencies = [ [[package]] name = "ndk" -version = "0.4.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d64d6af06fde0e527b1ba5c7b79a6cc89cfc46325b0b2887dffe8f70197e0c3c" +checksum = "2032c77e030ddee34a6787a64166008da93f6a352b629261d0fee232b8742dd4" dependencies = [ "bitflags", "jni-sys", @@ -2680,39 +2645,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" [[package]] -name = "ndk-glue" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3648f3609716eb7dbf5f5b5d4b84fcd67dd4c34efcdb12e4a6c0929c2ac48349" -dependencies = [ - "lazy_static", - "libc", - "log", - "ndk", - "ndk-context", - "ndk-macro", - "ndk-sys", -] - -[[package]] -name = "ndk-macro" -version = "0.2.0" +name = "ndk-sys" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05d1c6307dc424d0f65b9b06e94f88248e6305726b14729fd67a5e47b2dc481d" +checksum = "6e5a6ae77c8ee183dcbbba6150e2e6b9f3f4196a7666c02a715a95692ec1fa97" dependencies = [ - "darling 0.10.2", - "proc-macro-crate 0.1.5", - "proc-macro2", - "quote", - "syn", + "jni-sys", ] -[[package]] -name = "ndk-sys" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1bcdd74c20ad5d95aacd60ef9ba40fdf77f767051040541df557b7a9b2a2121" - [[package]] name = "new_debug_unreachable" version = "1.0.4" @@ -2896,18 +2836,18 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.10.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9" +checksum = "7709cef83f0c1f58f666e746a08b21e0085f7440fa6a29cc194d68aac97a4225" [[package]] name = "open" -version = "2.1.2" +version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0524af9508f9b5c4eb41dce095860456727748f63b478d625f119a70e0d764a" +checksum = "f2423ffbf445b82e58c3b1543655968923dd06f85432f10be2bb4f1b7122f98c" dependencies = [ "pathdiff", - "winapi", + "windows-sys", ] [[package]] @@ -2944,9 +2884,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.73" +version = "0.9.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d5fd19fb3e0a8191c1e34935718976a3e70c112ab9a24af6d7cadccd9d90bc0" +checksum = "835363342df5fba8354c5b453325b110ffd54044e588c539cf2f20a8014e4cb1" dependencies = [ "autocfg", "cc", @@ -2957,9 +2897,9 @@ dependencies = [ [[package]] name = "os_info" -version = "3.3.0" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04304d855bb5385d4b595edf0147b8e281871766b75dd4c87b2bdf3c9e5c2d19" +checksum = "0eca3ecae1481e12c3d9379ec541b238a16f0b75c9a409942daa8ec20dbfdb62" dependencies = [ "log", "serde", @@ -3076,9 +3016,9 @@ dependencies = [ [[package]] name = "parking_lot" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f5ec2493a61ac0506c0f4199f99070cbe83857b0337006a30f3e6719b8ef58" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" dependencies = [ "lock_api", "parking_lot_core 0.9.3", @@ -3559,13 +3499,13 @@ dependencies = [ [[package]] name = "regex" -version = "1.5.5" +version = "1.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286" +checksum = "d83f127d94bdbcda4c8cc2e50f6f84f4b611f69c902699ca385a39c3a75f9ff1" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.6.25", + "regex-syntax 0.6.26", ] [[package]] @@ -3574,7 +3514,7 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" dependencies = [ - "regex-syntax 0.6.25", + "regex-syntax 0.6.26", ] [[package]] @@ -3585,9 +3525,9 @@ checksum = "8e931c58b93d86f080c734bfd2bce7dd0079ae2331235818133c8be7f422e20e" [[package]] name = "regex-syntax" -version = "0.6.25" +version = "0.6.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" +checksum = "49b3de9ec5dc0a3417da371aab17d729997c15010e7fd24ff707773a33bddb64" [[package]] name = "reindexer" @@ -3715,9 +3655,9 @@ dependencies = [ [[package]] name = "rust_decimal" -version = "1.23.1" +version = "1.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22dc69eadbf0ee2110b8d20418c0c6edbaefec2811c4963dc17b6344e11fe0f8" +checksum = "e2ee7337df68898256ad0d4af4aad178210d9e44d2ff900ce44064a97cd86530" dependencies = [ "arrayvec 0.7.2", "num-traits", @@ -3881,11 +3821,10 @@ dependencies = [ [[package]] name = "sea-orm-migration" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6be15a93dc65a67bb3615fc0fe45c22581b25b27123520e18fb66cd87f429f4c" +checksum = "15589f057677f57bea393572bd8eb9e8feb843a5f09b4fa518be6cef3a6ffedc" dependencies = [ - "async-std", "async-trait", "clap", "dotenv", @@ -4046,6 +3985,9 @@ name = "semver" version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8cb243bdfdb5936c8dc3c45762a19d12ab4550cdc753bc247637d4ec35a040fd" +dependencies = [ + "serde", +] [[package]] name = "semver-parser" @@ -4130,11 +4072,10 @@ dependencies = [ [[package]] name = "serde_with" -version = "1.13.0" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b827f2113224f3f19a665136f006709194bdfdcb1fdc1e4b2b5cbac8e0cced54" +checksum = "678b5a069e50bf00ecd22d0cd8ddf7c236f68581b03db652061ed5eb13a312ff" dependencies = [ - "rustversion", "serde", "serde_with_macros", ] @@ -4145,7 +4086,7 @@ version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e182d6ec6f05393cc0e5ed1bf81ad6db3a8feedf8ee515ecdd369809bcce8082" dependencies = [ - "darling 0.13.4", + "darling", "proc-macro2", "quote", "syn", @@ -4362,7 +4303,7 @@ dependencies = [ "tracing-log", "tracing-subscriber", "url 2.2.2", - "uuid 1.0.0", + "uuid 1.1.1", ] [[package]] @@ -4376,6 +4317,7 @@ dependencies = [ "num-format", "open", "reqwest", + "ron", "serde", "serde_json", "shared", @@ -4387,6 +4329,7 @@ dependencies = [ "tracing-appender", "tracing-log", "tracing-subscriber", + "url 2.2.2", ] [[package]] @@ -4536,12 +4479,6 @@ dependencies = [ "loom", ] -[[package]] -name = "static_assertions" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" - [[package]] name = "stdweb" version = "0.4.20" @@ -4599,7 +4536,7 @@ checksum = "213494b7a2b503146286049378ce02b482200519accc31872ee8be91fa820a08" dependencies = [ "new_debug_unreachable", "once_cell", - "parking_lot 0.12.0", + "parking_lot 0.12.1", "phf_shared 0.10.0", "precomputed-hash", "serde", @@ -4633,12 +4570,6 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" -[[package]] -name = "strsim" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c" - [[package]] name = "strsim" version = "0.10.0" @@ -4668,9 +4599,9 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.95" +version = "1.0.96" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbaf6116ab8924f39d52792136fb74fd60a80194cf1b1c6ffa6453eef1c3f942" +checksum = "0748dd251e24453cb8717f0354206b91557e4ec8703673a4b30208f2abaf1ebf" dependencies = [ "proc-macro2", "quote", @@ -4696,7 +4627,7 @@ version = "6.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1a45a1c4c9015217e12347f2a411b57ce2c4fc543913b14b6fe40483328e709" dependencies = [ - "cfg-expr 0.10.2", + "cfg-expr 0.10.3", "heck 0.4.0", "pkg-config", "toml", @@ -4801,9 +4732,9 @@ dependencies = [ [[package]] name = "tao" -version = "0.8.5" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df895eb66ff23d1824055114d6fbdd2c297bf70ad85349a4adaee0f8b2a860d1" +checksum = "53da5dd98a3c605a3ca8fe967d7c50eba8a36072ff13e04e24402b2c492ac55a" dependencies = [ "bitflags", "cairo-rs", @@ -4822,22 +4753,25 @@ dependencies = [ "glib-sys", "gtk", "instant", + "jni 0.19.0", "lazy_static", "libayatana-appindicator", "libc", "log", "ndk", - "ndk-glue", + "ndk-context", "ndk-sys", "objc", + "once_cell", "parking_lot 0.11.2", + "paste", "raw-window-handle", "scopeguard", "serde", "tao-core-video-sys", "unicode-segmentation", - "windows 0.30.0", - "windows_macros", + "windows 0.37.0", + "windows-implement", "x11-dl", ] @@ -4866,9 +4800,9 @@ dependencies = [ [[package]] name = "tauri" -version = "1.0.0-rc.11" +version = "1.0.0-rc.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4c7350af2191f3b7a288cadd672a01fc47c8c3610f990fc5e9b78b9953e2e82" +checksum = "81af088a87f908dab3a268f92e3c331e911bed6b1756bbfaeadedfe9dd40fe4f" dependencies = [ "anyhow", "attohttpc", @@ -4912,20 +4846,21 @@ dependencies = [ "thiserror", "tokio", "url 2.2.2", - "uuid 1.0.0", + "uuid 1.1.1", "webkit2gtk", "webview2-com", - "windows 0.30.0", + "windows 0.37.0", ] [[package]] name = "tauri-build" -version = "1.0.0-rc.9" +version = "1.0.0-rc.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae2a4dfb8e5d8a5a4325fda01e9ddf327db23115dce0f54a4a3f9e8f74341f28" +checksum = "9bbf472a3caf7ec80358996056fe56f0ff3f91f71bc42e96efdbdc3c2618511a" dependencies = [ "anyhow", "cargo_toml", + "heck 0.4.0", "semver 1.0.9", "serde_json", "tauri-utils", @@ -4934,9 +4869,9 @@ dependencies = [ [[package]] name = "tauri-codegen" -version = "1.0.0-rc.7" +version = "1.0.0-rc.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d7f042dc907b65468e33495b9d48982dec21216f5b7e9281eb10214aa028a0f" +checksum = "0ae4ebcd190eb22fcee58b40b77d32f5b372a20440833bf27ae7921db131ecca" dependencies = [ "base64", "brotli", @@ -4945,20 +4880,21 @@ dependencies = [ "proc-macro2", "quote", "regex", + "semver 1.0.9", "serde", "serde_json", "sha2", "tauri-utils", "thiserror", - "uuid 1.0.0", + "uuid 1.1.1", "walkdir", ] [[package]] name = "tauri-macros" -version = "1.0.0-rc.7" +version = "1.0.0-rc.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd358b30472a20c70d861b579960da1aee95232e833f72628d5f8dacf9cb2bcc" +checksum = "cc72220c1e52ecb33b4d9f04ff171009f100d28789c18049e19e374ec0355531" dependencies = [ "heck 0.4.0", "proc-macro2", @@ -4970,9 +4906,9 @@ dependencies = [ [[package]] name = "tauri-runtime" -version = "0.5.1" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffba4a1d7e3a5770253c7dff2dd16553ae7f04c0505ac728447083c2e9bf2d09" +checksum = "dc343e974f76c0f5471da85f87510bb54dfc9a7664f3e649af58f49887965e43" dependencies = [ "gtk", "http", @@ -4982,16 +4918,16 @@ dependencies = [ "serde_json", "tauri-utils", "thiserror", - "uuid 1.0.0", + "uuid 1.1.1", "webview2-com", - "windows 0.30.0", + "windows 0.37.0", ] [[package]] name = "tauri-runtime-wry" -version = "0.5.2" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b78338baa375a2c3f7746e91595ef2b33b09bc4714586cc6b4486fb718d98e33" +checksum = "0cd6fe3f8dc12a9c409ee6da19379636525e0ff8da12897c04dc1e76b8c8ff62" dependencies = [ "cocoa", "gtk", @@ -4999,18 +4935,18 @@ dependencies = [ "rand 0.8.5", "tauri-runtime", "tauri-utils", - "uuid 1.0.0", + "uuid 1.1.1", "webkit2gtk", "webview2-com", - "windows 0.30.0", + "windows 0.37.0", "wry", ] [[package]] name = "tauri-utils" -version = "1.0.0-rc.7" +version = "1.0.0-rc.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c41e14b545d79532743e1d279b9b8488babf35737fcc6cfcd9dbc5fde58919c9" +checksum = "2a636fa13c9210cc19243e3efee408fe0c09a3de820c329c61fecb25dbf1e643" dependencies = [ "brotli", "ctor", @@ -5023,6 +4959,7 @@ dependencies = [ "phf 0.10.1", "proc-macro2", "quote", + "semver 1.0.9", "serde", "serde_json", "serde_with", @@ -5187,7 +5124,7 @@ dependencies = [ "mio", "num_cpus", "once_cell", - "parking_lot 0.12.0", + "parking_lot 0.12.1", "pin-project-lite", "signal-hook-registry", "socket2", @@ -5381,16 +5318,6 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" -[[package]] -name = "twox-hash" -version = "1.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" -dependencies = [ - "cfg-if", - "static_assertions", -] - [[package]] name = "typenum" version = "1.15.0" @@ -5505,9 +5432,9 @@ dependencies = [ [[package]] name = "uuid" -version = "1.0.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cfcd319456c4d6ea10087ed423473267e1a071f3bc0aa89f80d60997843c6f0" +checksum = "c6d5d669b51467dcf7b2f1a796ce0f955f05f01cafda6c19d6e95f730df29238" dependencies = [ "getrandom 0.2.6", "serde", @@ -5761,21 +5688,21 @@ dependencies = [ [[package]] name = "webview2-com" -version = "0.13.0" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb8e90ac2d9ce39cdb70017aaec641be09fbdd702b7b332b9896d053eb469524" +checksum = "a489a9420acabb3c2ed0434b6f71f6b56b9485ec32665a28dec1ee186d716e0f" dependencies = [ "webview2-com-macros", "webview2-com-sys", - "windows 0.30.0", - "windows_macros", + "windows 0.37.0", + "windows-implement", ] [[package]] name = "webview2-com-macros" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1515c6c82fcee93f6edaacc72c8e233dbe4ff3ca569dce1901dfc36c404a3e99" +checksum = "eaebe196c01691db62e9e4ca52c5ef1e4fd837dcae27dae3ada599b5a8fd05ac" dependencies = [ "proc-macro2", "quote", @@ -5784,15 +5711,15 @@ dependencies = [ [[package]] name = "webview2-com-sys" -version = "0.13.0" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92160310b3322397e4ff8a8285a7429d73a07a68fda44ee80879605b93e53f76" +checksum = "0258c53ee9adc0a4f8ba1c8c317588f7a58c7048a55b621d469ba75ab3709ca1" dependencies = [ "regex", "serde", "serde_json", "thiserror", - "windows 0.30.0", + "windows 0.37.0", "windows-bindgen", ] @@ -5854,19 +5781,6 @@ dependencies = [ "windows_x86_64_msvc 0.24.0", ] -[[package]] -name = "windows" -version = "0.30.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b749ebd2304aa012c5992d11a25d07b406bdbe5f79d371cb7a918ce501a19eb0" -dependencies = [ - "windows_aarch64_msvc 0.30.0", - "windows_i686_gnu 0.30.0", - "windows_i686_msvc 0.30.0", - "windows_x86_64_gnu 0.30.0", - "windows_x86_64_msvc 0.30.0", -] - [[package]] name = "windows" version = "0.35.0" @@ -5880,16 +5794,46 @@ dependencies = [ "windows_x86_64_msvc 0.35.0", ] +[[package]] +name = "windows" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57b543186b344cc61c85b5aab0d2e3adf4e0f99bc076eff9aa5927bcc0b8a647" +dependencies = [ + "windows-implement", + "windows_aarch64_msvc 0.37.0", + "windows_i686_gnu 0.37.0", + "windows_i686_msvc 0.37.0", + "windows_x86_64_gnu 0.37.0", + "windows_x86_64_msvc 0.37.0", +] + [[package]] name = "windows-bindgen" -version = "0.30.0" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "944c545fcae9dd66488308f8b69aa3ba34f53714416ecfcdcbbfa4b6821e27c6" +checksum = "0bed7be31ade0af08fec9b5343e9edcc005d22b1f11859b8a59b24797f5858e8" dependencies = [ - "windows_quote", - "windows_reader", + "windows-metadata", + "windows-tokens", ] +[[package]] +name = "windows-implement" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67a1062e555f7d9d66fd1130ed4f7c6ec41a47529ee0850cd0e926d95b26bb14" +dependencies = [ + "syn", + "windows-tokens", +] + +[[package]] +name = "windows-metadata" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f33f2b90a6664e369c41ab5ff262d06f048fc9685d9bf8a0e99a47750bb0463" + [[package]] name = "windows-sys" version = "0.36.1" @@ -5904,10 +5848,10 @@ dependencies = [ ] [[package]] -name = "windows_aarch64_msvc" -version = "0.30.0" +name = "windows-tokens" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29277a4435d642f775f63c7d1faeb927adba532886ce0287bd985bffb16b6bca" +checksum = "3263d25f1170419995b78ff10c06b949e8a986c35c208dc24333c64753a87169" [[package]] name = "windows_aarch64_msvc" @@ -5922,14 +5866,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" [[package]] -name = "windows_gen" -version = "0.30.0" +name = "windows_aarch64_msvc" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30dff4d91d22520628bb94b66f2bb313cb16a09a515a32320a84a1b449bc94c0" -dependencies = [ - "windows_quote", - "windows_reader", -] +checksum = "2623277cb2d1c216ba3b578c0f3cf9cdebeddb6e66b1b218bb33596ea7769c3a" [[package]] name = "windows_i686_gnu" @@ -5937,12 +5877,6 @@ version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0866510a3eca9aed73a077490bbbf03e5eaac4e1fd70849d89539e5830501fd" -[[package]] -name = "windows_i686_gnu" -version = "0.30.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1145e1989da93956c68d1864f32fb97c8f561a8f89a5125f6a2b7ea75524e4b8" - [[package]] name = "windows_i686_gnu" version = "0.35.0" @@ -5956,16 +5890,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" [[package]] -name = "windows_i686_msvc" -version = "0.24.0" +name = "windows_i686_gnu" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf0ffed56b7e9369a29078d2ab3aaeceea48eb58999d2cff3aa2494a275b95c6" +checksum = "d3925fd0b0b804730d44d4b6278c50f9699703ec49bcd628020f46f4ba07d9e1" [[package]] name = "windows_i686_msvc" -version = "0.30.0" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4a09e3a0d4753b73019db171c1339cd4362c8c44baf1bcea336235e955954a6" +checksum = "bf0ffed56b7e9369a29078d2ab3aaeceea48eb58999d2cff3aa2494a275b95c6" [[package]] name = "windows_i686_msvc" @@ -5980,28 +5914,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" [[package]] -name = "windows_macros" -version = "0.30.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62ae44ab917e9005fe710d99d52d227ca0164b10a09be90649142cc3fab825d3" -dependencies = [ - "syn", - "windows_gen", - "windows_quote", - "windows_reader", -] - -[[package]] -name = "windows_quote" -version = "0.30.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71f02c51a77e6248c1206aaa920802c32d50a05205e229b118d7f3afd3036667" - -[[package]] -name = "windows_reader" -version = "0.30.0" +name = "windows_i686_msvc" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e44e6df0da993cda589c5ac852272fbb2a0ead67a031a017dd3eac11528a2d72" +checksum = "ce907ac74fe331b524c1298683efbf598bb031bc84d5e274db2083696d07c57c" [[package]] name = "windows_x86_64_gnu" @@ -6009,12 +5925,6 @@ version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "384a173630588044205a2993b6864a2f56e5a8c1e7668c07b93ec18cf4888dc4" -[[package]] -name = "windows_x86_64_gnu" -version = "0.30.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ca64fcb0220d58db4c119e050e7af03c69e6f4f415ef69ec1773d9aab422d5a" - [[package]] name = "windows_x86_64_gnu" version = "0.35.0" @@ -6028,16 +5938,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" [[package]] -name = "windows_x86_64_msvc" -version = "0.24.0" +name = "windows_x86_64_gnu" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9bd8f062d8ca5446358159d79a90be12c543b3a965c847c8f3eedf14b321d399" +checksum = "2babfba0828f2e6b32457d5341427dcbb577ceef556273229959ac23a10af33d" [[package]] name = "windows_x86_64_msvc" -version = "0.30.0" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08cabc9f0066848fef4bc6a1c1668e6efce38b661d2aeec75d18d8617eebb5f1" +checksum = "9bd8f062d8ca5446358159d79a90be12c543b3a965c847c8f3eedf14b321d399" [[package]] name = "windows_x86_64_msvc" @@ -6051,6 +5961,12 @@ version = "0.36.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" +[[package]] +name = "windows_x86_64_msvc" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4dd6dc7df2d84cf7b33822ed5b86318fb1781948e9663bacd047fc9dd52259d" + [[package]] name = "winreg" version = "0.10.1" @@ -6082,9 +5998,9 @@ dependencies = [ [[package]] name = "wry" -version = "0.16.2" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5676092e1a33448ed0f268717bcbb2e928354b78f4c1f60f3d43641eedea0d9" +checksum = "38425583b1f8c16c074fa4f962f7f0ddd5cb2f6b241a494a26db5eca3ccd4fd7" dependencies = [ "block", "cocoa", @@ -6094,7 +6010,7 @@ dependencies = [ "glib", "gtk", "http", - "jni", + "jni 0.18.0", "libc", "log", "objc", @@ -6108,8 +6024,8 @@ dependencies = [ "webkit2gtk", "webkit2gtk-sys", "webview2-com", - "windows 0.30.0", - "windows_macros", + "windows 0.37.0", + "windows-implement", ] [[package]] diff --git a/README.md b/README.md index f9ebd6c42..fe49a5bfc 100644 --- a/README.md +++ b/README.md @@ -8,9 +8,12 @@ ⚠️ Spyglass is very much in its early stages, but it’s in a place where it's functional and can be used to replace basic searches. ⚠️ Download now: - [Mac](https://github.com/a5huynh/spyglass/releases/download/v2022.5.27/Spyglass_22.5.27_x64.dmg) - | [Windows](https://github.com/a5huynh/spyglass/releases/download/v2022.5.27/Spyglass_22.5.27_x64_en-US.msi) - | [Linux (AppImage)](https://github.com/a5huynh/spyglass/releases/download/v2022.5.27/spyglass_22.5.27_amd64.AppImage) + [Mac](https://github.com/a5huynh/spyglass/releases/download/v2022.5.28/Spyglass_22.5.28_x64.dmg) + | [Windows](https://github.com/a5huynh/spyglass/releases/download/v2022.5.28/Spyglass_22.5.28_x64_en-US.msi) + | [Linux (AppImage)](https://github.com/a5huynh/spyglass/releases/download/v2022.5.28/spyglass_22.5.28_amd64.AppImage) + + +Looking for lenses? Check out our [community contributions](https://github.com/spyglass-search/lens-box)! --- @@ -22,6 +25,7 @@ Download now: * [How does it know what to crawl](#how-does-it-know-what-to-crawl) * [Example: Curated recipe searching](#curated-recipe-searching) * [Example: Narrowing down by a specific topic](#curated-recipe-searching) +* [Lens Directory](#lens-directory) * [Settings](#settings) * [Updating the shorcut](#updating-the-shortcut) @@ -157,6 +161,10 @@ programming language and not the Rust game / The Rust Belt / oxidation / etc. ) ``` +## Lens Directory + +Looking for lenses? Check out our [community contributions](https://github.com/spyglass-search/lens-box)! + ## Settings diff --git a/crates/client/public/glue.js b/crates/client/public/glue.js index 3c3f68bf9..90b4f8a8a 100644 --- a/crates/client/public/glue.js +++ b/crates/client/public/glue.js @@ -21,6 +21,10 @@ export async function onRefreshResults(callback) { await listen('refresh_results', callback); } +export async function on_refresh_lens_manager(callback) { + await listen('refresh_lens_manager', callback); +} + export async function crawlStats() { return await invoke("crawl_stats"); } @@ -29,6 +33,18 @@ export async function deleteDoc(id) { return await invoke("delete_doc", { id }); } +export async function install_lens(downloadUrl) { + return await invoke("install_lens", { downloadUrl }) +} + +export async function listInstalledLenses() { + return await invoke("list_installed_lenses"); +} + +export async function listInstallableLenses() { + return await invoke("list_installable_lenses"); +} + export async function searchDocs(lenses, query) { return await invoke("search_docs", { lenses, query }); } @@ -41,6 +57,10 @@ export async function openResult(url) { return await invoke("open_result", { url }); } +export async function openLensFolder() { + return await invoke("open_lens_folder"); +} + export async function resizeWindow(height) { return await invoke("resize_window", { height }); } \ No newline at end of file diff --git a/crates/client/public/main.css b/crates/client/public/main.css index 51c9d4d05..5ae0652e5 100644 --- a/crates/client/public/main.css +++ b/crates/client/public/main.css @@ -522,6 +522,10 @@ Ensure the default browser behavior of the `hidden` attribute. margin-top: -0.5rem; } +.ml-2 { + margin-left: 0.5rem; +} + .block { display: block; } @@ -534,6 +538,10 @@ Ensure the default browser behavior of the `hidden` attribute. display: flex; } +.contents { + display: contents; +} + .hidden { display: none; } @@ -558,6 +566,14 @@ Ensure the default browser behavior of the `hidden` attribute. height: 7rem; } +.h-5 { + height: 1.25rem; +} + +.h-20 { + height: 5rem; +} + .h-24 { height: 6rem; } @@ -578,6 +594,10 @@ Ensure the default browser behavior of the `hidden` attribute. width: 0.75rem; } +.w-5 { + width: 1.25rem; +} + .w-16 { width: 4rem; } @@ -607,6 +627,10 @@ Ensure the default browser behavior of the `hidden` attribute. animation: spin 1s linear infinite; } +.cursor-pointer { + cursor: pointer; +} + .flex-row { flex-direction: row; } @@ -623,6 +647,14 @@ Ensure the default browser behavior of the `hidden` attribute. justify-content: center; } +.gap-8 { + gap: 2rem; +} + +.gap-4 { + gap: 1rem; +} + .divide-y > :not([hidden]) ~ :not([hidden]) { --tw-divide-y-reverse: 0; border-top-width: calc(1px * calc(1 - var(--tw-divide-y-reverse))); @@ -727,6 +759,11 @@ Ensure the default browser behavior of the `hidden` attribute. background-color: rgb(22 78 99 / var(--tw-bg-opacity)); } +.bg-stone-900 { + --tw-bg-opacity: 1; + background-color: rgb(28 25 23 / var(--tw-bg-opacity)); +} + .bg-sky-600 { --tw-bg-opacity: 1; background-color: rgb(2 132 199 / var(--tw-bg-opacity)); @@ -742,11 +779,6 @@ Ensure the default browser behavior of the `hidden` attribute. background-color: rgb(63 98 18 / var(--tw-bg-opacity)); } -.bg-stone-900 { - --tw-bg-opacity: 1; - background-color: rgb(28 25 23 / var(--tw-bg-opacity)); -} - .p-4 { padding: 1rem; } @@ -759,14 +791,14 @@ Ensure the default browser behavior of the `hidden` attribute. padding: 0.75rem; } -.p-16 { - padding: 4rem; -} - .p-0 { padding: 0px; } +.p-16 { + padding: 4rem; +} + .py-4 { padding-top: 1rem; padding-bottom: 1rem; @@ -812,6 +844,10 @@ Ensure the default browser behavior of the `hidden` attribute. padding-right: 0px; } +.pt-2 { + padding-top: 0.5rem; +} + .text-center { text-align: center; } @@ -850,6 +886,11 @@ Ensure the default browser behavior of the `hidden` attribute. line-height: 1.75rem; } +.text-xl { + font-size: 1.25rem; + line-height: 1.75rem; +} + .leading-relaxed { line-height: 1.625; } @@ -879,6 +920,15 @@ Ensure the default browser behavior of the `hidden` attribute. color: rgb(220 38 38 / var(--tw-text-opacity)); } +.text-green-400 { + --tw-text-opacity: 1; + color: rgb(74 222 128 / var(--tw-text-opacity)); +} + +.filter { + filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); +} + .hover\:bg-neutral-600:hover { --tw-bg-opacity: 1; background-color: rgb(82 82 82 / var(--tw-bg-opacity)); @@ -889,6 +939,11 @@ Ensure the default browser behavior of the `hidden` attribute. color: rgb(220 38 38 / var(--tw-text-opacity)); } +.hover\:text-white:hover { + --tw-text-opacity: 1; + color: rgb(255 255 255 / var(--tw-text-opacity)); +} + .focus\:outline-none:focus { outline: 2px solid transparent; outline-offset: 2px; diff --git a/crates/client/src/components/btn.rs b/crates/client/src/components/btn.rs index 49b90d893..714165845 100644 --- a/crates/client/src/components/btn.rs +++ b/crates/client/src/components/btn.rs @@ -1,6 +1,8 @@ use wasm_bindgen_futures::spawn_local; use yew::prelude::*; +use crate::components::icons; + #[derive(Properties, PartialEq)] pub struct TooltipProps { pub label: String, @@ -56,9 +58,7 @@ pub fn delete_btn(props: &DeleteButtonProps) -> Html { {onclick} class="hover:text-red-600 text-neutral-600 group"> - - - + } } diff --git a/crates/client/src/components/icons.rs b/crates/client/src/components/icons.rs new file mode 100644 index 000000000..b947203bd --- /dev/null +++ b/crates/client/src/components/icons.rs @@ -0,0 +1,89 @@ +use yew::function_component; +use yew::prelude::*; + +#[derive(Properties, PartialEq)] +pub struct IconProps { + #[prop_or_default] + pub animate_spin: bool, + #[prop_or("h-5".into())] + pub height: String, + #[prop_or("w-5".into())] + pub width: String, +} + +impl IconProps { + pub fn class(&self) -> Vec> { + let animated = if self.animate_spin { + Some("animate-spin".to_string()) + } else { + None + }; + + vec![animated, Some(format!("{} {}", self.height, self.width))] + } +} + +#[function_component(BadgeCheckIcon)] +pub fn badge_check_icon(props: &IconProps) -> Html { + html! { + + + + } +} + +#[function_component(DocumentDownloadIcon)] +pub fn document_download_icon(props: &IconProps) -> Html { + html! { + + + + } +} + +#[function_component(EmojiSadIcon)] +pub fn emoji_sad_icon(props: &IconProps) -> Html { + html! { + + + + } +} + +#[function_component(EyeIcon)] +pub fn eye_icon(props: &IconProps) -> Html { + html! { + + + + + } +} + +#[function_component(FolderOpenIcon)] +pub fn folder_open_icon(props: &IconProps) -> Html { + html! { + + + + + } +} + +#[function_component(RefreshIcon)] +pub fn refresh_icon(props: &IconProps) -> Html { + html! { + + + + } +} + +#[function_component(TrashIcon)] +pub fn trash_icon(props: &IconProps) -> Html { + html! { + + + + } +} diff --git a/crates/client/src/components/lens.rs b/crates/client/src/components/lens.rs new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/crates/client/src/components/lens.rs @@ -0,0 +1 @@ + diff --git a/crates/client/src/components/mod.rs b/crates/client/src/components/mod.rs index fb90bf5d2..7fabf0fc3 100644 --- a/crates/client/src/components/mod.rs +++ b/crates/client/src/components/mod.rs @@ -1,8 +1,11 @@ -use shared::response::{LensResult, SearchResult}; +pub mod btn; +pub mod icons; +pub mod lens; + use yew::prelude::*; -pub mod btn; use btn::DeleteButton; +use shared::response::{LensResult, SearchResult}; #[derive(Clone, Debug, PartialEq)] pub enum ResultListType { @@ -62,8 +65,8 @@ pub fn selected_lens_list(props: &SelectLensProps) -> Html { .iter() .map(|lens_name: &String| { html! { -
  • - {lens_name} +
  • + {lens_name}
  • } }) @@ -117,14 +120,14 @@ pub fn search_result_component(props: &SearchResultProps) -> Html { .trim_start_matches(&domain); html! { -
    - + } @@ -138,10 +141,10 @@ pub fn search_result_component(props: &SearchResultProps) -> Html {
    {url_link} -

    +

    {result.title.clone()}

    -
    +
    {result.description.clone()}
    @@ -150,10 +153,10 @@ pub fn search_result_component(props: &SearchResultProps) -> Html { ResultListType::LensSearch => { html! {
    -

    +

    {result.title.clone()}

    -
    +
    {result.description.clone()}
    diff --git a/crates/client/src/icons.rs b/crates/client/src/icons.rs new file mode 100644 index 000000000..e69de29bb diff --git a/crates/client/src/main.rs b/crates/client/src/main.rs index 82af93c2b..2cb2444f5 100644 --- a/crates/client/src/main.rs +++ b/crates/client/src/main.rs @@ -7,13 +7,22 @@ mod constants; mod events; mod pages; -use crate::pages::{SearchPage, StatsPage}; +use crate::pages::{LensManagerPage, SearchPage, StatsPage}; #[wasm_bindgen(module = "/public/glue.js")] extern "C" { #[wasm_bindgen(js_name = "deleteDoc", catch)] pub async fn delete_doc(id: String) -> Result<(), JsValue>; + #[wasm_bindgen(catch)] + pub async fn install_lens(download_url: String) -> Result<(), JsValue>; + + #[wasm_bindgen(js_name = "listInstalledLenses", catch)] + pub async fn list_installed_lenses() -> Result; + + #[wasm_bindgen(js_name = "listInstallableLenses", catch)] + pub async fn list_installable_lenses() -> Result; + #[wasm_bindgen(js_name = "searchDocs", catch)] pub async fn search_docs(lenses: JsValue, query: String) -> Result; @@ -29,9 +38,15 @@ extern "C" { #[wasm_bindgen(js_name = "onRefreshResults")] pub async fn on_refresh_results(callback: &Closure); + #[wasm_bindgen] + pub async fn on_refresh_lens_manager(callback: &Closure); + #[wasm_bindgen(js_name = "openResult", catch)] pub async fn open(url: String) -> Result<(), JsValue>; + #[wasm_bindgen(js_name = "openLensFolder", catch)] + pub async fn open_lens_folder() -> Result<(), JsValue>; + #[wasm_bindgen(js_name = "escape", catch)] pub async fn escape() -> Result<(), JsValue>; @@ -46,6 +61,8 @@ extern "C" { enum Route { #[at("/")] Search, + #[at("/settings/lens")] + LensManager, #[at("/stats")] Status, } @@ -66,6 +83,7 @@ pub fn app() -> Html { fn switch(routes: &Route) -> Html { match routes { + Route::LensManager => html! { }, Route::Search => html! { }, Route::Status => html! { }, } diff --git a/crates/client/src/pages/lens_manager.rs b/crates/client/src/pages/lens_manager.rs new file mode 100644 index 000000000..5d667a072 --- /dev/null +++ b/crates/client/src/pages/lens_manager.rs @@ -0,0 +1,292 @@ +use shared::response::LensResult; +use std::collections::HashSet; +use wasm_bindgen::prelude::*; +use wasm_bindgen_futures::spawn_local; +use yew::function_component; +use yew::prelude::*; + +use crate::components::icons; +use crate::{ + install_lens, list_installable_lenses, list_installed_lenses, on_refresh_lens_manager, +}; +use shared::response::InstallableLens; + +#[derive(Properties, PartialEq)] +pub struct LensProps { + pub result: LensResult, + #[prop_or_default] + pub is_installed: bool, +} + +#[derive(PartialEq)] +enum RequestState { + NotStarted, + InProgress, + Finished, + Error, +} + +impl RequestState { + pub fn is_done(&self) -> bool { + *self == Self::Finished || *self == Self::Error + } +} + +fn fetch_installed_lenses( + lenses_handle: UseStateHandle>, + req_state: UseStateHandle, +) { + spawn_local(async move { + match list_installed_lenses().await { + Ok(results) => { + lenses_handle.set(results.into_serde().unwrap()); + req_state.set(RequestState::Finished); + } + Err(e) => { + log::info!("Error: {:?}", e); + req_state.set(RequestState::Error); + } + } + }); +} + +fn fetch_installable_lenses( + data_handle: UseStateHandle>, + req_state: UseStateHandle, +) { + spawn_local(async move { + match list_installable_lenses().await { + Ok(results) => { + let lenses: Vec = results.into_serde().unwrap(); + let parsed: Vec = lenses + .iter() + .map(|lens| LensResult { + author: lens.author.to_owned(), + title: lens.name.to_owned(), + description: lens.description.to_owned(), + html_url: Some(lens.html_url.to_owned()), + download_url: Some(lens.download_url.to_owned()), + }) + .collect(); + + data_handle.set(parsed); + req_state.set(RequestState::Finished); + } + Err(e) => { + log::info!("Error: {:?}", e); + req_state.set(RequestState::Error); + } + } + }); +} + +fn handle_install_lens(download_url: String) { + spawn_local(async move { + if let Err(e) = install_lens(download_url.clone()).await { + log::error!("error installing lens: {} {:?}", download_url.clone(), e); + } + }); +} + +#[derive(Properties, PartialEq)] +pub struct InstallBtnProps { + pub download_url: String, +} + +#[function_component(InstallButton)] +pub fn install_btn(props: &InstallBtnProps) -> Html { + let is_installing = use_state_eq(|| false); + let download_url = props.download_url.clone(); + + let onclick = { + let is_installing = is_installing.clone(); + move |_| { + is_installing.set(true); + // Download to lens directory + handle_install_lens(download_url.clone()); + } + }; + + if *is_installing { + html! { +
    + +
    {"Installing"}
    +
    + } + } else { + html! { + + } + } +} + +#[function_component(Lens)] +pub fn lens_component(props: &LensProps) -> Html { + let component_styles: Vec = vec![ + "border-t".into(), + "border-neutral-600".into(), + "p-4".into(), + "pr-0".into(), + "text-white".into(), + "bg-netural-800".into(), + ]; + let result = &props.result; + + let installed_el = if props.is_installed { + html! { +
    + +
    {"Installed"}
    +
    + } + } else { + html! { } + }; + + let view_link = if result.html_url.is_some() { + html! { + + +
    {"View Source"}
    +
    + } + } else { + html! {} + }; + + html! { +
    +

    + {result.title.clone()} +

    +

    + {"Crafted By:"} + + {format!("@{}", result.author)} + +

    +
    + {result.description.clone()} +
    +
    + {installed_el} + {view_link} +
    +
    + } +} + +#[function_component(LensManagerPage)] +pub fn lens_manager_page() -> Html { + let user_installed: UseStateHandle> = use_state_eq(Vec::new); + let installable: UseStateHandle> = use_state_eq(Vec::new); + + let ui_req_state = use_state_eq(|| RequestState::NotStarted); + if *ui_req_state == RequestState::NotStarted { + ui_req_state.set(RequestState::InProgress); + fetch_installed_lenses(user_installed.clone(), ui_req_state.clone()); + } + + let i_req_state = use_state_eq(|| RequestState::NotStarted); + if *i_req_state == RequestState::NotStarted { + i_req_state.set(RequestState::InProgress); + fetch_installable_lenses(installable.clone(), i_req_state.clone()); + } + + let on_open_folder = { + move |_| { + spawn_local(async { + let _ = crate::open_lens_folder().await; + }); + } + }; + + let on_refresh = { + let ui_req_state = ui_req_state.clone(); + let i_req_state = i_req_state.clone(); + move |_| { + ui_req_state.set(RequestState::NotStarted); + i_req_state.set(RequestState::NotStarted); + } + }; + + let already_installed: HashSet = + user_installed.iter().map(|x| x.title.clone()).collect(); + installable.set( + installable + .iter() + .filter(|x| !already_installed.contains(&x.title)) + .map(|x| x.to_owned()) + .collect::>(), + ); + + // Handle refreshing the list + { + let ui_req_state = ui_req_state.clone(); + let i_req_state = i_req_state.clone(); + spawn_local(async move { + let cb = Closure::wrap(Box::new(move || { + ui_req_state.set(RequestState::NotStarted); + i_req_state.set(RequestState::NotStarted); + }) as Box); + + on_refresh_lens_manager(&cb).await; + cb.forget(); + }); + } + + let contents = if ui_req_state.is_done() && i_req_state.is_done() { + html! { + <> + { + user_installed.iter().map(|data| { + html! { } + }).collect::() + } + { + installable.iter().map(|data| { + html! { } + }).collect::() + } + + } + } else { + html! { +
    +
    + +
    +
    + } + }; + + html! { +
    +
    +
    +

    {"Lens Manager"}

    + + +
    +
    +
    + {contents} +
    +
    + } +} diff --git a/crates/client/src/pages/mod.rs b/crates/client/src/pages/mod.rs index 44cbc773d..ef47f47b6 100644 --- a/crates/client/src/pages/mod.rs +++ b/crates/client/src/pages/mod.rs @@ -1,3 +1,6 @@ +mod lens_manager; +pub use lens_manager::*; + mod search; pub use search::*; diff --git a/crates/client/src/pages/search.rs b/crates/client/src/pages/search.rs index b9c3bae1c..3b325926a 100644 --- a/crates/client/src/pages/search.rs +++ b/crates/client/src/pages/search.rs @@ -172,18 +172,18 @@ pub fn search_page() -> Html { html! {
    -
    +
    { results }
    diff --git a/crates/client/src/pages/stats.rs b/crates/client/src/pages/stats.rs index c3eb15579..9b2b13583 100644 --- a/crates/client/src/pages/stats.rs +++ b/crates/client/src/pages/stats.rs @@ -2,10 +2,14 @@ use num_format::{Buffer, Locale}; use wasm_bindgen_futures::spawn_local; use yew::prelude::*; +use crate::components::icons; use crate::crawl_stats; use shared::response::{CrawlStats, QueueStatus}; -fn fetch_crawl_stats(stats_handle: UseStateHandle>) { +fn fetch_crawl_stats( + stats_handle: UseStateHandle>, + request_finished: UseStateHandle, +) { spawn_local(async move { match crawl_stats().await { Ok(results) => { @@ -13,8 +17,12 @@ fn fetch_crawl_stats(stats_handle: UseStateHandle>) { let mut sorted = results.by_domain; sorted.sort_by(|(_, a), (_, b)| b.num_completed.cmp(&a.num_completed)); stats_handle.set(sorted); + request_finished.set(true); + } + Err(e) => { + log::info!("Error: {:?}", e); + request_finished.set(true); } - Err(e) => log::info!("Error: {:?}", e), } }); } @@ -39,7 +47,7 @@ pub fn legend_icon(props: &LegendIconProps) -> Html { ]; html! { -
    +
    {props.label.clone()}
    @@ -82,7 +90,7 @@ fn stats_bar(props: &StatsBarProps) -> Html { html! {
    - {buf.as_str()} + {buf.as_str()}
    } } @@ -90,15 +98,19 @@ fn stats_bar(props: &StatsBarProps) -> Html { #[function_component(StatsPage)] pub fn stats_page() -> Html { let stats: UseStateHandle> = use_state_eq(Vec::new); - if stats.is_empty() { - fetch_crawl_stats(stats.clone()); + let request_finished = use_state(|| false); + + if stats.is_empty() && !(*request_finished) { + fetch_crawl_stats(stats.clone(), request_finished.clone()); } let onclick = { + let request_finished = request_finished.clone(); let stats = stats.clone(); move |_| { + request_finished.set(false); stats.set(Vec::new()); - fetch_crawl_stats(stats.clone()); + fetch_crawl_stats(stats.clone(), request_finished.clone()); } }; @@ -107,11 +119,11 @@ pub fn stats_page() -> Html { .map(|(domain, stats)| { let total = stats.total() as f64; html! { -
    -
    +
    +
    {domain}
    -
    +
    @@ -122,31 +134,35 @@ pub fn stats_page() -> Html { }) .collect::(); - if stats.is_empty() { + if stats.is_empty() && !(*request_finished) { rendered = html! {
    - - - + +
    +
    + } + } else if stats.is_empty() && *request_finished { + rendered = html! { +
    +
    +
    } } html! { -
    +
    -

    +

    {"Crawl Status"}

    @@ -158,7 +174,7 @@ pub fn stats_page() -> Html {
    -
    +
    {rendered}
    diff --git a/crates/entities/src/models/crawl_queue.rs b/crates/entities/src/models/crawl_queue.rs index 3fc69c639..9ace3ffd7 100644 --- a/crates/entities/src/models/crawl_queue.rs +++ b/crates/entities/src/models/crawl_queue.rs @@ -152,7 +152,7 @@ struct CrawlQueueCount { count: i64, } -#[derive(FromQueryResult)] +#[derive(Debug, FromQueryResult)] pub struct QueueCountByStatus { pub count: i64, pub domain: String, diff --git a/crates/entities/src/models/indexed_document.rs b/crates/entities/src/models/indexed_document.rs index e7500f7f3..3bd10626a 100644 --- a/crates/entities/src/models/indexed_document.rs +++ b/crates/entities/src/models/indexed_document.rs @@ -46,7 +46,7 @@ impl ActiveModelBehavior for ActiveModel { } } -#[derive(FromQueryResult)] +#[derive(Debug, FromQueryResult)] pub struct CountByDomain { pub count: i64, pub domain: String, diff --git a/crates/shared/src/response.rs b/crates/shared/src/response.rs index 5ab26460d..e54be89a4 100644 --- a/crates/shared/src/response.rs +++ b/crates/shared/src/response.rs @@ -25,6 +25,26 @@ pub struct CrawlStats { pub by_domain: Vec<(String, QueueStatus)>, } +#[derive(Clone, Deserialize, Serialize)] +pub struct InstallableLens { + pub author: String, + pub description: String, + pub name: String, + pub sha: String, + pub download_url: String, + pub html_url: String, +} + +#[derive(Clone, Debug, Default, Deserialize, Serialize, PartialEq)] +pub struct LensResult { + pub author: String, + pub title: String, + pub description: String, + // Only relevant for installable lenses + pub html_url: Option, + pub download_url: Option, +} + #[derive(Debug, Deserialize, Serialize)] pub struct SearchMeta { pub query: String, @@ -48,13 +68,7 @@ pub struct SearchResults { pub meta: SearchMeta, } -#[derive(Clone, Debug, Deserialize, Serialize)] -pub struct LensResult { - pub title: String, - pub description: String, -} - -#[derive(Debug, Deserialize, Serialize)] +#[derive(Debug, Default, Deserialize, Serialize)] pub struct SearchLensesResp { pub results: Vec, } diff --git a/crates/shared/src/rpc.rs b/crates/shared/src/rpc.rs index 098f20a4e..e4d142e39 100644 --- a/crates/shared/src/rpc.rs +++ b/crates/shared/src/rpc.rs @@ -2,7 +2,7 @@ use jsonrpc_core::{BoxFuture, Result}; use jsonrpc_derive::rpc; use crate::request::{SearchLensesParam, SearchParam}; -use crate::response::{AppStatus, CrawlStats, SearchLensesResp, SearchResults}; +use crate::response::{AppStatus, CrawlStats, LensResult, SearchLensesResp, SearchResults}; pub fn gen_ipc_path() -> String { if cfg!(windows) { @@ -28,12 +28,15 @@ pub trait Rpc { #[rpc(name = "delete_doc")] fn delete_doc(&self, id: String) -> BoxFuture>; - #[rpc(name = "toggle_pause")] - fn toggle_pause(&self) -> BoxFuture>; + #[rpc(name = "list_installed_lenses")] + fn list_installed_lenses(&self) -> BoxFuture>>; #[rpc(name = "search_docs")] fn search_docs(&self, query: SearchParam) -> BoxFuture>; #[rpc(name = "search_lenses")] fn search_lenses(&self, query: SearchLensesParam) -> BoxFuture>; + + #[rpc(name = "toggle_pause")] + fn toggle_pause(&self) -> BoxFuture>; } diff --git a/crates/spyglass/src/api/mod.rs b/crates/spyglass/src/api/mod.rs index 953d154c0..cac18a252 100644 --- a/crates/spyglass/src/api/mod.rs +++ b/crates/spyglass/src/api/mod.rs @@ -6,7 +6,7 @@ use jsonrpc_ipc_server::{Server, ServerBuilder}; use libspyglass::state::AppState; use shared::request::{SearchLensesParam, SearchParam}; -use shared::response::{AppStatus, CrawlStats, SearchLensesResp, SearchResults}; +use shared::response::{AppStatus, CrawlStats, LensResult, SearchLensesResp, SearchResults}; use shared::rpc::{gen_ipc_path, Rpc}; mod response; @@ -33,8 +33,8 @@ impl Rpc for SpyglassRPC { Box::pin(route::delete_doc(self.state.clone(), id)) } - fn toggle_pause(&self) -> BoxFuture> { - Box::pin(route::toggle_pause(self.state.clone())) + fn list_installed_lenses(&self) -> BoxFuture>> { + Box::pin(route::list_installed_lenses(self.state.clone())) } fn search_docs(&self, query: SearchParam) -> BoxFuture> { @@ -44,6 +44,10 @@ impl Rpc for SpyglassRPC { fn search_lenses(&self, query: SearchLensesParam) -> BoxFuture> { Box::pin(route::search_lenses(self.state.clone(), query)) } + + fn toggle_pause(&self) -> BoxFuture> { + Box::pin(route::toggle_pause(self.state.clone())) + } } pub fn start_api_ipc(state: &AppState) -> anyhow::Result { diff --git a/crates/spyglass/src/api/route.rs b/crates/spyglass/src/api/route.rs index e4e27692d..06385d5ff 100644 --- a/crates/spyglass/src/api/route.rs +++ b/crates/spyglass/src/api/route.rs @@ -19,74 +19,6 @@ use libspyglass::state::AppState; use super::response; -#[instrument(skip(state))] -pub async fn search(state: AppState, search_req: request::SearchParam) -> Result { - let fields = Searcher::doc_fields(); - - let index = state.index; - let searcher = index.reader.searcher(); - - // Create a copy of the lenses for this search - let mut lenses = HashMap::new(); - for entry in state.lenses.iter() { - lenses.insert(entry.key().clone(), entry.value().clone()); - } - - let docs = Searcher::search_with_lens( - &lenses, - &index.index, - &index.reader, - &search_req.lenses, - &search_req.query, - ); - - let mut results: Vec = Vec::new(); - for (score, doc_addr) in docs { - let retrieved = searcher.doc(doc_addr).unwrap(); - - let doc_id = retrieved.get_first(fields.id).unwrap(); - let domain = retrieved.get_first(fields.domain).unwrap(); - let title = retrieved.get_first(fields.title).unwrap(); - let description = retrieved.get_first(fields.description).unwrap(); - let url = retrieved.get_first(fields.url).unwrap(); - - let result = SearchResult { - doc_id: doc_id.as_text().unwrap().to_string(), - domain: domain.as_text().unwrap().to_string(), - title: title.as_text().unwrap().to_string(), - description: description.as_text().unwrap().to_string(), - url: url.as_text().unwrap().to_string(), - score, - }; - - results.push(result); - } - - let meta = SearchMeta { - query: search_req.query, - num_docs: searcher.num_docs(), - wall_time_ms: 1000, - }; - - Ok(SearchResults { results, meta }) -} - -/// Show the list of URLs in the queue and their status -#[instrument(skip(state))] -pub async fn list_queue(state: AppState) -> Result { - let db = &state.db; - let queue = crawl_queue::Entity::find().all(db).await; - - match queue { - Ok(queue) => Ok(response::ListQueue { queue }), - Err(err) => Err(Error { - code: ErrorCode::InternalError, - message: err.to_string(), - data: None, - }), - } -} - /// Add url to queue #[instrument(skip(state))] pub async fn add_queue(state: AppState, queue_item: request::QueueItemParam) -> Result { @@ -170,12 +102,61 @@ pub async fn crawl_stats(state: AppState) -> jsonrpc_core::Result { let by_domain = by_domain .into_iter() - .filter(|(_, stats)| stats.total() >= 100) + .filter(|(_, stats)| stats.total() >= 10) .collect(); Ok(CrawlStats { by_domain }) } +/// Remove a doc from the index +#[instrument(skip(state))] +pub async fn delete_doc(state: AppState, id: String) -> Result<()> { + if let Ok(mut writer) = state.index.writer.lock() { + if let Err(e) = Searcher::delete(&mut writer, &id) { + log::error!("Unable to delete doc {} due to {}", id, e); + } else { + let _ = writer.commit(); + } + } + + Ok(()) +} + +/// List of installed lenses +#[instrument(skip(state))] +pub async fn list_installed_lenses(state: AppState) -> Result> { + let mut lenses: Vec = state + .lenses + .iter() + .map(|lens| LensResult { + author: lens.author.clone(), + title: lens.name.clone(), + description: lens.description.clone().unwrap_or_else(|| "".into()), + ..Default::default() + }) + .collect(); + + lenses.sort_by(|x, y| x.title.cmp(&y.title)); + + Ok(lenses) +} + +/// Show the list of URLs in the queue and their status +#[instrument(skip(state))] +pub async fn list_queue(state: AppState) -> Result { + let db = &state.db; + let queue = crawl_queue::Entity::find().all(db).await; + + match queue { + Ok(queue) => Ok(response::ListQueue { queue }), + Err(err) => Err(Error { + code: ErrorCode::InternalError, + message: err.to_string(), + data: None, + }), + } +} + #[instrument(skip(state))] pub async fn toggle_pause(state: AppState) -> jsonrpc_core::Result { // Scope so that the app_state mutex is correctly released. @@ -191,6 +172,60 @@ pub async fn toggle_pause(state: AppState) -> jsonrpc_core::Result { _get_current_status(state.clone()).await } +/// Search the user's indexed documents +#[instrument(skip(state))] +pub async fn search(state: AppState, search_req: request::SearchParam) -> Result { + let fields = Searcher::doc_fields(); + + let index = state.index; + let searcher = index.reader.searcher(); + + // Create a copy of the lenses for this search + let mut lenses = HashMap::new(); + for entry in state.lenses.iter() { + lenses.insert(entry.key().clone(), entry.value().clone()); + } + + let docs = Searcher::search_with_lens( + &lenses, + &index.index, + &index.reader, + &search_req.lenses, + &search_req.query, + ); + + let mut results: Vec = Vec::new(); + for (score, doc_addr) in docs { + let retrieved = searcher.doc(doc_addr).unwrap(); + + let doc_id = retrieved.get_first(fields.id).unwrap(); + let domain = retrieved.get_first(fields.domain).unwrap(); + let title = retrieved.get_first(fields.title).unwrap(); + let description = retrieved.get_first(fields.description).unwrap(); + let url = retrieved.get_first(fields.url).unwrap(); + + let result = SearchResult { + doc_id: doc_id.as_text().unwrap().to_string(), + domain: domain.as_text().unwrap().to_string(), + title: title.as_text().unwrap().to_string(), + description: description.as_text().unwrap().to_string(), + url: url.as_text().unwrap().to_string(), + score, + }; + + results.push(result); + } + + let meta = SearchMeta { + query: search_req.query, + num_docs: searcher.num_docs(), + wall_time_ms: 1000, + }; + + Ok(SearchResults { results, meta }) +} + +/// Search the user's installed lenses #[instrument(skip(state))] pub async fn search_lenses( state: AppState, @@ -212,23 +247,12 @@ pub async fn search_lenses( let query_results = query_results.unwrap(); for lens in query_results { results.push(LensResult { + author: lens.author, title: lens.name, description: lens.description.unwrap_or_else(|| "".to_string()), + ..Default::default() }); } Ok(SearchLensesResp { results }) } - -#[instrument(skip(state))] -pub async fn delete_doc(state: AppState, id: String) -> Result<()> { - if let Ok(mut writer) = state.index.writer.lock() { - if let Err(e) = Searcher::delete(&mut writer, &id) { - log::error!("Unable to delete doc {} due to {}", id, e); - } else { - let _ = writer.commit(); - } - } - - Ok(()) -} diff --git a/crates/spyglass/src/search/lens.rs b/crates/spyglass/src/search/lens.rs index cd2427595..17f3178bb 100644 --- a/crates/spyglass/src/search/lens.rs +++ b/crates/spyglass/src/search/lens.rs @@ -9,30 +9,6 @@ use crate::crawler::bootstrap; use crate::search::Searcher; use crate::state::AppState; -async fn create_default_lens(config: &Config) { - // Create a default lens as an example. - let lens = Lens { - author: "Spyglass".to_string(), - version: "1".to_string(), - name: "rust".to_string(), - description: Some( - "All things Rustlang. Search through Rust blogs, the rust book, and - more." - .to_string(), - ), - domains: vec!["blog.rust-lang.org".into()], - urls: vec!["https://doc.rust-lang.org/book/".into()], - is_enabled: true, - rules: Vec::new(), - }; - - fs::write( - config.lenses_dir().join("rust.ron"), - ron::ser::to_string_pretty(&lens, Default::default()).unwrap(), - ) - .expect("Unable to save default lens file."); -} - /// Check if we've already bootstrapped a prefix / otherwise add it to the queue. async fn check_and_bootstrap( db: &DatabaseConnection, @@ -63,7 +39,6 @@ pub async fn read_lenses(state: &AppState, config: &Config) -> anyhow::Result<() state.lenses.clear(); let lense_dir = config.lenses_dir(); - let mut num_lenses = 0; for entry in (fs::read_dir(lense_dir)?).flatten() { let path = entry.path(); @@ -72,7 +47,6 @@ pub async fn read_lenses(state: &AppState, config: &Config) -> anyhow::Result<() match ron::from_str::(&file_contents) { Err(err) => log::error!("Unable to load lens {:?}: {}", entry.path(), err), Ok(lens) => { - num_lenses += 1; if lens.is_enabled { state.lenses.insert(lens.name.clone(), lens); } @@ -82,10 +56,6 @@ pub async fn read_lenses(state: &AppState, config: &Config) -> anyhow::Result<() } } - if num_lenses == 0 { - create_default_lens(config).await; - } - Ok(()) } diff --git a/crates/tauri/Cargo.toml b/crates/tauri/Cargo.toml index f649e8614..598baeb26 100644 --- a/crates/tauri/Cargo.toml +++ b/crates/tauri/Cargo.toml @@ -22,6 +22,7 @@ log = "0.4" num-format = "0.4" open = "2" reqwest = { version = "0.11", features = ["json"] } +ron = "0.7" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" shared = { path = "../shared" } @@ -32,6 +33,7 @@ tracing = "0.1" tracing-appender = "0.2" tracing-log = "0.1.3" tracing-subscriber = { version = "0.3", features = ["env-filter", "std"] } +url = "2.2" [features] default = [ "custom-protocol" ] diff --git a/crates/tauri/src/cmd.rs b/crates/tauri/src/cmd.rs index a286aa20a..ae231c8a2 100644 --- a/crates/tauri/src/cmd.rs +++ b/crates/tauri/src/cmd.rs @@ -1,8 +1,15 @@ +use std::fs; + use jsonrpc_core::Value; use tauri::State; +use url::Url; -use crate::{rpc, window}; -use shared::{request, response}; +use crate::{constants, open_folder, rpc, window}; +use shared::{ + config::Config, + request, + response::{self, InstallableLens}, +}; #[tauri::command] pub async fn escape(window: tauri::Window) -> Result<(), String> { @@ -10,6 +17,12 @@ pub async fn escape(window: tauri::Window) -> Result<(), String> { Ok(()) } +#[tauri::command] +pub async fn open_lens_folder(_: tauri::Window, config: State<'_, Config>) -> Result<(), String> { + open_folder(config.lenses_dir()); + Ok(()) +} + #[tauri::command] pub async fn open_result(_: tauri::Window, url: &str) -> Result<(), String> { open::that(url).unwrap(); @@ -21,6 +34,60 @@ pub async fn resize_window(window: tauri::Window, height: f64) { window::resize_window(&window, height).await; } +#[tauri::command] +pub async fn crawl_stats<'r>( + _: tauri::Window, + rpc: State<'_, rpc::RpcMutex>, +) -> Result { + let mut rpc = rpc.lock().await; + match rpc + .client + .call_method::("crawl_stats", "", Value::Null) + .await + { + Ok(resp) => Ok(resp), + Err(err) => { + log::error!("Error sending RPC: {}", err); + rpc.reconnect().await; + Ok(response::CrawlStats { + by_domain: Vec::new(), + }) + } + } +} + +#[tauri::command] +pub async fn list_installed_lenses( + _: tauri::Window, + rpc: State<'_, rpc::RpcMutex>, +) -> Result, String> { + let mut rpc = rpc.lock().await; + Ok(rpc + .call::>("list_installed_lenses", Value::Null) + .await) +} + +#[tauri::command] +pub async fn list_installable_lenses( + _: tauri::Window, +) -> Result, String> { + let client = reqwest::Client::builder() + .user_agent(constants::APP_USER_AGENT) + .build() + .expect("Unable to create reqwest client"); + + if let Ok(res) = client.get(constants::LENS_DIRECTORY_INDEX_URL).send().await { + if let Ok(file_contents) = res.text().await { + return match ron::from_str::>(&file_contents) { + Ok(json) => Ok(json), + Err(e) => Err(format!("Unable to parse index: {}", e)), + }; + } + } + + Ok(Vec::new()) +} + #[tauri::command] pub async fn search_docs<'r>( _: tauri::Window, @@ -57,44 +124,11 @@ pub async fn search_lenses<'r>( query: query.to_string(), }; - let rpc = rpc.lock().await; - match rpc - .client - .call_method::<(request::SearchLensesParam,), response::SearchLensesResp>( - "search_lenses", - "", - (data,), - ) - .await - { - Ok(resp) => Ok(resp.results.to_vec()), - Err(err) => { - log::error!("{}", err); - Ok(Vec::new()) - } - } -} - -#[tauri::command] -pub async fn crawl_stats<'r>( - _: tauri::Window, - rpc: State<'_, rpc::RpcMutex>, -) -> Result { let mut rpc = rpc.lock().await; - match rpc - .client - .call_method::("crawl_stats", "", Value::Null) - .await - { - Ok(resp) => Ok(resp), - Err(err) => { - log::error!("Error sending RPC: {}", err); - rpc.reconnect().await; - Ok(response::CrawlStats { - by_domain: Vec::new(), - }) - } - } + let resp = rpc + .call::<(request::SearchLensesParam,), response::SearchLensesResp>("search_lenses", (data,)) + .await; + Ok(resp.results) } #[tauri::command] @@ -120,3 +154,45 @@ pub async fn delete_doc<'r>( } } } + +/// Install a lens (assumes correct format) from a URL +#[tauri::command] +pub async fn install_lens<'r>( + window: tauri::Window, + config: State<'_, Config>, + download_url: &str, +) -> Result<(), String> { + log::trace!("installing lens from <{}>", download_url); + + let client = reqwest::Client::builder() + .user_agent(constants::APP_USER_AGENT) + .build() + .expect("Unable to create reqwest client"); + + if let Ok(resp) = client.get(download_url).send().await { + if let Ok(file_contents) = resp.text().await { + // Grab the file name from the end of the URL + let url = Url::parse(download_url).unwrap(); + let mut segments = url.path_segments().map(|c| c.collect::>()).unwrap(); + let file_name = segments.pop().unwrap(); + // Create path from file name + lens directory + let lens_path = config.lenses_dir().join(file_name); + log::info!("installing lens to {:?}", lens_path); + + if let Err(e) = fs::write(lens_path.clone(), file_contents) { + log::error!( + "Unable to install lens {} to {:?} due to error: {}", + download_url, + lens_path, + e + ); + } else { + // Sleep for a second to let the app reload the lenses and then let the client know we're done. + tokio::time::sleep(tokio::time::Duration::from_secs(2)).await; + let _ = window.emit("refresh_lens_manager", true); + } + } + } + + Ok(()) +} diff --git a/crates/tauri/src/constants.rs b/crates/tauri/src/constants.rs index 8c38e77c7..d132111bc 100644 --- a/crates/tauri/src/constants.rs +++ b/crates/tauri/src/constants.rs @@ -3,4 +3,9 @@ pub const INPUT_Y: f64 = 128.0; pub const APP_USER_AGENT: &str = "spyglass (github.com/a5huynh/spyglass)"; pub const DISCORD_JOIN_URL: &str = "https://discord.gg/663wPVBSTB"; +pub const LENS_DIRECTORY_INDEX_URL: &str = + "https://raw.githubusercontent.com/spyglass-search/lens-box/main/index.ron"; pub const VERSION_CHECK_URL: &str = "https://api.github.com/repos/a5huynh/spyglass/releases"; + +pub const STATS_WIN_NAME: &str = "crawl_stats"; +pub const LENS_MANAGER_WIN_NAME: &str = "lens_manager"; diff --git a/crates/tauri/src/main.rs b/crates/tauri/src/main.rs index 654be022b..f86189b20 100644 --- a/crates/tauri/src/main.rs +++ b/crates/tauri/src/main.rs @@ -27,7 +27,7 @@ mod constants; mod menu; mod rpc; mod window; -use window::show_crawl_stats_window; +use window::{show_crawl_stats_window, show_lens_manager_window}; fn main() -> Result<(), Box> { let config = Config::new(); @@ -52,13 +52,17 @@ fn main() -> Result<(), Box> { tauri::Builder::default() .invoke_handler(tauri::generate_handler![ + cmd::crawl_stats, + cmd::delete_doc, cmd::escape, + cmd::install_lens, + cmd::list_installable_lenses, + cmd::list_installed_lenses, + cmd::open_lens_folder, cmd::open_result, + cmd::resize_window, cmd::search_docs, cmd::search_lenses, - cmd::resize_window, - cmd::crawl_stats, - cmd::delete_doc, ]) .menu(menu::get_app_menu()) .system_tray(SystemTray::new().with_menu(menu::get_tray_menu(&config))) @@ -165,7 +169,9 @@ fn main() -> Result<(), Box> { let _ = open::that(&version.html_url); } } - menu::OPEN_LENSES_FOLDER => open_folder(config.lenses_dir()), + menu::OPEN_LENS_MANAGER => { + show_lens_manager_window(app); + } menu::OPEN_LOGS_FOLDER => open_folder(config.logs_dir()), menu::OPEN_SETTINGS_FOLDER => open_folder(Config::prefs_dir()), menu::SHOW_CRAWL_STATUS => { diff --git a/crates/tauri/src/menu.rs b/crates/tauri/src/menu.rs index 74223e571..5d682386a 100644 --- a/crates/tauri/src/menu.rs +++ b/crates/tauri/src/menu.rs @@ -7,7 +7,7 @@ pub const QUIT_MENU_ITEM: &str = "quit"; pub const NUM_DOCS_MENU_ITEM: &str = "num_docs"; pub const CRAWL_STATUS_MENU_ITEM: &str = "crawl_status"; -pub const OPEN_LENSES_FOLDER: &str = "open_lenses_folder"; +pub const OPEN_LENS_MANAGER: &str = "open_lens_manager"; pub const OPEN_SETTINGS_FOLDER: &str = "open_settings_folder"; pub const OPEN_LOGS_FOLDER: &str = "open_logs_folder"; pub const SHOW_SEARCHBAR: &str = "show_searchbar"; @@ -25,12 +25,10 @@ pub fn get_tray_menu(config: &Config) -> SystemTrayMenu { let pause = CustomMenuItem::new(CRAWL_STATUS_MENU_ITEM.to_string(), ""); let quit = CustomMenuItem::new(QUIT_MENU_ITEM.to_string(), "Quit"); - let open_lenses_folder = - CustomMenuItem::new(OPEN_LENSES_FOLDER.to_string(), "Show lenses folder"); let open_settings_folder = - CustomMenuItem::new(OPEN_SETTINGS_FOLDER.to_string(), "Show settings folder"); + CustomMenuItem::new(OPEN_SETTINGS_FOLDER.to_string(), "Open settings folder"); - let open_logs_folder = CustomMenuItem::new(OPEN_LOGS_FOLDER.to_string(), "Show logs folder"); + let open_logs_folder = CustomMenuItem::new(OPEN_LOGS_FOLDER.to_string(), "Open logs folder"); let app_version = format!("v20{}", ctx.package_info().version); let mut tray = SystemTrayMenu::new(); @@ -47,8 +45,11 @@ pub fn get_tray_menu(config: &Config) -> SystemTrayMenu { SHOW_CRAWL_STATUS.to_string(), "Show crawl status", )) + .add_item(CustomMenuItem::new( + OPEN_LENS_MANAGER.to_string(), + "Manage/install lenses", + )) .add_native_item(SystemTrayMenuItem::Separator) - .add_item(open_lenses_folder) .add_item(open_settings_folder) .add_item(open_logs_folder); @@ -56,7 +57,7 @@ pub fn get_tray_menu(config: &Config) -> SystemTrayMenu { if cfg!(debug_assertions) { tray = tray .add_native_item(SystemTrayMenuItem::Separator) - .add_item(CustomMenuItem::new(DEV_SHOW_CONSOLE, "Show console")); + .add_item(CustomMenuItem::new(DEV_SHOW_CONSOLE, "Open dev console")); } tray.add_native_item(SystemTrayMenuItem::Separator) diff --git a/crates/tauri/src/rpc.rs b/crates/tauri/src/rpc.rs index ee09c19b4..7b7dfc8dd 100644 --- a/crates/tauri/src/rpc.rs +++ b/crates/tauri/src/rpc.rs @@ -1,6 +1,8 @@ use std::sync::Arc; use jsonrpc_core_client::{transports::ipc, TypedClient}; +use serde::de::DeserializeOwned; +use serde::Serialize; use shared::rpc::gen_ipc_path; use tauri::api::process::{Command, CommandEvent}; use tokio::sync::Mutex; @@ -63,6 +65,21 @@ impl RpcClient { } } + pub async fn call( + &mut self, + method: &str, + args: T, + ) -> R { + match self.client.call_method::(method, "", args).await { + Ok(resp) => resp, + Err(err) => { + log::error!("Error sending RPC: {}", err); + self.reconnect().await; + R::default() + } + } + } + pub async fn reconnect(&mut self) { log::info!("Attempting to restart backend"); // Attempt to reconnect diff --git a/crates/tauri/src/window.rs b/crates/tauri/src/window.rs index b59dc4d30..ea110e2b4 100644 --- a/crates/tauri/src/window.rs +++ b/crates/tauri/src/window.rs @@ -40,14 +40,35 @@ pub fn show_window(window: &Window) { } pub fn show_crawl_stats_window(app: &AppHandle) -> Window { - if let Some(window) = app.get_window("stats") { + if let Some(window) = app.get_window(constants::STATS_WIN_NAME) { let _ = window.show(); let _ = window.set_focus(); return window; } - WindowBuilder::new(app, "stats", WindowUrl::App("/stats".into())) - .title("Status") - .build() - .unwrap() + WindowBuilder::new( + app, + constants::STATS_WIN_NAME, + WindowUrl::App("/stats".into()), + ) + .title("Status") + .build() + .unwrap() +} + +pub fn show_lens_manager_window(app: &AppHandle) -> Window { + if let Some(window) = app.get_window(constants::LENS_MANAGER_WIN_NAME) { + let _ = window.show(); + let _ = window.set_focus(); + return window; + } + + WindowBuilder::new( + app, + constants::LENS_MANAGER_WIN_NAME, + WindowUrl::App("/settings/lens".into()), + ) + .title("Lens Manager") + .build() + .unwrap() } diff --git a/crates/tauri/tauri.conf.json b/crates/tauri/tauri.conf.json index b9cc8aad5..fd52bfb26 100644 --- a/crates/tauri/tauri.conf.json +++ b/crates/tauri/tauri.conf.json @@ -1,7 +1,7 @@ { "package": { "productName": "Spyglass", - "version": "22.5.28" + "version": "22.6.1" }, "build": { "distDir": "../client/dist",