You've already forked AstralRinth
forked from didirus/AstralRinth
Analytics + more bug fixes (#144)
* Analytics + more bug fixes * debug deadlock * Fix mostly everything * merge fixes * fix rest * final fixeS
This commit is contained in:
417
Cargo.lock
generated
417
Cargo.lock
generated
@@ -616,7 +616,7 @@ dependencies = [
|
|||||||
"android-tzdata",
|
"android-tzdata",
|
||||||
"iana-time-zone",
|
"iana-time-zone",
|
||||||
"js-sys",
|
"js-sys",
|
||||||
"num-traits",
|
"num-traits 0.2.15",
|
||||||
"serde",
|
"serde",
|
||||||
"time 0.1.45",
|
"time 0.1.45",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
@@ -800,6 +800,31 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crash-context"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cf7e754a5156db1e23c2126b45082d23b197f08ed047b656e6103da67459e2e6"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"libc",
|
||||||
|
"mach2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crash-handler"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "37571ca6b1166c54bdde2b482eea4c935207d5d82889382b327ad6fcf88ce656"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"crash-context",
|
||||||
|
"libc",
|
||||||
|
"mach2",
|
||||||
|
"parking_lot",
|
||||||
|
"windows-sys 0.42.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crc32fast"
|
name = "crc32fast"
|
||||||
version = "1.3.2"
|
version = "1.3.2"
|
||||||
@@ -927,9 +952,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "daedalus"
|
name = "daedalus"
|
||||||
version = "0.1.21"
|
version = "0.1.23"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2a66b666b316919af243d8684f225b56aed72a83db52a93d61da89e2f588a7c7"
|
checksum = "d14d655650f5f0fd5b88946d4add0f1b02d866e40632304cfe1427240bfd2430"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bincode 2.0.0-rc.2",
|
"bincode 2.0.0-rc.2",
|
||||||
"bytes",
|
"bytes",
|
||||||
@@ -1018,6 +1043,16 @@ version = "2.3.3"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "23d8666cb01533c39dde32bcbab8e227b4ed6679b2c925eba05feabea39508fb"
|
checksum = "23d8666cb01533c39dde32bcbab8e227b4ed6679b2c925eba05feabea39508fb"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "debugid"
|
||||||
|
version = "0.8.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bef552e6f588e446098f6ba40d89ac146c8c7b64aade83c051ee00bb5d2bc18d"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
"uuid",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "derivative"
|
name = "derivative"
|
||||||
version = "2.2.0"
|
version = "2.2.0"
|
||||||
@@ -1197,6 +1232,17 @@ dependencies = [
|
|||||||
"cfg-if",
|
"cfg-if",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "enum-primitive-derive"
|
||||||
|
version = "0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c375b9c5eadb68d0a6efee2999fef292f45854c3444c86f09d8ab086ba942b0e"
|
||||||
|
dependencies = [
|
||||||
|
"num-traits 0.2.15",
|
||||||
|
"quote",
|
||||||
|
"syn 1.0.109",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "enumflags2"
|
name = "enumflags2"
|
||||||
version = "0.7.7"
|
version = "0.7.7"
|
||||||
@@ -1286,6 +1332,18 @@ dependencies = [
|
|||||||
"windows-sys 0.45.0",
|
"windows-sys 0.45.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "findshlibs"
|
||||||
|
version = "0.10.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "40b9e59cd0f7e0806cca4be089683ecb6434e602038df21fe6bf6711b2f07f64"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"lazy_static",
|
||||||
|
"libc",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "flate2"
|
name = "flate2"
|
||||||
version = "1.0.25"
|
version = "1.0.25"
|
||||||
@@ -1700,6 +1758,17 @@ dependencies = [
|
|||||||
"system-deps 6.0.4",
|
"system-deps 6.0.4",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "goblin"
|
||||||
|
version = "0.5.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a7666983ed0dd8d21a6f6576ee00053ca0926fb281a5522577a4dbd0f1b54143"
|
||||||
|
dependencies = [
|
||||||
|
"log",
|
||||||
|
"plain",
|
||||||
|
"scroll",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gtk"
|
name = "gtk"
|
||||||
version = "0.15.5"
|
version = "0.15.5"
|
||||||
@@ -1825,6 +1894,17 @@ dependencies = [
|
|||||||
"digest 0.10.6",
|
"digest 0.10.6",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hostname"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"match_cfg",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "html5ever"
|
name = "html5ever"
|
||||||
version = "0.25.2"
|
version = "0.25.2"
|
||||||
@@ -1994,7 +2074,7 @@ dependencies = [
|
|||||||
"byteorder",
|
"byteorder",
|
||||||
"color_quant",
|
"color_quant",
|
||||||
"num-rational",
|
"num-rational",
|
||||||
"num-traits",
|
"num-traits 0.2.15",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2299,6 +2379,15 @@ version = "0.1.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4"
|
checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "mach2"
|
||||||
|
version = "0.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6d0d1830bcd151a6fc4aea1369af235b36c1528fe976b8ff678683c9995eade8"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "malloc_buf"
|
name = "malloc_buf"
|
||||||
version = "0.0.6"
|
version = "0.0.6"
|
||||||
@@ -2322,6 +2411,12 @@ dependencies = [
|
|||||||
"tendril",
|
"tendril",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "match_cfg"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "matchers"
|
name = "matchers"
|
||||||
version = "0.0.1"
|
version = "0.0.1"
|
||||||
@@ -2352,6 +2447,24 @@ version = "2.5.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
|
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "memmap2"
|
||||||
|
version = "0.5.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "83faa42c0a078c393f6b29d5db232d8be22776a891f8f56e5284faee4a20b327"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "memoffset"
|
||||||
|
version = "0.6.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "memoffset"
|
name = "memoffset"
|
||||||
version = "0.7.1"
|
version = "0.7.1"
|
||||||
@@ -2376,6 +2489,75 @@ version = "0.3.17"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
|
checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "minidump-common"
|
||||||
|
version = "0.14.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "97dbaf56dfe28d07e1fecffce410976774dcac1f0d7f6d797b437468e989e687"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 1.3.2",
|
||||||
|
"debugid",
|
||||||
|
"enum-primitive-derive",
|
||||||
|
"num-traits 0.2.15",
|
||||||
|
"range-map",
|
||||||
|
"scroll",
|
||||||
|
"smart-default",
|
||||||
|
"tracing",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "minidump-writer"
|
||||||
|
version = "0.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8c8c8fcc3823f1f4eec257a24990ab4c6a20ef9bcbc515400d0eb4a99620b943"
|
||||||
|
dependencies = [
|
||||||
|
"byteorder",
|
||||||
|
"cfg-if",
|
||||||
|
"crash-context",
|
||||||
|
"goblin",
|
||||||
|
"libc",
|
||||||
|
"mach2",
|
||||||
|
"memmap2",
|
||||||
|
"memoffset 0.6.5",
|
||||||
|
"minidump-common",
|
||||||
|
"nix 0.25.1",
|
||||||
|
"scroll",
|
||||||
|
"tempfile",
|
||||||
|
"thiserror",
|
||||||
|
"windows-sys 0.42.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "minidumper"
|
||||||
|
version = "0.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a8e7577424f7abeacef16980ed8e200c84e74aaabb799c3ee30159ea877534fb"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"crash-context",
|
||||||
|
"libc",
|
||||||
|
"log",
|
||||||
|
"minidump-writer",
|
||||||
|
"parking_lot",
|
||||||
|
"polling",
|
||||||
|
"scroll",
|
||||||
|
"thiserror",
|
||||||
|
"uds",
|
||||||
|
"windows-sys 0.42.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "minidumper-child"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c5f6a7c1a63d65dd21fa335135e5a614a7adb03560b2feb9fcb70eef34439bc8"
|
||||||
|
dependencies = [
|
||||||
|
"crash-handler",
|
||||||
|
"minidumper",
|
||||||
|
"thiserror",
|
||||||
|
"uuid",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "minisign-verify"
|
name = "minisign-verify"
|
||||||
version = "0.2.1"
|
version = "0.2.1"
|
||||||
@@ -2483,6 +2665,18 @@ version = "1.0.4"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54"
|
checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "nix"
|
||||||
|
version = "0.25.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f346ff70e7dbfd675fe90590b92d59ef2de15a8779ae305ebcbfd3f0caf59be4"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"bitflags 1.3.2",
|
||||||
|
"cfg-if",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nix"
|
name = "nix"
|
||||||
version = "0.26.2"
|
version = "0.26.2"
|
||||||
@@ -2546,7 +2740,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9"
|
checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"autocfg",
|
"autocfg",
|
||||||
"num-traits",
|
"num-traits 0.2.15",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2557,7 +2751,16 @@ checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"autocfg",
|
"autocfg",
|
||||||
"num-integer",
|
"num-integer",
|
||||||
"num-traits",
|
"num-traits 0.2.15",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-traits"
|
||||||
|
version = "0.1.43"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31"
|
||||||
|
dependencies = [
|
||||||
|
"num-traits 0.2.15",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -3015,6 +3218,12 @@ version = "0.3.26"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160"
|
checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "plain"
|
||||||
|
version = "0.2.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "plist"
|
name = "plist"
|
||||||
version = "1.4.3"
|
version = "1.4.3"
|
||||||
@@ -3223,6 +3432,15 @@ dependencies = [
|
|||||||
"rand_core 0.5.1",
|
"rand_core 0.5.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "range-map"
|
||||||
|
version = "0.1.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "87dc8ff3b0f3e32dbba6e49c592c0191a3a2cabbf6f7e5a78e1010050b9a42e1"
|
||||||
|
dependencies = [
|
||||||
|
"num-traits 0.1.43",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "raw-window-handle"
|
name = "raw-window-handle"
|
||||||
version = "0.5.0"
|
version = "0.5.0"
|
||||||
@@ -3433,6 +3651,26 @@ version = "1.0.5"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1792db035ce95be60c3f8853017b3999209281c24e2ba5bc8e59bf97a0c590c1"
|
checksum = "1792db035ce95be60c3f8853017b3999209281c24e2ba5bc8e59bf97a0c590c1"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "scroll"
|
||||||
|
version = "0.11.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "04c565b551bafbef4157586fa379538366e4385d42082f255bfd96e4fe8519da"
|
||||||
|
dependencies = [
|
||||||
|
"scroll_derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "scroll_derive"
|
||||||
|
version = "0.11.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bdbda6ac5cd1321e724fa9cee216f3a61885889b896f073b8f82322789c5250e"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 1.0.109",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "security-framework"
|
name = "security-framework"
|
||||||
version = "2.8.2"
|
version = "2.8.2"
|
||||||
@@ -3485,6 +3723,112 @@ dependencies = [
|
|||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sentry"
|
||||||
|
version = "0.30.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b5ce6d3512e2617c209ec1e86b0ca2fea06454cd34653c91092bf0f3ec41f8e3"
|
||||||
|
dependencies = [
|
||||||
|
"httpdate",
|
||||||
|
"native-tls",
|
||||||
|
"reqwest",
|
||||||
|
"sentry-backtrace",
|
||||||
|
"sentry-contexts",
|
||||||
|
"sentry-core",
|
||||||
|
"sentry-debug-images",
|
||||||
|
"sentry-panic",
|
||||||
|
"tokio",
|
||||||
|
"ureq",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sentry-backtrace"
|
||||||
|
version = "0.30.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0e7fe408d4d1f8de188a9309916e02e129cbe51ca19e55badea5a64899399b1a"
|
||||||
|
dependencies = [
|
||||||
|
"backtrace",
|
||||||
|
"once_cell",
|
||||||
|
"regex",
|
||||||
|
"sentry-core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sentry-contexts"
|
||||||
|
version = "0.30.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5695096a059a89973ec541062d331ff4c9aeef9c2951416c894f0fff76340e7d"
|
||||||
|
dependencies = [
|
||||||
|
"hostname",
|
||||||
|
"libc",
|
||||||
|
"os_info",
|
||||||
|
"rustc_version",
|
||||||
|
"sentry-core",
|
||||||
|
"uname",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sentry-core"
|
||||||
|
version = "0.30.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5b22828bfd118a7b660cf7a155002a494755c0424cebb7061e4743ecde9c7dbc"
|
||||||
|
dependencies = [
|
||||||
|
"once_cell",
|
||||||
|
"rand 0.8.5",
|
||||||
|
"sentry-types",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sentry-debug-images"
|
||||||
|
version = "0.30.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0a9164d44a2929b1b7670afd7e87552514b70d3ae672ca52884639373d912a3d"
|
||||||
|
dependencies = [
|
||||||
|
"findshlibs",
|
||||||
|
"once_cell",
|
||||||
|
"sentry-core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sentry-panic"
|
||||||
|
version = "0.30.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1f4ced2a7a8c14899d58eec402d946f69d5ed26a3fc363a7e8b1e5cb88473a01"
|
||||||
|
dependencies = [
|
||||||
|
"sentry-backtrace",
|
||||||
|
"sentry-core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sentry-rust-minidump"
|
||||||
|
version = "0.5.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a489204e5cb676310d7ef1506eefb76d006a82f27b648f5477ea74733467d5a1"
|
||||||
|
dependencies = [
|
||||||
|
"minidumper-child",
|
||||||
|
"sentry",
|
||||||
|
"thiserror",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sentry-types"
|
||||||
|
version = "0.30.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "360ee3270f7a4a1eee6c667f7d38360b995431598a73b740dfe420da548d9cc9"
|
||||||
|
dependencies = [
|
||||||
|
"debugid",
|
||||||
|
"getrandom 0.2.8",
|
||||||
|
"hex",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"thiserror",
|
||||||
|
"time 0.3.15",
|
||||||
|
"url",
|
||||||
|
"uuid",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.159"
|
version = "1.0.159"
|
||||||
@@ -3713,6 +4057,17 @@ version = "1.10.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
|
checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "smart-default"
|
||||||
|
version = "0.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "133659a15339456eeeb07572eb02a91c91e9815e9cbc89566944d2c8d3efdbf6"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 1.0.109",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "socket2"
|
name = "socket2"
|
||||||
version = "0.4.9"
|
version = "0.4.9"
|
||||||
@@ -4245,6 +4600,7 @@ dependencies = [
|
|||||||
"tracing-subscriber 0.3.17",
|
"tracing-subscriber 0.3.17",
|
||||||
"url",
|
"url",
|
||||||
"uuid",
|
"uuid",
|
||||||
|
"whoami",
|
||||||
"winreg 0.50.0",
|
"winreg 0.50.0",
|
||||||
"zip",
|
"zip",
|
||||||
]
|
]
|
||||||
@@ -4286,7 +4642,8 @@ dependencies = [
|
|||||||
"futures",
|
"futures",
|
||||||
"objc",
|
"objc",
|
||||||
"os_info",
|
"os_info",
|
||||||
"regex",
|
"sentry",
|
||||||
|
"sentry-rust-minidump",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"tauri",
|
"tauri",
|
||||||
@@ -4530,6 +4887,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8"
|
checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
|
"log",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"tracing-attributes",
|
"tracing-attributes",
|
||||||
"tracing-core",
|
"tracing-core",
|
||||||
@@ -4688,6 +5046,15 @@ version = "1.16.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba"
|
checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "uds"
|
||||||
|
version = "0.2.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "343758ccc8a17c1663182d780f68b52021d68b9a43d4b912b0a01f48b526e4f0"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uds_windows"
|
name = "uds_windows"
|
||||||
version = "1.0.2"
|
version = "1.0.2"
|
||||||
@@ -4698,6 +5065,15 @@ dependencies = [
|
|||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "uname"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b72f89f0ca32e4db1c04e2a72f5345d59796d4866a1ee0609084569f73683dc8"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-bidi"
|
name = "unicode-bidi"
|
||||||
version = "0.3.13"
|
version = "0.3.13"
|
||||||
@@ -4731,6 +5107,19 @@ version = "0.1.10"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b"
|
checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ureq"
|
||||||
|
version = "2.6.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "338b31dd1314f68f3aabf3ed57ab922df95ffcd902476ca7ba3c4ce7b908c46d"
|
||||||
|
dependencies = [
|
||||||
|
"base64 0.13.1",
|
||||||
|
"log",
|
||||||
|
"native-tls",
|
||||||
|
"once_cell",
|
||||||
|
"url",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "url"
|
name = "url"
|
||||||
version = "2.3.1"
|
version = "2.3.1"
|
||||||
@@ -5047,6 +5436,16 @@ dependencies = [
|
|||||||
"windows-metadata",
|
"windows-metadata",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "whoami"
|
||||||
|
version = "1.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2c70234412ca409cc04e864e89523cb0fc37f5e1344ebed5a3ebf4192b6b9f68"
|
||||||
|
dependencies = [
|
||||||
|
"wasm-bindgen",
|
||||||
|
"web-sys",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "widestring"
|
name = "widestring"
|
||||||
version = "0.5.1"
|
version = "0.5.1"
|
||||||
@@ -5480,7 +5879,7 @@ version = "1.0.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2769203cd13a0c6015d515be729c526d041e9cf2c0cc478d57faee85f40c6dcd"
|
checksum = "2769203cd13a0c6015d515be729c526d041e9cf2c0cc478d57faee85f40c6dcd"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"nix",
|
"nix 0.26.2",
|
||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -5516,7 +5915,7 @@ dependencies = [
|
|||||||
"futures-sink",
|
"futures-sink",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"hex",
|
"hex",
|
||||||
"nix",
|
"nix 0.26.2",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"ordered-stream",
|
"ordered-stream",
|
||||||
"rand 0.8.5",
|
"rand 0.8.5",
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ async_zip = { version = "0.0.13", features = ["full"] }
|
|||||||
tempfile = "3.5.0"
|
tempfile = "3.5.0"
|
||||||
|
|
||||||
chrono = { version = "0.4.19", features = ["serde"] }
|
chrono = { version = "0.4.19", features = ["serde"] }
|
||||||
daedalus = { version = "0.1.21" }
|
daedalus = { version = "0.1.23" }
|
||||||
dirs = "5.0.1"
|
dirs = "5.0.1"
|
||||||
|
|
||||||
regex = "1.5"
|
regex = "1.5"
|
||||||
@@ -49,6 +49,8 @@ notify-debouncer-mini = { version = "0.2.1", default-features = false }
|
|||||||
lazy_static = "1.4.0"
|
lazy_static = "1.4.0"
|
||||||
dunce = "1.0.3"
|
dunce = "1.0.3"
|
||||||
|
|
||||||
|
whoami = "1.4.0"
|
||||||
|
|
||||||
[target.'cfg(windows)'.dependencies]
|
[target.'cfg(windows)'.dependencies]
|
||||||
winreg = "0.50.0"
|
winreg = "0.50.0"
|
||||||
|
|
||||||
|
|||||||
@@ -5,8 +5,7 @@ use tokio::fs::read_to_string;
|
|||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
pub struct Logs {
|
pub struct Logs {
|
||||||
pub datetime_string: String,
|
pub datetime_string: String,
|
||||||
pub stdout: Option<String>,
|
pub output: Option<String>,
|
||||||
pub stderr: Option<String>,
|
|
||||||
}
|
}
|
||||||
impl Logs {
|
impl Logs {
|
||||||
async fn build(
|
async fn build(
|
||||||
@@ -15,19 +14,11 @@ impl Logs {
|
|||||||
clear_contents: Option<bool>,
|
clear_contents: Option<bool>,
|
||||||
) -> crate::Result<Self> {
|
) -> crate::Result<Self> {
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
stdout: if clear_contents.unwrap_or(false) {
|
output: if clear_contents.unwrap_or(false) {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
Some(
|
Some(
|
||||||
get_stdout_by_datetime(profile_uuid, &datetime_string)
|
get_output_by_datetime(profile_uuid, &datetime_string)
|
||||||
.await?,
|
|
||||||
)
|
|
||||||
},
|
|
||||||
stderr: if clear_contents.unwrap_or(false) {
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
Some(
|
|
||||||
get_stderr_by_datetime(profile_uuid, &datetime_string)
|
|
||||||
.await?,
|
.await?,
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
@@ -74,18 +65,15 @@ pub async fn get_logs_by_datetime(
|
|||||||
datetime_string: String,
|
datetime_string: String,
|
||||||
) -> crate::Result<Logs> {
|
) -> crate::Result<Logs> {
|
||||||
Ok(Logs {
|
Ok(Logs {
|
||||||
stdout: Some(
|
output: Some(
|
||||||
get_stdout_by_datetime(profile_uuid, &datetime_string).await?,
|
get_output_by_datetime(profile_uuid, &datetime_string).await?,
|
||||||
),
|
|
||||||
stderr: Some(
|
|
||||||
get_stderr_by_datetime(profile_uuid, &datetime_string).await?,
|
|
||||||
),
|
),
|
||||||
datetime_string,
|
datetime_string,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument]
|
#[tracing::instrument]
|
||||||
pub async fn get_stdout_by_datetime(
|
pub async fn get_output_by_datetime(
|
||||||
profile_uuid: uuid::Uuid,
|
profile_uuid: uuid::Uuid,
|
||||||
datetime_string: &str,
|
datetime_string: &str,
|
||||||
) -> crate::Result<String> {
|
) -> crate::Result<String> {
|
||||||
@@ -97,19 +85,6 @@ pub async fn get_stdout_by_datetime(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument]
|
|
||||||
pub async fn get_stderr_by_datetime(
|
|
||||||
profile_uuid: uuid::Uuid,
|
|
||||||
datetime_string: &str,
|
|
||||||
) -> crate::Result<String> {
|
|
||||||
let state = State::get().await?;
|
|
||||||
let logs_folder = state.directories.profile_logs_dir(profile_uuid);
|
|
||||||
Ok(
|
|
||||||
read_to_string(logs_folder.join(datetime_string).join("stderr.log"))
|
|
||||||
.await?,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tracing::instrument]
|
#[tracing::instrument]
|
||||||
pub async fn delete_logs(profile_uuid: uuid::Uuid) -> crate::Result<()> {
|
pub async fn delete_logs(profile_uuid: uuid::Uuid) -> crate::Result<()> {
|
||||||
let state = State::get().await?;
|
let state = State::get().await?;
|
||||||
|
|||||||
@@ -335,7 +335,6 @@ async fn install_pack(
|
|||||||
async { Ok(()) }
|
async { Ok(()) }
|
||||||
})
|
})
|
||||||
.await?;
|
.await?;
|
||||||
State::sync().await?;
|
|
||||||
|
|
||||||
let profile = profile.clone();
|
let profile = profile.clone();
|
||||||
let result = async {
|
let result = async {
|
||||||
@@ -487,6 +486,8 @@ async fn install_pack(
|
|||||||
Some(loading_bar),
|
Some(loading_bar),
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
State::sync().await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok::<PathBuf, crate::Error>(profile.clone())
|
Ok::<PathBuf, crate::Error>(profile.clone())
|
||||||
|
|||||||
@@ -69,9 +69,9 @@ pub async fn get_uuids_by_profile_path(
|
|||||||
children.running_keys_with_profile(profile_path).await
|
children.running_keys_with_profile(profile_path).await
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gets stdout of a child process stored in the state by UUID, as a string
|
// Gets output of a child process stored in the state by UUID, as a string
|
||||||
#[tracing::instrument]
|
#[tracing::instrument]
|
||||||
pub async fn get_stdout_by_uuid(uuid: &Uuid) -> crate::Result<String> {
|
pub async fn get_output_by_uuid(uuid: &Uuid) -> crate::Result<String> {
|
||||||
let state = State::get().await?;
|
let state = State::get().await?;
|
||||||
// Get stdout from child
|
// Get stdout from child
|
||||||
let children = state.children.read().await;
|
let children = state.children.read().await;
|
||||||
@@ -79,7 +79,7 @@ pub async fn get_stdout_by_uuid(uuid: &Uuid) -> crate::Result<String> {
|
|||||||
// Extract child or return crate::Error
|
// Extract child or return crate::Error
|
||||||
if let Some(child) = children.get(uuid) {
|
if let Some(child) = children.get(uuid) {
|
||||||
let child = child.read().await;
|
let child = child.read().await;
|
||||||
Ok(child.stdout.get_output().await?)
|
Ok(child.output.get_output().await?)
|
||||||
} else {
|
} else {
|
||||||
Err(crate::ErrorKind::LauncherError(format!(
|
Err(crate::ErrorKind::LauncherError(format!(
|
||||||
"No child process by UUID {}",
|
"No child process by UUID {}",
|
||||||
@@ -89,26 +89,6 @@ pub async fn get_stdout_by_uuid(uuid: &Uuid) -> crate::Result<String> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Gets stderr of a child process stored in the state by UUID, as a string
|
|
||||||
#[tracing::instrument]
|
|
||||||
pub async fn get_stderr_by_uuid(uuid: &Uuid) -> crate::Result<String> {
|
|
||||||
let state = State::get().await?;
|
|
||||||
// Get stdout from child
|
|
||||||
let children = state.children.read().await;
|
|
||||||
|
|
||||||
// Extract child or return crate::Error
|
|
||||||
if let Some(child) = children.get(uuid) {
|
|
||||||
let child = child.read().await;
|
|
||||||
Ok(child.stderr.get_output().await?)
|
|
||||||
} else {
|
|
||||||
Err(crate::ErrorKind::LauncherError(format!(
|
|
||||||
"No child process with UUID {}",
|
|
||||||
uuid
|
|
||||||
))
|
|
||||||
.as_error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Kill a child process stored in the state by UUID, as a string
|
// Kill a child process stored in the state by UUID, as a string
|
||||||
#[tracing::instrument]
|
#[tracing::instrument]
|
||||||
pub async fn kill_by_uuid(uuid: &Uuid) -> crate::Result<()> {
|
pub async fn kill_by_uuid(uuid: &Uuid) -> crate::Result<()> {
|
||||||
@@ -150,7 +130,7 @@ pub async fn kill(running: &mut MinecraftChild) -> crate::Result<()> {
|
|||||||
pub async fn wait_for(running: &mut MinecraftChild) -> crate::Result<()> {
|
pub async fn wait_for(running: &mut MinecraftChild) -> crate::Result<()> {
|
||||||
// We do not wait on the Child directly, but wait on the thread manager.
|
// We do not wait on the Child directly, but wait on the thread manager.
|
||||||
// This way we can still run all cleanup hook functions that happen after.
|
// This way we can still run all cleanup hook functions that happen after.
|
||||||
let result = running
|
running
|
||||||
.manager
|
.manager
|
||||||
.take()
|
.take()
|
||||||
.ok_or_else(|| {
|
.ok_or_else(|| {
|
||||||
@@ -166,12 +146,5 @@ pub async fn wait_for(running: &mut MinecraftChild) -> crate::Result<()> {
|
|||||||
))
|
))
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
match result.success() {
|
Ok(())
|
||||||
false => Err(crate::ErrorKind::LauncherError(format!(
|
|
||||||
"Minecraft exited with non-zero code {}",
|
|
||||||
result.code().unwrap_or(-1)
|
|
||||||
))
|
|
||||||
.as_error()),
|
|
||||||
true => Ok(()),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -120,6 +120,7 @@ pub async fn edit_icon(
|
|||||||
ProfilePayloadType::Edited,
|
ProfilePayloadType::Edited,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
State::sync().await?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -133,7 +134,10 @@ pub async fn edit_icon(
|
|||||||
profile.metadata.icon = None;
|
profile.metadata.icon = None;
|
||||||
async { Ok(()) }
|
async { Ok(()) }
|
||||||
})
|
})
|
||||||
.await
|
.await?;
|
||||||
|
State::sync().await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -288,6 +292,7 @@ pub async fn update_all(
|
|||||||
ProfilePayloadType::Edited,
|
ProfilePayloadType::Edited,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
State::sync().await?;
|
||||||
|
|
||||||
Ok(Arc::try_unwrap(map).unwrap().into_inner())
|
Ok(Arc::try_unwrap(map).unwrap().into_inner())
|
||||||
} else {
|
} else {
|
||||||
@@ -344,6 +349,7 @@ pub async fn update_project(
|
|||||||
ProfilePayloadType::Edited,
|
ProfilePayloadType::Edited,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
State::sync().await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Ok(path);
|
return Ok(path);
|
||||||
@@ -378,6 +384,7 @@ pub async fn add_project_from_version(
|
|||||||
ProfilePayloadType::Edited,
|
ProfilePayloadType::Edited,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
State::sync().await?;
|
||||||
|
|
||||||
Ok(path)
|
Ok(path)
|
||||||
} else {
|
} else {
|
||||||
@@ -418,6 +425,7 @@ pub async fn add_project_from_path(
|
|||||||
ProfilePayloadType::Edited,
|
ProfilePayloadType::Edited,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
State::sync().await?;
|
||||||
|
|
||||||
Ok(path)
|
Ok(path)
|
||||||
} else {
|
} else {
|
||||||
@@ -444,6 +452,7 @@ pub async fn toggle_disable_project(
|
|||||||
ProfilePayloadType::Edited,
|
ProfilePayloadType::Edited,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
State::sync().await?;
|
||||||
|
|
||||||
Ok(res)
|
Ok(res)
|
||||||
} else {
|
} else {
|
||||||
@@ -470,6 +479,7 @@ pub async fn remove_project(
|
|||||||
ProfilePayloadType::Edited,
|
ProfilePayloadType::Edited,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
State::sync().await?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -164,7 +164,11 @@ pub(crate) async fn get_loader_version_from_loader(
|
|||||||
let filter = |it: &LoaderVersion| match version.as_str() {
|
let filter = |it: &LoaderVersion| match version.as_str() {
|
||||||
"latest" => true,
|
"latest" => true,
|
||||||
"stable" => it.stable,
|
"stable" => it.stable,
|
||||||
id => it.id == *id || format!("{}-{}", game_version, id) == it.id,
|
id => {
|
||||||
|
it.id == *id
|
||||||
|
|| format!("{}-{}", game_version, id) == it.id
|
||||||
|
|| format!("{}-{}-{}", game_version, id, game_version) == it.id
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let loader_data = match loader {
|
let loader_data = match loader {
|
||||||
|
|||||||
@@ -124,7 +124,7 @@ impl Drop for LoadingBarId {
|
|||||||
// Emit event to indicatif progress bar arc
|
// Emit event to indicatif progress bar arc
|
||||||
#[cfg(feature = "cli")]
|
#[cfg(feature = "cli")]
|
||||||
{
|
{
|
||||||
let cli_progress_bar = bar.cli_progress_bar.clone();
|
let cli_progress_bar = bar.cli_progress_bar;
|
||||||
cli_progress_bar.finish();
|
cli_progress_bar.finish();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -262,12 +262,17 @@ fn parse_minecraft_argument(
|
|||||||
resolution: WindowSize,
|
resolution: WindowSize,
|
||||||
) -> crate::Result<String> {
|
) -> crate::Result<String> {
|
||||||
Ok(argument
|
Ok(argument
|
||||||
|
.replace("${accessToken}", access_token)
|
||||||
.replace("${auth_access_token}", access_token)
|
.replace("${auth_access_token}", access_token)
|
||||||
.replace("${auth_session}", access_token)
|
.replace("${auth_session}", access_token)
|
||||||
.replace("${auth_player_name}", username)
|
.replace("${auth_player_name}", username)
|
||||||
|
// TODO: add auth xuid eventually
|
||||||
|
.replace("${auth_xuid}", "0")
|
||||||
.replace("${auth_uuid}", &uuid.hyphenated().to_string())
|
.replace("${auth_uuid}", &uuid.hyphenated().to_string())
|
||||||
|
.replace("${uuid}", &uuid.hyphenated().to_string())
|
||||||
|
.replace("${clientid}", "c4502edb-87c6-40cb-b595-64a280cf8906")
|
||||||
.replace("${user_properties}", "{}")
|
.replace("${user_properties}", "{}")
|
||||||
.replace("${user_type}", "mojang")
|
.replace("${user_type}", "msa")
|
||||||
.replace("${version_name}", version)
|
.replace("${version_name}", version)
|
||||||
.replace("${assets_index_name}", asset_index_name)
|
.replace("${assets_index_name}", asset_index_name)
|
||||||
.replace(
|
.replace(
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ use daedalus as d;
|
|||||||
use daedalus::minecraft::VersionInfo;
|
use daedalus::minecraft::VersionInfo;
|
||||||
use dunce::canonicalize;
|
use dunce::canonicalize;
|
||||||
use st::Profile;
|
use st::Profile;
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::{process::Stdio, sync::Arc};
|
use std::{process::Stdio, sync::Arc};
|
||||||
use tokio::process::Command;
|
use tokio::process::Command;
|
||||||
@@ -36,9 +37,12 @@ pub fn parse_rule(rule: &d::minecraft::Rule, java_version: &str) -> bool {
|
|||||||
features: Some(ref features),
|
features: Some(ref features),
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
features.has_demo_resolution.unwrap_or(false)
|
!features.is_demo_user.unwrap_or(true)
|
||||||
|| (features.has_demo_resolution.is_none()
|
|| features.has_custom_resolution.unwrap_or(false)
|
||||||
&& features.is_demo_user.is_none())
|
|| !features.has_quick_plays_support.unwrap_or(true)
|
||||||
|
|| !features.is_quick_play_multiplayer.unwrap_or(true)
|
||||||
|
|| !features.is_quick_play_realms.unwrap_or(true)
|
||||||
|
|| !features.is_quick_play_singleplayer.unwrap_or(true)
|
||||||
}
|
}
|
||||||
_ => false,
|
_ => false,
|
||||||
};
|
};
|
||||||
@@ -431,7 +435,6 @@ pub async fn launch_minecraft(
|
|||||||
fs::create_dir_all(&logs_dir)?;
|
fs::create_dir_all(&logs_dir)?;
|
||||||
|
|
||||||
let stdout_log_path = logs_dir.join("stdout.log");
|
let stdout_log_path = logs_dir.join("stdout.log");
|
||||||
let stderr_log_path = logs_dir.join("stderr.log");
|
|
||||||
|
|
||||||
crate::api::profile::edit(&profile.path, |prof| {
|
crate::api::profile::edit(&profile.path, |prof| {
|
||||||
prof.metadata.last_played = Some(Utc::now());
|
prof.metadata.last_played = Some(Utc::now());
|
||||||
@@ -439,6 +442,34 @@ pub async fn launch_minecraft(
|
|||||||
async { Ok(()) }
|
async { Ok(()) }
|
||||||
})
|
})
|
||||||
.await?;
|
.await?;
|
||||||
|
State::sync().await?;
|
||||||
|
|
||||||
|
let mut censor_strings = HashMap::new();
|
||||||
|
let username = whoami::username();
|
||||||
|
censor_strings.insert(
|
||||||
|
format!("/{}/", username),
|
||||||
|
"/{COMPUTER_USERNAME}/".to_string(),
|
||||||
|
);
|
||||||
|
censor_strings.insert(
|
||||||
|
format!("\\{}\\", username),
|
||||||
|
"\\{COMPUTER_USERNAME}\\".to_string(),
|
||||||
|
);
|
||||||
|
censor_strings.insert(
|
||||||
|
credentials.access_token.clone(),
|
||||||
|
"{MINECRAFT_ACCESS_TOKEN}".to_string(),
|
||||||
|
);
|
||||||
|
censor_strings.insert(
|
||||||
|
credentials.username.clone(),
|
||||||
|
"{MINECRAFT_USERNAME}".to_string(),
|
||||||
|
);
|
||||||
|
censor_strings.insert(
|
||||||
|
credentials.id.as_simple().to_string(),
|
||||||
|
"{MINECRAFT_UUID}".to_string(),
|
||||||
|
);
|
||||||
|
censor_strings.insert(
|
||||||
|
credentials.id.as_hyphenated().to_string(),
|
||||||
|
"{MINECRAFT_UUID}".to_string(),
|
||||||
|
);
|
||||||
|
|
||||||
// Create Minecraft child by inserting it into the state
|
// Create Minecraft child by inserting it into the state
|
||||||
// This also spawns the process and prepares the subsequent processes
|
// This also spawns the process and prepares the subsequent processes
|
||||||
@@ -448,9 +479,9 @@ pub async fn launch_minecraft(
|
|||||||
Uuid::new_v4(),
|
Uuid::new_v4(),
|
||||||
instance_path.to_path_buf(),
|
instance_path.to_path_buf(),
|
||||||
stdout_log_path,
|
stdout_log_path,
|
||||||
stderr_log_path,
|
|
||||||
command,
|
command,
|
||||||
post_exit_hook,
|
post_exit_hook,
|
||||||
|
censor_strings,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,8 +26,7 @@ pub struct MinecraftChild {
|
|||||||
pub profile_path: PathBuf, //todo: make UUID when profiles are recognized by UUID
|
pub profile_path: PathBuf, //todo: make UUID when profiles are recognized by UUID
|
||||||
pub manager: Option<JoinHandle<crate::Result<ExitStatus>>>, // None when future has completed and been handled
|
pub manager: Option<JoinHandle<crate::Result<ExitStatus>>>, // None when future has completed and been handled
|
||||||
pub current_child: Arc<RwLock<Child>>,
|
pub current_child: Arc<RwLock<Child>>,
|
||||||
pub stdout: SharedOutput,
|
pub output: SharedOutput,
|
||||||
pub stderr: SharedOutput,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Children {
|
impl Children {
|
||||||
@@ -45,27 +44,27 @@ impl Children {
|
|||||||
&mut self,
|
&mut self,
|
||||||
uuid: Uuid,
|
uuid: Uuid,
|
||||||
profile_path: PathBuf,
|
profile_path: PathBuf,
|
||||||
stdout_log_path: PathBuf,
|
log_path: PathBuf,
|
||||||
stderr_log_path: PathBuf,
|
|
||||||
mut mc_command: Command,
|
mut mc_command: Command,
|
||||||
post_command: Option<Command>, // Command to run after minecraft.
|
post_command: Option<Command>, // Command to run after minecraft.
|
||||||
|
censor_strings: HashMap<String, String>,
|
||||||
) -> crate::Result<Arc<RwLock<MinecraftChild>>> {
|
) -> crate::Result<Arc<RwLock<MinecraftChild>>> {
|
||||||
// Takes the first element of the commands vector and spawns it
|
// Takes the first element of the commands vector and spawns it
|
||||||
let mut child = mc_command.spawn()?;
|
let mut child = mc_command.spawn()?;
|
||||||
|
|
||||||
// Create std watcher threads for stdout and stderr
|
// Create std watcher threads for stdout and stderr
|
||||||
let stdout = SharedOutput::build(&stdout_log_path).await?;
|
let shared_output =
|
||||||
|
SharedOutput::build(&log_path, censor_strings).await?;
|
||||||
if let Some(child_stdout) = child.stdout.take() {
|
if let Some(child_stdout) = child.stdout.take() {
|
||||||
let stdout_clone = stdout.clone();
|
let stdout_clone = shared_output.clone();
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
if let Err(e) = stdout_clone.read_stdout(child_stdout).await {
|
if let Err(e) = stdout_clone.read_stdout(child_stdout).await {
|
||||||
error!("Stdout process died with error: {}", e);
|
error!("Stdout process died with error: {}", e);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
let stderr = SharedOutput::build(&stderr_log_path).await?;
|
|
||||||
if let Some(child_stderr) = child.stderr.take() {
|
if let Some(child_stderr) = child.stderr.take() {
|
||||||
let stderr_clone = stderr.clone();
|
let stderr_clone = shared_output.clone();
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
if let Err(e) = stderr_clone.read_stderr(child_stderr).await {
|
if let Err(e) = stderr_clone.read_stderr(child_stderr).await {
|
||||||
error!("Stderr process died with error: {}", e);
|
error!("Stderr process died with error: {}", e);
|
||||||
@@ -100,8 +99,7 @@ impl Children {
|
|||||||
uuid,
|
uuid,
|
||||||
profile_path,
|
profile_path,
|
||||||
current_child,
|
current_child,
|
||||||
stdout,
|
output: shared_output,
|
||||||
stderr,
|
|
||||||
manager,
|
manager,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -293,13 +291,18 @@ impl Default for Children {
|
|||||||
pub struct SharedOutput {
|
pub struct SharedOutput {
|
||||||
output: Arc<RwLock<String>>,
|
output: Arc<RwLock<String>>,
|
||||||
log_file: Arc<RwLock<File>>,
|
log_file: Arc<RwLock<File>>,
|
||||||
|
censor_strings: HashMap<String, String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SharedOutput {
|
impl SharedOutput {
|
||||||
async fn build(log_file_path: &Path) -> crate::Result<Self> {
|
async fn build(
|
||||||
|
log_file_path: &Path,
|
||||||
|
censor_strings: HashMap<String, String>,
|
||||||
|
) -> crate::Result<Self> {
|
||||||
Ok(SharedOutput {
|
Ok(SharedOutput {
|
||||||
output: Arc::new(RwLock::new(String::new())),
|
output: Arc::new(RwLock::new(String::new())),
|
||||||
log_file: Arc::new(RwLock::new(File::create(log_file_path).await?)),
|
log_file: Arc::new(RwLock::new(File::create(log_file_path).await?)),
|
||||||
|
censor_strings,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -317,14 +320,17 @@ impl SharedOutput {
|
|||||||
let mut line = String::new();
|
let mut line = String::new();
|
||||||
|
|
||||||
while buf_reader.read_line(&mut line).await? > 0 {
|
while buf_reader.read_line(&mut line).await? > 0 {
|
||||||
|
let val_line = self.censor_log(line.clone());
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut output = self.output.write().await;
|
let mut output = self.output.write().await;
|
||||||
output.push_str(&line);
|
output.push_str(&val_line);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
let mut log_file = self.log_file.write().await;
|
let mut log_file = self.log_file.write().await;
|
||||||
log_file.write_all(line.as_bytes()).await?;
|
log_file.write_all(val_line.as_bytes()).await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
line.clear();
|
line.clear();
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -338,12 +344,27 @@ impl SharedOutput {
|
|||||||
let mut line = String::new();
|
let mut line = String::new();
|
||||||
|
|
||||||
while buf_reader.read_line(&mut line).await? > 0 {
|
while buf_reader.read_line(&mut line).await? > 0 {
|
||||||
|
let val_line = self.censor_log(line.clone());
|
||||||
|
|
||||||
{
|
{
|
||||||
let mut output = self.output.write().await;
|
let mut output = self.output.write().await;
|
||||||
output.push_str(&line);
|
output.push_str(&val_line);
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
let mut log_file = self.log_file.write().await;
|
||||||
|
log_file.write_all(val_line.as_bytes()).await?;
|
||||||
|
}
|
||||||
|
|
||||||
line.clear();
|
line.clear();
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn censor_log(&self, mut val: String) -> String {
|
||||||
|
for (find, replace) in &self.censor_strings {
|
||||||
|
val = val.replace(find, replace);
|
||||||
|
}
|
||||||
|
|
||||||
|
val
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -266,7 +266,16 @@ async fn init_watcher() -> crate::Result<Debouncer<RecommendedWatcher>> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !visited_paths.contains(&new_path) {
|
if e.path
|
||||||
|
.components()
|
||||||
|
.any(|x| x.as_os_str() == "crash-reports")
|
||||||
|
&& e.path
|
||||||
|
.extension()
|
||||||
|
.map(|x| x == "txt")
|
||||||
|
.unwrap_or(false)
|
||||||
|
{
|
||||||
|
Profile::crash_task(new_path);
|
||||||
|
} else if !visited_paths.contains(&new_path) {
|
||||||
Profile::sync_projects_task(new_path.clone());
|
Profile::sync_projects_task(new_path.clone());
|
||||||
visited_paths.push(new_path);
|
visited_paths.push(new_path);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use super::settings::{Hooks, MemorySettings, WindowSize};
|
use super::settings::{Hooks, MemorySettings, WindowSize};
|
||||||
use crate::config::MODRINTH_API_URL;
|
use crate::config::MODRINTH_API_URL;
|
||||||
use crate::data::DirectoryInfo;
|
use crate::data::DirectoryInfo;
|
||||||
use crate::event::emit::emit_profile;
|
use crate::event::emit::{emit_profile, emit_warning};
|
||||||
use crate::event::ProfilePayloadType;
|
use crate::event::ProfilePayloadType;
|
||||||
use crate::prelude::JavaVersion;
|
use crate::prelude::JavaVersion;
|
||||||
use crate::state::projects::Project;
|
use crate::state::projects::Project;
|
||||||
@@ -198,6 +198,30 @@ impl Profile {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn crash_task(path: PathBuf) {
|
||||||
|
tokio::task::spawn(async move {
|
||||||
|
let res = async {
|
||||||
|
let profile = crate::api::profile::get(&path, None).await?;
|
||||||
|
|
||||||
|
if let Some(profile) = profile {
|
||||||
|
emit_warning(&format!("Profile {} has crashed! Visit the logs page to see a crash report.", profile.metadata.name)).await?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok::<(), crate::Error>(())
|
||||||
|
}
|
||||||
|
.await;
|
||||||
|
|
||||||
|
match res {
|
||||||
|
Ok(()) => {}
|
||||||
|
Err(err) => {
|
||||||
|
tracing::warn!(
|
||||||
|
"Unable to send crash report to frontend: {err}"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
pub fn sync_projects_task(path: PathBuf) {
|
pub fn sync_projects_task(path: PathBuf) {
|
||||||
tokio::task::spawn(async move {
|
tokio::task::spawn(async move {
|
||||||
let res = async {
|
let res = async {
|
||||||
@@ -306,6 +330,7 @@ impl Profile {
|
|||||||
.await?;
|
.await?;
|
||||||
watch_path(profile_path, watcher, ProjectType::DataPack.get_folder())
|
watch_path(profile_path, watcher, ProjectType::DataPack.get_folder())
|
||||||
.await?;
|
.await?;
|
||||||
|
watch_path(profile_path, watcher, "crash-reports").await?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -575,6 +600,11 @@ impl Profiles {
|
|||||||
))
|
))
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
{
|
||||||
|
let profiles = state.profiles.read().await;
|
||||||
|
profiles.sync().await?;
|
||||||
|
}
|
||||||
|
|
||||||
Ok::<(), crate::Error>(())
|
Ok::<(), crate::Error>(())
|
||||||
}
|
}
|
||||||
.await;
|
.await;
|
||||||
|
|||||||
@@ -28,6 +28,10 @@ pub struct Settings {
|
|||||||
pub collapsed_navigation: bool,
|
pub collapsed_navigation: bool,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub developer_mode: bool,
|
pub developer_mode: bool,
|
||||||
|
#[serde(default)]
|
||||||
|
pub opt_out_analytics: bool,
|
||||||
|
#[serde(default)]
|
||||||
|
pub advanced_rendering: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Settings {
|
impl Default for Settings {
|
||||||
@@ -46,6 +50,8 @@ impl Default for Settings {
|
|||||||
version: CURRENT_FORMAT_VERSION,
|
version: CURRENT_FORMAT_VERSION,
|
||||||
collapsed_navigation: false,
|
collapsed_navigation: false,
|
||||||
developer_mode: false,
|
developer_mode: false,
|
||||||
|
opt_out_analytics: false,
|
||||||
|
advanced_rendering: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,8 +16,9 @@
|
|||||||
"@tauri-apps/api": "^1.3.0",
|
"@tauri-apps/api": "^1.3.0",
|
||||||
"dayjs": "^1.11.7",
|
"dayjs": "^1.11.7",
|
||||||
"floating-vue": "^2.0.0-beta.20",
|
"floating-vue": "^2.0.0-beta.20",
|
||||||
|
"mixpanel-browser": "^2.47.0",
|
||||||
"ofetch": "^1.0.1",
|
"ofetch": "^1.0.1",
|
||||||
"omorphia": "^0.4.27",
|
"omorphia": "^0.4.28",
|
||||||
"pinia": "^2.1.3",
|
"pinia": "^2.1.3",
|
||||||
"vite-svg-loader": "^4.0.0",
|
"vite-svg-loader": "^4.0.0",
|
||||||
"vue": "^3.3.4",
|
"vue": "^3.3.4",
|
||||||
|
|||||||
15
theseus_gui/pnpm-lock.yaml
generated
15
theseus_gui/pnpm-lock.yaml
generated
@@ -10,12 +10,15 @@ dependencies:
|
|||||||
floating-vue:
|
floating-vue:
|
||||||
specifier: ^2.0.0-beta.20
|
specifier: ^2.0.0-beta.20
|
||||||
version: 2.0.0-beta.20(vue@3.3.4)
|
version: 2.0.0-beta.20(vue@3.3.4)
|
||||||
|
mixpanel-browser:
|
||||||
|
specifier: ^2.47.0
|
||||||
|
version: 2.47.0
|
||||||
ofetch:
|
ofetch:
|
||||||
specifier: ^1.0.1
|
specifier: ^1.0.1
|
||||||
version: 1.0.1
|
version: 1.0.1
|
||||||
omorphia:
|
omorphia:
|
||||||
specifier: ^0.4.27
|
specifier: ^0.4.28
|
||||||
version: 0.4.27
|
version: 0.4.28
|
||||||
pinia:
|
pinia:
|
||||||
specifier: ^2.1.3
|
specifier: ^2.1.3
|
||||||
version: 2.1.3(vue@3.3.4)
|
version: 2.1.3(vue@3.3.4)
|
||||||
@@ -1291,6 +1294,10 @@ packages:
|
|||||||
brace-expansion: 1.1.11
|
brace-expansion: 1.1.11
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/mixpanel-browser@2.47.0:
|
||||||
|
resolution: {integrity: sha512-Ldrva0fRBEIFWmEibBQO1PulfpJVF3pf28Guk09lDirDaSQqqU/xs9zQLwN2rL5VwVtsP1aD3JaCgaa98EjojQ==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/ms@2.1.2:
|
/ms@2.1.2:
|
||||||
resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==}
|
resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==}
|
||||||
dev: true
|
dev: true
|
||||||
@@ -1326,8 +1333,8 @@ packages:
|
|||||||
ufo: 1.1.2
|
ufo: 1.1.2
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/omorphia@0.4.27:
|
/omorphia@0.4.28:
|
||||||
resolution: {integrity: sha512-DvT8jTAE0RW9qAD2LAIkztVmhZkkITZ3ER587guK69KD2iErm+ZRSKCUJIOXFet94B9+d8+M3eM2pIiBnAkD9Q==}
|
resolution: {integrity: sha512-ZTUgBD3ZL+aymS7u5pLaPo8I5FUI8fkoz2dZLtAS5ksGRI5wrWkwIi/kxjpC95A2oDxNQvZaylfwUTK3Z6a2Sw==}
|
||||||
dependencies:
|
dependencies:
|
||||||
dayjs: 1.11.7
|
dayjs: 1.11.7
|
||||||
floating-vue: 2.0.0-beta.20(vue@3.3.4)
|
floating-vue: 2.0.0-beta.20(vue@3.3.4)
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ build = "build.rs"
|
|||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
tauri-build = { version = "1.3", features = [] }
|
tauri-build = { version = "1.3", features = [] }
|
||||||
regex = "1.5"
|
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
theseus = { path = "../../theseus", features = ["tauri"] }
|
theseus = { path = "../../theseus", features = ["tauri"] }
|
||||||
@@ -37,6 +36,9 @@ tracing = "0.1.37"
|
|||||||
tracing-subscriber = "0.2"
|
tracing-subscriber = "0.2"
|
||||||
tracing-error = "0.1"
|
tracing-error = "0.1"
|
||||||
|
|
||||||
|
sentry = "0.30"
|
||||||
|
sentry-rust-minidump = "0.5"
|
||||||
|
|
||||||
[target.'cfg(target_os = "macos")'.dependencies]
|
[target.'cfg(target_os = "macos")'.dependencies]
|
||||||
cocoa = "0.24.1"
|
cocoa = "0.24.1"
|
||||||
objc = "0.2.7"
|
objc = "0.2.7"
|
||||||
|
|||||||
@@ -1,111 +1,4 @@
|
|||||||
use std::fs;
|
|
||||||
|
|
||||||
use regex::Regex;
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
// Build the Tauri app
|
// Build the Tauri app
|
||||||
tauri_build::build();
|
tauri_build::build();
|
||||||
|
|
||||||
// Check that all JavaScript 'invoke' Tauri functions have a corresponding tagged Rust function
|
|
||||||
// This is to prevent the app from crashing if a JavaScript function is invoked but the corresponding Rust function is not tagged
|
|
||||||
// This only allows simple functions, but functions in theseus_gui should be kept simple
|
|
||||||
check_invoke_sanity();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn check_invoke_sanity() {
|
|
||||||
let js_files = read_js_files("../src/helpers");
|
|
||||||
let rust_files = read_rust_files("src");
|
|
||||||
|
|
||||||
let js_function_names = extract_js_function_names(&js_files);
|
|
||||||
let rust_function_names = extract_rust_function_names(&rust_files);
|
|
||||||
|
|
||||||
let mut missing_functions = Vec::new();
|
|
||||||
for js_fn_name in js_function_names {
|
|
||||||
if !rust_function_names.contains(&js_fn_name) {
|
|
||||||
missing_functions.push(js_fn_name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !missing_functions.is_empty() {
|
|
||||||
panic!(
|
|
||||||
"The following invoked Tauri functions do not have corresponding Rust functions with #[tauri::command] attribute :\n{}",
|
|
||||||
missing_functions.join("\n")
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn read_js_files(directory: &str) -> Vec<String> {
|
|
||||||
let mut files = Vec::new();
|
|
||||||
read_files_recursively(directory, "js", &mut files);
|
|
||||||
files
|
|
||||||
}
|
|
||||||
|
|
||||||
fn read_rust_files(directory: &str) -> Vec<String> {
|
|
||||||
let mut files = Vec::new();
|
|
||||||
read_files_recursively(directory, "rs", &mut files);
|
|
||||||
files
|
|
||||||
}
|
|
||||||
|
|
||||||
// Recursive in case we make the helpers directory more complex
|
|
||||||
fn read_files_recursively(
|
|
||||||
directory: &str,
|
|
||||||
extension: &str,
|
|
||||||
files: &mut Vec<String>,
|
|
||||||
) {
|
|
||||||
for entry in fs::read_dir(directory).unwrap() {
|
|
||||||
let entry = entry.unwrap();
|
|
||||||
let path = entry.path();
|
|
||||||
if path.is_dir() {
|
|
||||||
read_files_recursively(&path.to_string_lossy(), extension, files);
|
|
||||||
} else if path.extension().map_or(false, |ext| ext == extension) {
|
|
||||||
let content = fs::read_to_string(path).unwrap();
|
|
||||||
files.push(content);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn extract_rust_function_names(rust_files: &[String]) -> Vec<String> {
|
|
||||||
// Matches #[tauri::command] attribute
|
|
||||||
let re_tauri_command = Regex::new(r"(?m)#\[tauri::command\]").unwrap();
|
|
||||||
// Matches function name following the #[tauri::command] attribute
|
|
||||||
// Matches up to the first (, to allow for function arguments and comments in that area
|
|
||||||
let re_function_name =
|
|
||||||
Regex::new(r"fn\s+([a-zA-Z_][a-zA-Z0-9_]*)\s*\(").unwrap();
|
|
||||||
let mut function_names = Vec::new();
|
|
||||||
|
|
||||||
for file in rust_files {
|
|
||||||
let mut start = 0;
|
|
||||||
while let Some(command_match) = re_tauri_command.find_at(file, start) {
|
|
||||||
if let Some(function_name_cap) =
|
|
||||||
re_function_name.captures(&file[command_match.end()..])
|
|
||||||
{
|
|
||||||
function_names.push(function_name_cap[1].to_string());
|
|
||||||
start = command_match.start() + 1;
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function_names
|
|
||||||
}
|
|
||||||
|
|
||||||
fn extract_js_function_names(js_files: &[String]) -> Vec<String> {
|
|
||||||
// Matches functions of the form: invoke('function_name', { ... }) (or invoke('function_name') )
|
|
||||||
let re_invoke = Regex::new(
|
|
||||||
r"(?m)invoke\(\s*'([a-zA-Z_][a-zA-Z0-9_]*)'\s*(?:,\s*\{.*?\})?\s*\)",
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
let mut function_names = Vec::new();
|
|
||||||
|
|
||||||
for file in js_files {
|
|
||||||
let mut start = 0;
|
|
||||||
while let Some(invoke_match) = re_invoke.find_at(file, start) {
|
|
||||||
if let Some(captures) = re_invoke.captures(invoke_match.as_str()) {
|
|
||||||
function_names.push(captures[1].to_string());
|
|
||||||
}
|
|
||||||
start = invoke_match.start() + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function_names
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,20 +34,11 @@ pub async fn logs_get_logs_by_datetime(
|
|||||||
|
|
||||||
/// Get the stdout for a profile by profile id and datetime string
|
/// Get the stdout for a profile by profile id and datetime string
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub async fn logs_get_stdout_by_datetime(
|
pub async fn logs_get_output_by_datetime(
|
||||||
profile_uuid: Uuid,
|
profile_uuid: Uuid,
|
||||||
datetime_string: String,
|
datetime_string: String,
|
||||||
) -> Result<String> {
|
) -> Result<String> {
|
||||||
Ok(logs::get_stdout_by_datetime(profile_uuid, &datetime_string).await?)
|
Ok(logs::get_output_by_datetime(profile_uuid, &datetime_string).await?)
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the stderr for a profile by profile id and datetime string
|
|
||||||
#[tauri::command]
|
|
||||||
pub async fn logs_get_stderr_by_datetime(
|
|
||||||
profile_uuid: Uuid,
|
|
||||||
datetime_string: String,
|
|
||||||
) -> Result<String> {
|
|
||||||
Ok(logs::get_stderr_by_datetime(profile_uuid, &datetime_string).await?)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Delete all logs for a profile by profile id
|
/// Delete all logs for a profile by profile id
|
||||||
|
|||||||
@@ -52,14 +52,8 @@ pub async fn process_get_all_running_profiles() -> Result<Vec<Profile>> {
|
|||||||
|
|
||||||
// Gets process stderr by process UUID
|
// Gets process stderr by process UUID
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub async fn process_get_stderr_by_uuid(uuid: Uuid) -> Result<String> {
|
pub async fn process_get_output_by_uuid(uuid: Uuid) -> Result<String> {
|
||||||
Ok(process::get_stderr_by_uuid(&uuid).await?)
|
Ok(process::get_output_by_uuid(&uuid).await?)
|
||||||
}
|
|
||||||
|
|
||||||
// Gets process stdout by process UUID
|
|
||||||
#[tauri::command]
|
|
||||||
pub async fn process_get_stdout_by_uuid(uuid: Uuid) -> Result<String> {
|
|
||||||
Ok(process::get_stdout_by_uuid(&uuid).await?)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Kill a process by process UUID
|
// Kill a process by process UUID
|
||||||
|
|||||||
@@ -233,6 +233,7 @@ pub async fn profile_edit(
|
|||||||
async { Ok(()) }
|
async { Ok(()) }
|
||||||
})
|
})
|
||||||
.await?;
|
.await?;
|
||||||
|
State::sync().await?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,15 @@ async fn initialize_state(app: tauri::AppHandle) -> api::Result<()> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tauri::command]
|
||||||
|
fn is_dev() -> bool {
|
||||||
|
if cfg!(debug_assertions) {
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
use tracing_subscriber::prelude::*;
|
use tracing_subscriber::prelude::*;
|
||||||
|
|
||||||
#[derive(Clone, serde::Serialize)]
|
#[derive(Clone, serde::Serialize)]
|
||||||
@@ -30,6 +39,9 @@ struct Payload {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
let client = sentry::init("https://19a14416dafc4b4a858fa1a38db3b704@o485889.ingest.sentry.io/4505349067374592");
|
||||||
|
|
||||||
|
let _guard = sentry_rust_minidump::init(&client);
|
||||||
/*
|
/*
|
||||||
tracing is set basd on the environment variable RUST_LOG=xxx, depending on the amount of logs to show
|
tracing is set basd on the environment variable RUST_LOG=xxx, depending on the amount of logs to show
|
||||||
ERROR > WARN > INFO > DEBUG > TRACE
|
ERROR > WARN > INFO > DEBUG > TRACE
|
||||||
@@ -83,6 +95,7 @@ fn main() {
|
|||||||
|
|
||||||
builder = builder.invoke_handler(tauri::generate_handler![
|
builder = builder.invoke_handler(tauri::generate_handler![
|
||||||
initialize_state,
|
initialize_state,
|
||||||
|
is_dev,
|
||||||
api::progress_bars_list,
|
api::progress_bars_list,
|
||||||
api::profile_create::profile_create_empty,
|
api::profile_create::profile_create_empty,
|
||||||
api::profile_create::profile_create,
|
api::profile_create::profile_create,
|
||||||
@@ -138,8 +151,7 @@ fn main() {
|
|||||||
api::process::process_get_all_running_profiles,
|
api::process::process_get_all_running_profiles,
|
||||||
api::process::process_get_exit_status_by_uuid,
|
api::process::process_get_exit_status_by_uuid,
|
||||||
api::process::process_has_finished_by_uuid,
|
api::process::process_has_finished_by_uuid,
|
||||||
api::process::process_get_stderr_by_uuid,
|
api::process::process_get_output_by_uuid,
|
||||||
api::process::process_get_stdout_by_uuid,
|
|
||||||
api::process::process_kill_by_uuid,
|
api::process::process_kill_by_uuid,
|
||||||
api::process::process_wait_for_by_uuid,
|
api::process::process_wait_for_by_uuid,
|
||||||
api::metadata::metadata_get_game_versions,
|
api::metadata::metadata_get_game_versions,
|
||||||
@@ -148,8 +160,7 @@ fn main() {
|
|||||||
api::metadata::metadata_get_quilt_versions,
|
api::metadata::metadata_get_quilt_versions,
|
||||||
api::logs::logs_get_logs,
|
api::logs::logs_get_logs,
|
||||||
api::logs::logs_get_logs_by_datetime,
|
api::logs::logs_get_logs_by_datetime,
|
||||||
api::logs::logs_get_stdout_by_datetime,
|
api::logs::logs_get_output_by_datetime,
|
||||||
api::logs::logs_get_stderr_by_datetime,
|
|
||||||
api::logs::logs_delete_logs,
|
api::logs::logs_delete_logs,
|
||||||
api::logs::logs_delete_logs_by_datetime,
|
api::logs::logs_delete_logs_by_datetime,
|
||||||
api::utils::show_in_folder,
|
api::utils::show_in_folder,
|
||||||
@@ -159,4 +170,9 @@ fn main() {
|
|||||||
builder
|
builder
|
||||||
.run(tauri::generate_context!())
|
.run(tauri::generate_context!())
|
||||||
.expect("error while running tauri application");
|
.expect("error while running tauri application");
|
||||||
|
|
||||||
|
#[allow(deref_nullptr)]
|
||||||
|
unsafe {
|
||||||
|
*std::ptr::null_mut() = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { onMounted, ref, watch } from 'vue'
|
import { ref, watch } from 'vue'
|
||||||
import { RouterView, RouterLink } from 'vue-router'
|
import { RouterView, RouterLink, useRouter } from 'vue-router'
|
||||||
import {
|
import {
|
||||||
HomeIcon,
|
HomeIcon,
|
||||||
SearchIcon,
|
SearchIcon,
|
||||||
@@ -10,7 +10,7 @@ import {
|
|||||||
Button,
|
Button,
|
||||||
Notifications,
|
Notifications,
|
||||||
} from 'omorphia'
|
} from 'omorphia'
|
||||||
import { handleError, useLoading, useTheming } from '@/store/state'
|
import { useLoading, useTheming } from '@/store/state'
|
||||||
import AccountsCard from '@/components/ui/AccountsCard.vue'
|
import AccountsCard from '@/components/ui/AccountsCard.vue'
|
||||||
import InstanceCreationModal from '@/components/ui/InstanceCreationModal.vue'
|
import InstanceCreationModal from '@/components/ui/InstanceCreationModal.vue'
|
||||||
import { get } from '@/helpers/settings'
|
import { get } from '@/helpers/settings'
|
||||||
@@ -20,31 +20,47 @@ import SplashScreen from '@/components/ui/SplashScreen.vue'
|
|||||||
import ModrinthLoadingIndicator from '@/components/modrinth-loading-indicator'
|
import ModrinthLoadingIndicator from '@/components/modrinth-loading-indicator'
|
||||||
import { useNotifications } from '@/store/notifications.js'
|
import { useNotifications } from '@/store/notifications.js'
|
||||||
import { warning_listener } from '@/helpers/events.js'
|
import { warning_listener } from '@/helpers/events.js'
|
||||||
|
import { isDev } from '@/helpers/utils.js'
|
||||||
|
import mixpanel from 'mixpanel-browser'
|
||||||
|
|
||||||
const themeStore = useTheming()
|
const themeStore = useTheming()
|
||||||
|
|
||||||
const isLoading = ref(true)
|
const isLoading = ref(true)
|
||||||
onMounted(async () => {
|
|
||||||
const { settings, collapsed_navigation } = await get().catch(handleError)
|
|
||||||
themeStore.setThemeState(settings)
|
|
||||||
themeStore.collapsedNavigation = collapsed_navigation
|
|
||||||
|
|
||||||
await warning_listener((e) =>
|
|
||||||
notificationsWrapper.value.addNotification({
|
|
||||||
title: 'Warning',
|
|
||||||
text: e.message,
|
|
||||||
type: 'warn',
|
|
||||||
})
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
defineExpose({
|
defineExpose({
|
||||||
initialize: async () => {
|
initialize: async () => {
|
||||||
isLoading.value = false
|
isLoading.value = false
|
||||||
const { theme } = await get()
|
const { theme, opt_out_analytics, collapsed_navigation, advanced_rendering } = await get()
|
||||||
|
const dev = await isDev()
|
||||||
|
|
||||||
themeStore.setThemeState(theme)
|
themeStore.setThemeState(theme)
|
||||||
|
themeStore.collapsedNavigation = collapsed_navigation
|
||||||
|
themeStore.advancedRendering = advanced_rendering
|
||||||
|
|
||||||
|
mixpanel.init('014c7d6a336d0efaefe3aca91063748d', { debug: dev, persistence: 'localStorage' })
|
||||||
|
if (opt_out_analytics) {
|
||||||
|
mixpanel.opt_out_tracking()
|
||||||
|
}
|
||||||
|
mixpanel.track('Launched')
|
||||||
|
|
||||||
|
if (!dev) document.addEventListener('contextmenu', (event) => event.preventDefault())
|
||||||
|
|
||||||
|
await warning_listener((e) =>
|
||||||
|
notificationsWrapper.value.addNotification({
|
||||||
|
title: 'Warning',
|
||||||
|
text: e.message,
|
||||||
|
type: 'warn',
|
||||||
|
})
|
||||||
|
)
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const router = useRouter()
|
||||||
|
router.afterEach((to, from, failure) => {
|
||||||
|
if (mixpanel.__loaded) {
|
||||||
|
mixpanel.track('PageView', { path: to.path, fromPath: from.path, failed: failure })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
const loading = useLoading()
|
const loading = useLoading()
|
||||||
|
|
||||||
const notifications = useNotifications()
|
const notifications = useNotifications()
|
||||||
@@ -54,8 +70,6 @@ watch(notificationsWrapper, () => {
|
|||||||
notifications.setNotifs(notificationsWrapper.value)
|
notifications.setNotifs(notificationsWrapper.value)
|
||||||
})
|
})
|
||||||
|
|
||||||
document.addEventListener('contextmenu', (event) => event.preventDefault())
|
|
||||||
|
|
||||||
document.querySelector('body').addEventListener('click', function (e) {
|
document.querySelector('body').addEventListener('click', function (e) {
|
||||||
let target = e.target
|
let target = e.target
|
||||||
while (target != null) {
|
while (target != null) {
|
||||||
|
|||||||
@@ -12,10 +12,16 @@ import {
|
|||||||
Card,
|
Card,
|
||||||
DropdownSelect,
|
DropdownSelect,
|
||||||
SearchIcon,
|
SearchIcon,
|
||||||
|
XIcon,
|
||||||
|
Button,
|
||||||
formatCategoryHeader,
|
formatCategoryHeader,
|
||||||
|
ModalConfirm,
|
||||||
} from 'omorphia'
|
} from 'omorphia'
|
||||||
import ContextMenu from '@/components/ui/ContextMenu.vue'
|
import ContextMenu from '@/components/ui/ContextMenu.vue'
|
||||||
import dayjs from 'dayjs'
|
import dayjs from 'dayjs'
|
||||||
|
import { useTheming } from '@/store/theme.js'
|
||||||
|
import { remove } from '@/helpers/profile.js'
|
||||||
|
import { handleError } from '@/store/notifications.js'
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
instances: {
|
instances: {
|
||||||
@@ -32,6 +38,19 @@ const props = defineProps({
|
|||||||
const instanceOptions = ref(null)
|
const instanceOptions = ref(null)
|
||||||
const instanceComponents = ref(null)
|
const instanceComponents = ref(null)
|
||||||
|
|
||||||
|
const themeStore = useTheming()
|
||||||
|
const currentDeleteInstance = ref(null)
|
||||||
|
const confirmModal = ref(null)
|
||||||
|
|
||||||
|
async function deleteProfile() {
|
||||||
|
if (currentDeleteInstance.value) {
|
||||||
|
instanceComponents.value = instanceComponents.value.filter(
|
||||||
|
(x) => x.instance.path !== currentDeleteInstance.value
|
||||||
|
)
|
||||||
|
await remove(currentDeleteInstance.value).catch(handleError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const handleRightClick = (event, item) => {
|
const handleRightClick = (event, item) => {
|
||||||
const baseOptions = [
|
const baseOptions = [
|
||||||
{ name: 'add_content' },
|
{ name: 'add_content' },
|
||||||
@@ -68,13 +87,12 @@ const handleRightClick = (event, item) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const handleOptionsClick = async (args) => {
|
const handleOptionsClick = async (args) => {
|
||||||
console.log(args)
|
|
||||||
switch (args.option) {
|
switch (args.option) {
|
||||||
case 'play':
|
case 'play':
|
||||||
args.item.play()
|
args.item.play(null, 'InstanceGridContextMenu')
|
||||||
break
|
break
|
||||||
case 'stop':
|
case 'stop':
|
||||||
args.item.stop()
|
args.item.stop(null, 'InstanceGridContextMenu')
|
||||||
break
|
break
|
||||||
case 'add_content':
|
case 'add_content':
|
||||||
await args.item.addContent()
|
await args.item.addContent()
|
||||||
@@ -82,15 +100,16 @@ const handleOptionsClick = async (args) => {
|
|||||||
case 'edit':
|
case 'edit':
|
||||||
await args.item.seeInstance()
|
await args.item.seeInstance()
|
||||||
break
|
break
|
||||||
case 'delete':
|
|
||||||
await args.item.deleteInstance()
|
|
||||||
break
|
|
||||||
case 'open':
|
case 'open':
|
||||||
await args.item.openFolder()
|
await args.item.openFolder()
|
||||||
break
|
break
|
||||||
case 'copy':
|
case 'copy':
|
||||||
await navigator.clipboard.writeText(args.item.instance.path)
|
await navigator.clipboard.writeText(args.item.instance.path)
|
||||||
break
|
break
|
||||||
|
case 'delete':
|
||||||
|
currentDeleteInstance.value = args.item.instance.path
|
||||||
|
confirmModal.value.show()
|
||||||
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -185,6 +204,15 @@ const filteredResults = computed(() => {
|
|||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
|
<ModalConfirm
|
||||||
|
ref="confirmModal"
|
||||||
|
title="Are you sure you want to delete this instance?"
|
||||||
|
description="If you proceed, all data for your instance will be removed. You will not be able to recover it."
|
||||||
|
:has-to-type="false"
|
||||||
|
proceed-label="Delete"
|
||||||
|
:noblur="!themeStore.advancedRendering"
|
||||||
|
@proceed="deleteProfile"
|
||||||
|
/>
|
||||||
<Card class="header">
|
<Card class="header">
|
||||||
<div class="iconified-input">
|
<div class="iconified-input">
|
||||||
<SearchIcon />
|
<SearchIcon />
|
||||||
@@ -222,7 +250,7 @@ const filteredResults = computed(() => {
|
|||||||
</div>
|
</div>
|
||||||
</Card>
|
</Card>
|
||||||
<div
|
<div
|
||||||
v-for="(instanceSection, index) in Array.from(filteredResults, ([key, value]) => ({
|
v-for="instanceSection in Array.from(filteredResults, ([key, value]) => ({
|
||||||
key,
|
key,
|
||||||
value,
|
value,
|
||||||
}))"
|
}))"
|
||||||
@@ -235,7 +263,7 @@ const filteredResults = computed(() => {
|
|||||||
</div>
|
</div>
|
||||||
<section class="instances">
|
<section class="instances">
|
||||||
<Instance
|
<Instance
|
||||||
v-for="instance in instanceSection.value"
|
v-for="(instance, index) in instanceSection.value"
|
||||||
ref="instanceComponents"
|
ref="instanceComponents"
|
||||||
:key="instance.id"
|
:key="instance.id"
|
||||||
:instance="instance"
|
:instance="instance"
|
||||||
@@ -298,6 +326,10 @@ const filteredResults = computed(() => {
|
|||||||
|
|
||||||
.iconified-input {
|
.iconified-input {
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
|
|
||||||
|
input {
|
||||||
|
min-width: 100%;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.sort-dropdown {
|
.sort-dropdown {
|
||||||
|
|||||||
@@ -12,10 +12,14 @@ import {
|
|||||||
StopCircleIcon,
|
StopCircleIcon,
|
||||||
ExternalIcon,
|
ExternalIcon,
|
||||||
EyeIcon,
|
EyeIcon,
|
||||||
|
ModalConfirm,
|
||||||
} from 'omorphia'
|
} from 'omorphia'
|
||||||
import Instance from '@/components/ui/Instance.vue'
|
import Instance from '@/components/ui/Instance.vue'
|
||||||
import { onMounted, onUnmounted, ref } from 'vue'
|
import { onMounted, onUnmounted, ref } from 'vue'
|
||||||
import ContextMenu from '@/components/ui/ContextMenu.vue'
|
import ContextMenu from '@/components/ui/ContextMenu.vue'
|
||||||
|
import { remove } from '@/helpers/profile.js'
|
||||||
|
import { handleError } from '@/store/notifications.js'
|
||||||
|
import { useTheming } from '@/store/state.js'
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
instances: {
|
instances: {
|
||||||
@@ -36,6 +40,19 @@ const modsRow = ref(null)
|
|||||||
const instanceOptions = ref(null)
|
const instanceOptions = ref(null)
|
||||||
const instanceComponents = ref(null)
|
const instanceComponents = ref(null)
|
||||||
|
|
||||||
|
const themeStore = useTheming()
|
||||||
|
const currentDeleteInstance = ref(null)
|
||||||
|
const confirmModal = ref(null)
|
||||||
|
|
||||||
|
async function deleteProfile() {
|
||||||
|
if (currentDeleteInstance.value) {
|
||||||
|
instanceComponents.value = instanceComponents.value.filter(
|
||||||
|
(x) => x.instance.path !== currentDeleteInstance.value
|
||||||
|
)
|
||||||
|
await remove(currentDeleteInstance.value).catch(handleError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const handlePaginationDisplay = () => {
|
const handlePaginationDisplay = () => {
|
||||||
for (let i = 0; i < props.instances.length; i++) {
|
for (let i = 0; i < props.instances.length; i++) {
|
||||||
let parentsRow = modsRow.value[i]
|
let parentsRow = modsRow.value[i]
|
||||||
@@ -114,10 +131,10 @@ const handleInstanceRightClick = (event, passedInstance) => {
|
|||||||
const handleOptionsClick = async (args) => {
|
const handleOptionsClick = async (args) => {
|
||||||
switch (args.option) {
|
switch (args.option) {
|
||||||
case 'play':
|
case 'play':
|
||||||
await args.item.play()
|
await args.item.play(null, 'InstanceRowContextMenu')
|
||||||
break
|
break
|
||||||
case 'stop':
|
case 'stop':
|
||||||
await args.item.stop()
|
await args.item.stop(null, 'InstanceRowContextMenu')
|
||||||
break
|
break
|
||||||
case 'add_content':
|
case 'add_content':
|
||||||
await args.item.addContent()
|
await args.item.addContent()
|
||||||
@@ -126,7 +143,8 @@ const handleOptionsClick = async (args) => {
|
|||||||
await args.item.seeInstance()
|
await args.item.seeInstance()
|
||||||
break
|
break
|
||||||
case 'delete':
|
case 'delete':
|
||||||
await args.item.deleteInstance()
|
currentDeleteInstance.value = args.item.instance.path
|
||||||
|
confirmModal.value.show()
|
||||||
break
|
break
|
||||||
case 'open_folder':
|
case 'open_folder':
|
||||||
await args.item.openFolder()
|
await args.item.openFolder()
|
||||||
@@ -165,6 +183,15 @@ const getInstanceIndex = (rowIndex, index) => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
<ModalConfirm
|
||||||
|
ref="confirmModal"
|
||||||
|
title="Are you sure you want to delete this instance?"
|
||||||
|
description="If you proceed, all data for your instance will be removed. You will not be able to recover it."
|
||||||
|
:has-to-type="false"
|
||||||
|
proceed-label="Delete"
|
||||||
|
:noblur="!themeStore.advancedRendering"
|
||||||
|
@proceed="deleteProfile"
|
||||||
|
/>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<div v-for="(row, rowIndex) in instances" :key="row.label" class="row">
|
<div v-for="(row, rowIndex) in instances" :key="row.label" class="row">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
|
|||||||
@@ -65,6 +65,7 @@ import {
|
|||||||
import { get, set } from '@/helpers/settings'
|
import { get, set } from '@/helpers/settings'
|
||||||
import { WebviewWindow } from '@tauri-apps/api/window'
|
import { WebviewWindow } from '@tauri-apps/api/window'
|
||||||
import { handleError } from '@/store/state.js'
|
import { handleError } from '@/store/state.js'
|
||||||
|
import mixpanel from 'mixpanel-browser'
|
||||||
|
|
||||||
defineProps({
|
defineProps({
|
||||||
expanded: {
|
expanded: {
|
||||||
@@ -131,6 +132,7 @@ const login = async () => {
|
|||||||
await setAccount(loggedIn)
|
await setAccount(loggedIn)
|
||||||
await refreshValues()
|
await refreshValues()
|
||||||
await window.close()
|
await window.close()
|
||||||
|
mixpanel.track('AccountLogIn')
|
||||||
}
|
}
|
||||||
|
|
||||||
const logout = async (id) => {
|
const logout = async (id) => {
|
||||||
@@ -140,6 +142,7 @@ const logout = async (id) => {
|
|||||||
await setAccount(accounts.value[0])
|
await setAccount(accounts.value[0])
|
||||||
await refreshValues()
|
await refreshValues()
|
||||||
}
|
}
|
||||||
|
mixpanel.track('AccountLogOut')
|
||||||
}
|
}
|
||||||
|
|
||||||
const toggle = () => {
|
const toggle = () => {
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
<template>
|
<template>
|
||||||
<Modal ref="incompatibleModal" header="Incompatibility warning">
|
<Modal
|
||||||
|
ref="incompatibleModal"
|
||||||
|
header="Incompatibility warning"
|
||||||
|
:noblur="!themeStore.advancedRendering"
|
||||||
|
>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<p>
|
<p>
|
||||||
This {{ versions?.length > 0 ? 'project' : 'version' }} is not compatible with the instance
|
This {{ versions?.length > 0 ? 'project' : 'version' }} is not compatible with the instance
|
||||||
@@ -54,9 +58,14 @@
|
|||||||
import { Button, Modal, XIcon, DownloadIcon, DropdownSelect, formatCategory } from 'omorphia'
|
import { Button, Modal, XIcon, DownloadIcon, DropdownSelect, formatCategory } from 'omorphia'
|
||||||
import { add_project_from_version as installMod } from '@/helpers/profile'
|
import { add_project_from_version as installMod } from '@/helpers/profile'
|
||||||
import { defineExpose, ref } from 'vue'
|
import { defineExpose, ref } from 'vue'
|
||||||
import { handleError } from '@/store/state.js'
|
import { handleError, useTheming } from '@/store/state.js'
|
||||||
|
import mixpanel from 'mixpanel-browser'
|
||||||
|
|
||||||
|
const themeStore = useTheming()
|
||||||
|
|
||||||
const instance = ref(null)
|
const instance = ref(null)
|
||||||
|
const project = ref(null)
|
||||||
|
const projectType = ref(null)
|
||||||
const projectTitle = ref(null)
|
const projectTitle = ref(null)
|
||||||
const versions = ref(null)
|
const versions = ref(null)
|
||||||
const selectedVersion = ref(null)
|
const selectedVersion = ref(null)
|
||||||
@@ -66,13 +75,26 @@ const installing = ref(false)
|
|||||||
let markInstalled = () => {}
|
let markInstalled = () => {}
|
||||||
|
|
||||||
defineExpose({
|
defineExpose({
|
||||||
show: (instanceVal, projectTitleVal, selectedVersions, extMarkInstalled) => {
|
show: (
|
||||||
|
instanceVal,
|
||||||
|
projectTitleVal,
|
||||||
|
selectedVersions,
|
||||||
|
extMarkInstalled,
|
||||||
|
projectIdVal,
|
||||||
|
projectTypeVal
|
||||||
|
) => {
|
||||||
instance.value = instanceVal
|
instance.value = instanceVal
|
||||||
projectTitle.value = projectTitleVal
|
projectTitle.value = projectTitleVal
|
||||||
versions.value = selectedVersions
|
versions.value = selectedVersions
|
||||||
selectedVersion.value = selectedVersions[0]
|
selectedVersion.value = selectedVersions[0]
|
||||||
|
|
||||||
|
project.value = projectIdVal
|
||||||
|
projectType.value = projectTypeVal
|
||||||
|
|
||||||
incompatibleModal.value.show()
|
incompatibleModal.value.show()
|
||||||
markInstalled = extMarkInstalled
|
markInstalled = extMarkInstalled
|
||||||
|
|
||||||
|
mixpanel.track('ProjectInstallStart', { source: 'ProjectIncompatibilityWarningModal' })
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -82,6 +104,16 @@ const install = async () => {
|
|||||||
installing.value = false
|
installing.value = false
|
||||||
markInstalled()
|
markInstalled()
|
||||||
incompatibleModal.value.hide()
|
incompatibleModal.value.hide()
|
||||||
|
|
||||||
|
mixpanel.track('ProjectInstall', {
|
||||||
|
loader: instance.value.metadata.loader,
|
||||||
|
game_version: instance.value.metadata.game_version,
|
||||||
|
id: project.value,
|
||||||
|
version_id: selectedVersion.value.id,
|
||||||
|
project_type: projectType.value,
|
||||||
|
title: projectTitle.value,
|
||||||
|
source: 'ProjectIncompatibilityWarningModal',
|
||||||
|
})
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,10 @@
|
|||||||
import { Button, Modal, XIcon, DownloadIcon } from 'omorphia'
|
import { Button, Modal, XIcon, DownloadIcon } from 'omorphia'
|
||||||
import { install as pack_install } from '@/helpers/pack'
|
import { install as pack_install } from '@/helpers/pack'
|
||||||
import { ref } from 'vue'
|
import { ref } from 'vue'
|
||||||
|
import mixpanel from 'mixpanel-browser'
|
||||||
|
import { useTheming } from '@/store/theme.js'
|
||||||
|
|
||||||
|
const themeStore = useTheming()
|
||||||
|
|
||||||
const version = ref('')
|
const version = ref('')
|
||||||
const title = ref('')
|
const title = ref('')
|
||||||
@@ -11,12 +15,14 @@ const confirmModal = ref(null)
|
|||||||
const installing = ref(false)
|
const installing = ref(false)
|
||||||
|
|
||||||
defineExpose({
|
defineExpose({
|
||||||
show: (id, projectId, projectTitle, projectIcon) => {
|
show: (id, projectIdVal, projectTitle, projectIcon) => {
|
||||||
version.value = id
|
version.value = id
|
||||||
projectId.value = projectId
|
projectId.value = projectIdVal
|
||||||
title.value = projectTitle
|
title.value = projectTitle
|
||||||
icon.value = projectIcon
|
icon.value = projectIcon
|
||||||
confirmModal.value.show()
|
confirmModal.value.show()
|
||||||
|
|
||||||
|
mixpanel.track('PackInstallStart')
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -24,11 +30,18 @@ async function install() {
|
|||||||
installing.value = true
|
installing.value = true
|
||||||
await pack_install(projectId.value, version.value, title.value, icon.value ? icon.value : null)
|
await pack_install(projectId.value, version.value, title.value, icon.value ? icon.value : null)
|
||||||
confirmModal.value.hide()
|
confirmModal.value.hide()
|
||||||
|
|
||||||
|
mixpanel.track('PackInstall', {
|
||||||
|
id: projectId.value,
|
||||||
|
version_id: version.value,
|
||||||
|
title: title.value,
|
||||||
|
source: 'ConfirmModal',
|
||||||
|
})
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<Modal ref="confirmModal" header="Are you sure?">
|
<Modal ref="confirmModal" header="Are you sure?" :noblur="!themeStore.advancedRendering">
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<p>You already have this modpack installed. Are you sure you want to install it again?</p>
|
<p>You already have this modpack installed. Are you sure you want to install it again?</p>
|
||||||
<div class="input-group push-right">
|
<div class="input-group push-right">
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { Card, DownloadIcon, StopCircleIcon, Avatar, AnimatedLogo, PlayIcon } fr
|
|||||||
import { convertFileSrc } from '@tauri-apps/api/tauri'
|
import { convertFileSrc } from '@tauri-apps/api/tauri'
|
||||||
import InstallConfirmModal from '@/components/ui/InstallConfirmModal.vue'
|
import InstallConfirmModal from '@/components/ui/InstallConfirmModal.vue'
|
||||||
import { install as pack_install } from '@/helpers/pack'
|
import { install as pack_install } from '@/helpers/pack'
|
||||||
import { list, remove, run } from '@/helpers/profile'
|
import { list, run } from '@/helpers/profile'
|
||||||
import {
|
import {
|
||||||
get_all_running_profile_paths,
|
get_all_running_profile_paths,
|
||||||
get_uuids_by_profile_path,
|
get_uuids_by_profile_path,
|
||||||
@@ -16,6 +16,7 @@ import { useFetch } from '@/helpers/fetch.js'
|
|||||||
import { handleError } from '@/store/state.js'
|
import { handleError } from '@/store/state.js'
|
||||||
import { showInFolder } from '@/helpers/utils.js'
|
import { showInFolder } from '@/helpers/utils.js'
|
||||||
import InstanceInstallModal from '@/components/ui/InstanceInstallModal.vue'
|
import InstanceInstallModal from '@/components/ui/InstanceInstallModal.vue'
|
||||||
|
import mixpanel from 'mixpanel-browser'
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
instance: {
|
instance: {
|
||||||
@@ -91,6 +92,13 @@ const install = async (e) => {
|
|||||||
props.instance.icon_url
|
props.instance.icon_url
|
||||||
).catch(handleError)
|
).catch(handleError)
|
||||||
modLoading.value = false
|
modLoading.value = false
|
||||||
|
|
||||||
|
mixpanel.track('PackInstall', {
|
||||||
|
id: props.instance.project_id,
|
||||||
|
version_id: versions[0].id,
|
||||||
|
title: props.instance.title,
|
||||||
|
source: 'InstanceCard',
|
||||||
|
})
|
||||||
} else
|
} else
|
||||||
confirmModal.value.show(
|
confirmModal.value.show(
|
||||||
props.instance.project_id,
|
props.instance.project_id,
|
||||||
@@ -99,21 +107,32 @@ const install = async (e) => {
|
|||||||
props.instance.icon_url
|
props.instance.icon_url
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
modInstallModal.value.show(props.instance.project_id, versions)
|
modInstallModal.value.show(
|
||||||
|
props.instance.project_id,
|
||||||
|
versions,
|
||||||
|
props.instance.title,
|
||||||
|
props.instance.project_type
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
modLoading.value = false
|
modLoading.value = false
|
||||||
}
|
}
|
||||||
|
|
||||||
const play = async (e) => {
|
const play = async (e, context) => {
|
||||||
e?.stopPropagation()
|
e?.stopPropagation()
|
||||||
modLoading.value = true
|
modLoading.value = true
|
||||||
uuid.value = await run(props.instance.path).catch(handleError)
|
uuid.value = await run(props.instance.path).catch(handleError)
|
||||||
modLoading.value = false
|
modLoading.value = false
|
||||||
playing.value = true
|
playing.value = true
|
||||||
|
|
||||||
|
mixpanel.track('InstancePlay', {
|
||||||
|
loader: props.instance.metadata.loader,
|
||||||
|
game_version: props.instance.metadata.game_version,
|
||||||
|
source: context,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const stop = async (e) => {
|
const stop = async (e, context) => {
|
||||||
e?.stopPropagation()
|
e?.stopPropagation()
|
||||||
playing.value = false
|
playing.value = false
|
||||||
|
|
||||||
@@ -126,11 +145,13 @@ const stop = async (e) => {
|
|||||||
uuids.forEach(async (u) => await kill_by_uuid(u).catch(handleError))
|
uuids.forEach(async (u) => await kill_by_uuid(u).catch(handleError))
|
||||||
} else await kill_by_uuid(uuid.value).catch(handleError) // If we still have the uuid, just kill it
|
} else await kill_by_uuid(uuid.value).catch(handleError) // If we still have the uuid, just kill it
|
||||||
|
|
||||||
uuid.value = null
|
mixpanel.track('InstanceStop', {
|
||||||
}
|
loader: props.instance.metadata.loader,
|
||||||
|
game_version: props.instance.metadata.game_version,
|
||||||
|
source: context,
|
||||||
|
})
|
||||||
|
|
||||||
const deleteInstance = async () => {
|
uuid.value = null
|
||||||
await remove(props.instance.path).catch(handleError)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const openFolder = async () => {
|
const openFolder = async () => {
|
||||||
@@ -151,7 +172,6 @@ defineExpose({
|
|||||||
stop,
|
stop,
|
||||||
seeInstance,
|
seeInstance,
|
||||||
openFolder,
|
openFolder,
|
||||||
deleteInstance,
|
|
||||||
addContent,
|
addContent,
|
||||||
instance: props.instance,
|
instance: props.instance,
|
||||||
})
|
})
|
||||||
@@ -190,7 +210,7 @@ onUnmounted(() => unlisten())
|
|||||||
<div
|
<div
|
||||||
v-if="props.instance.metadata && playing === false && modLoading === false"
|
v-if="props.instance.metadata && playing === false && modLoading === false"
|
||||||
class="install cta button-base"
|
class="install cta button-base"
|
||||||
@click="play"
|
@click="(e) => play(e, 'InstanceCard')"
|
||||||
>
|
>
|
||||||
<PlayIcon />
|
<PlayIcon />
|
||||||
</div>
|
</div>
|
||||||
@@ -200,7 +220,7 @@ onUnmounted(() => unlisten())
|
|||||||
<div
|
<div
|
||||||
v-else-if="playing === true"
|
v-else-if="playing === true"
|
||||||
class="stop cta button-base"
|
class="stop cta button-base"
|
||||||
@click="stop"
|
@click="(e) => stop(e, 'InstanceCard')"
|
||||||
@mousehover="checkProcess"
|
@mousehover="checkProcess"
|
||||||
>
|
>
|
||||||
<StopCircleIcon />
|
<StopCircleIcon />
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<Modal ref="modal" header="Create instance">
|
<Modal ref="modal" header="Create instance" :noblur="!themeStore.advancedRendering">
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<Chips v-model="creationType" :items="['custom', 'from file']" />
|
<Chips v-model="creationType" :items="['custom', 'from file']" />
|
||||||
</div>
|
</div>
|
||||||
@@ -116,9 +116,13 @@ import {
|
|||||||
} from '@/helpers/metadata'
|
} from '@/helpers/metadata'
|
||||||
import { handleError } from '@/store/notifications.js'
|
import { handleError } from '@/store/notifications.js'
|
||||||
import Multiselect from 'vue-multiselect'
|
import Multiselect from 'vue-multiselect'
|
||||||
|
import mixpanel from 'mixpanel-browser'
|
||||||
|
import { useTheming } from '@/store/state.js'
|
||||||
import { listen } from '@tauri-apps/api/event'
|
import { listen } from '@tauri-apps/api/event'
|
||||||
import { install_from_file } from '@/helpers/pack.js'
|
import { install_from_file } from '@/helpers/pack.js'
|
||||||
|
|
||||||
|
const themeStore = useTheming()
|
||||||
|
|
||||||
const profile_name = ref('')
|
const profile_name = ref('')
|
||||||
const game_version = ref('')
|
const game_version = ref('')
|
||||||
const loader = ref('vanilla')
|
const loader = ref('vanilla')
|
||||||
@@ -144,6 +148,8 @@ defineExpose({
|
|||||||
icon.value = null
|
icon.value = null
|
||||||
display_icon.value = null
|
display_icon.value = null
|
||||||
modal.value.show()
|
modal.value.show()
|
||||||
|
|
||||||
|
mixpanel.track('InstanceCreateStart', { source: 'CreationModal' })
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -195,6 +201,7 @@ const create_instance = async () => {
|
|||||||
creating.value = true
|
creating.value = true
|
||||||
const loader_version_value =
|
const loader_version_value =
|
||||||
loader_version.value === 'other' ? specified_loader_version.value : loader_version.value
|
loader_version.value === 'other' ? specified_loader_version.value : loader_version.value
|
||||||
|
const loaderVersion = loader.value === 'vanilla' ? null : loader_version_value ?? 'stable'
|
||||||
|
|
||||||
modal.value.hide()
|
modal.value.hide()
|
||||||
creating.value = false
|
creating.value = false
|
||||||
@@ -206,6 +213,15 @@ const create_instance = async () => {
|
|||||||
loader.value === 'vanilla' ? null : loader_version_value ?? 'stable',
|
loader.value === 'vanilla' ? null : loader_version_value ?? 'stable',
|
||||||
icon.value
|
icon.value
|
||||||
).catch(handleError)
|
).catch(handleError)
|
||||||
|
|
||||||
|
mixpanel.track('InstanceCreate', {
|
||||||
|
profile_name: profile_name.value,
|
||||||
|
game_version: game_version.value,
|
||||||
|
loader: loader.value,
|
||||||
|
loader_version: loaderVersion,
|
||||||
|
has_icon: !!icon.value,
|
||||||
|
source: 'CreationModal',
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const upload_icon = async () => {
|
const upload_icon = async () => {
|
||||||
@@ -253,11 +269,20 @@ const openFile = async () => {
|
|||||||
|
|
||||||
modal.value.hide()
|
modal.value.hide()
|
||||||
await install_from_file(newProject).catch(handleError)
|
await install_from_file(newProject).catch(handleError)
|
||||||
|
|
||||||
|
mixpanel.track('InstanceCreate', {
|
||||||
|
source: 'CreationModalFileOpen',
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
listen('tauri://file-drop', async (event) => {
|
listen('tauri://file-drop', async (event) => {
|
||||||
modal.value.hide()
|
modal.value.hide()
|
||||||
await install_from_file(event.payload[0]).catch(handleError)
|
if (event.payload && event.payload.length > 0 && event.payload[0].endsWith('.mrpack')) {
|
||||||
|
await install_from_file(event.payload[0]).catch(handleError)
|
||||||
|
mixpanel.track('InstanceCreate', {
|
||||||
|
source: 'CreationModalFileDrop',
|
||||||
|
})
|
||||||
|
}
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -12,16 +12,28 @@ import {
|
|||||||
CheckIcon,
|
CheckIcon,
|
||||||
} from 'omorphia'
|
} from 'omorphia'
|
||||||
import { computed, ref } from 'vue'
|
import { computed, ref } from 'vue'
|
||||||
import { add_project_from_version as installMod, check_installed, list } from '@/helpers/profile'
|
import {
|
||||||
|
add_project_from_version as installMod,
|
||||||
|
check_installed,
|
||||||
|
get,
|
||||||
|
list,
|
||||||
|
} from '@/helpers/profile'
|
||||||
import { tauri } from '@tauri-apps/api'
|
import { tauri } from '@tauri-apps/api'
|
||||||
import { open } from '@tauri-apps/api/dialog'
|
import { open } from '@tauri-apps/api/dialog'
|
||||||
import { convertFileSrc } from '@tauri-apps/api/tauri'
|
import { convertFileSrc } from '@tauri-apps/api/tauri'
|
||||||
import { create } from '@/helpers/profile'
|
import { create } from '@/helpers/profile'
|
||||||
import { installVersionDependencies } from '@/helpers/utils'
|
import { installVersionDependencies } from '@/helpers/utils'
|
||||||
import { handleError } from '@/store/notifications.js'
|
import { handleError } from '@/store/notifications.js'
|
||||||
|
import mixpanel from 'mixpanel-browser'
|
||||||
|
import { useTheming } from '@/store/theme.js'
|
||||||
|
|
||||||
|
const themeStore = useTheming()
|
||||||
|
|
||||||
const versions = ref([])
|
const versions = ref([])
|
||||||
const project = ref('')
|
const project = ref('')
|
||||||
|
const projectTitle = ref('')
|
||||||
|
const projectType = ref('')
|
||||||
|
|
||||||
const installModal = ref(null)
|
const installModal = ref(null)
|
||||||
const searchFilter = ref('')
|
const searchFilter = ref('')
|
||||||
const showCreation = ref(false)
|
const showCreation = ref(false)
|
||||||
@@ -33,13 +45,18 @@ const gameVersion = ref(null)
|
|||||||
const creatingInstance = ref(false)
|
const creatingInstance = ref(false)
|
||||||
|
|
||||||
defineExpose({
|
defineExpose({
|
||||||
show: async (projectId, selectedVersions) => {
|
show: async (projectId, selectedVersions, title, type) => {
|
||||||
project.value = projectId
|
project.value = projectId
|
||||||
versions.value = selectedVersions
|
versions.value = selectedVersions
|
||||||
|
projectTitle.value = title
|
||||||
|
projectType.value = type
|
||||||
|
|
||||||
installModal.value.show()
|
installModal.value.show()
|
||||||
searchFilter.value = ''
|
searchFilter.value = ''
|
||||||
|
|
||||||
profiles.value = await getData()
|
profiles.value = await getData()
|
||||||
|
|
||||||
|
mixpanel.track('ProjectInstallStart', { source: 'ProjectInstallModal' })
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -59,6 +76,16 @@ async function install(instance) {
|
|||||||
|
|
||||||
instance.installedMod = true
|
instance.installedMod = true
|
||||||
instance.installing = false
|
instance.installing = false
|
||||||
|
|
||||||
|
mixpanel.track('ProjectInstall', {
|
||||||
|
loader: instance.metadata.loader,
|
||||||
|
game_version: instance.metadata.game_version,
|
||||||
|
id: project.value,
|
||||||
|
version_id: version.id,
|
||||||
|
project_type: projectType.value,
|
||||||
|
title: projectTitle.value,
|
||||||
|
source: 'ProjectInstallModal',
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getData() {
|
async function getData() {
|
||||||
@@ -88,6 +115,7 @@ async function getData() {
|
|||||||
return filtered
|
return filtered
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const alreadySentCreation = ref(false)
|
||||||
const toggleCreation = () => {
|
const toggleCreation = () => {
|
||||||
showCreation.value = !showCreation.value
|
showCreation.value = !showCreation.value
|
||||||
name.value = null
|
name.value = null
|
||||||
@@ -95,6 +123,11 @@ const toggleCreation = () => {
|
|||||||
display_icon.value = null
|
display_icon.value = null
|
||||||
gameVersion.value = null
|
gameVersion.value = null
|
||||||
loader.value = null
|
loader.value = null
|
||||||
|
|
||||||
|
if (!alreadySentCreation.value) {
|
||||||
|
alreadySentCreation.value = false
|
||||||
|
mixpanel.track('InstanceCreateStart', { source: 'ProjectInstallModal' })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const upload_icon = async () => {
|
const upload_icon = async () => {
|
||||||
@@ -119,20 +152,46 @@ const reset_icon = () => {
|
|||||||
|
|
||||||
const createInstance = async () => {
|
const createInstance = async () => {
|
||||||
creatingInstance.value = true
|
creatingInstance.value = true
|
||||||
|
|
||||||
|
const loader =
|
||||||
|
versions.value[0].loaders[0] !== 'forge' ||
|
||||||
|
versions.value[0].loaders[0] !== 'fabric' ||
|
||||||
|
versions.value[0].loaders[0] !== 'quilt'
|
||||||
|
? versions.value[0].loaders[0]
|
||||||
|
: 'vanilla'
|
||||||
|
|
||||||
const id = await create(
|
const id = await create(
|
||||||
name.value,
|
name.value,
|
||||||
versions.value[0].game_versions[0],
|
versions.value[0].game_versions[0],
|
||||||
versions.value[0].loaders[0] !== 'forge' ||
|
loader,
|
||||||
versions.value[0].loaders[0] !== 'fabric' ||
|
|
||||||
versions.value[0].loaders[0] !== 'quilt'
|
|
||||||
? versions.value[0].loaders[0]
|
|
||||||
: 'vanilla',
|
|
||||||
'latest',
|
'latest',
|
||||||
icon.value
|
icon.value
|
||||||
).catch(handleError)
|
).catch(handleError)
|
||||||
|
|
||||||
await installMod(id, versions.value[0].id).catch(handleError)
|
await installMod(id, versions.value[0].id).catch(handleError)
|
||||||
|
|
||||||
|
const instance = await get(id, true)
|
||||||
|
await installVersionDependencies(instance, versions.value)
|
||||||
|
|
||||||
|
mixpanel.track('InstanceCreate', {
|
||||||
|
profile_name: name.value,
|
||||||
|
game_version: versions.value[0].game_versions[0],
|
||||||
|
loader: loader,
|
||||||
|
loader_version: 'latest',
|
||||||
|
has_icon: !!icon.value,
|
||||||
|
source: 'ProjectInstallModal',
|
||||||
|
})
|
||||||
|
|
||||||
|
mixpanel.track('ProjectInstall', {
|
||||||
|
loader: loader,
|
||||||
|
game_version: versions.value[0].game_versions[0],
|
||||||
|
id: project.value,
|
||||||
|
version_id: versions.value[0].id,
|
||||||
|
project_type: projectType.value,
|
||||||
|
title: projectTitle.value,
|
||||||
|
source: 'ProjectInstallModal',
|
||||||
|
})
|
||||||
|
|
||||||
installModal.value.hide()
|
installModal.value.hide()
|
||||||
creatingInstance.value = false
|
creatingInstance.value = false
|
||||||
}
|
}
|
||||||
@@ -143,7 +202,11 @@ const check_valid = computed(() => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<Modal ref="installModal" header="Install project to instance">
|
<Modal
|
||||||
|
ref="installModal"
|
||||||
|
header="Install project to instance"
|
||||||
|
:noblur="!themeStore.advancedRendering"
|
||||||
|
>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<input
|
<input
|
||||||
v-model="searchFilter"
|
v-model="searchFilter"
|
||||||
@@ -159,7 +222,15 @@ const check_valid = computed(() => {
|
|||||||
class="profile-button"
|
class="profile-button"
|
||||||
@click="$router.push(`/instance/${encodeURIComponent(profile.path)}`)"
|
@click="$router.push(`/instance/${encodeURIComponent(profile.path)}`)"
|
||||||
>
|
>
|
||||||
<Avatar :src="convertFileSrc(profile.metadata.icon)" class="profile-image" />
|
<Avatar
|
||||||
|
:src="
|
||||||
|
!profile.metadata.icon ||
|
||||||
|
(profile.metadata.icon && profile.metadata.icon.startsWith('http'))
|
||||||
|
? profile.metadata.icon
|
||||||
|
: convertFileSrc(profile.metadata?.icon)
|
||||||
|
"
|
||||||
|
class="profile-image"
|
||||||
|
/>
|
||||||
{{ profile.metadata.name }}
|
{{ profile.metadata.name }}
|
||||||
</Button>
|
</Button>
|
||||||
<Button :disabled="profile.installedMod || profile.installing" @click="install(profile)">
|
<Button :disabled="profile.installedMod || profile.installing" @click="install(profile)">
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<Modal ref="detectJavaModal" header="Select java version">
|
<Modal ref="detectJavaModal" header="Select java version" :noblur="!themeStore.advancedRendering">
|
||||||
<div class="auto-detect-modal">
|
<div class="auto-detect-modal">
|
||||||
<div class="table">
|
<div class="table">
|
||||||
<div class="table-row table-head">
|
<div class="table-row table-head">
|
||||||
@@ -44,6 +44,10 @@ import {
|
|||||||
get_all_jre,
|
get_all_jre,
|
||||||
} from '@/helpers/jre.js'
|
} from '@/helpers/jre.js'
|
||||||
import { handleError } from '@/store/notifications.js'
|
import { handleError } from '@/store/notifications.js'
|
||||||
|
import mixpanel from 'mixpanel-browser'
|
||||||
|
import { useTheming } from '@/store/theme.js'
|
||||||
|
|
||||||
|
const themeStore = useTheming()
|
||||||
|
|
||||||
const chosenInstallOptions = ref([])
|
const chosenInstallOptions = ref([])
|
||||||
const detectJavaModal = ref(null)
|
const detectJavaModal = ref(null)
|
||||||
@@ -75,6 +79,10 @@ const emit = defineEmits(['submit'])
|
|||||||
function setJavaInstall(javaInstall) {
|
function setJavaInstall(javaInstall) {
|
||||||
emit('submit', javaInstall)
|
emit('submit', javaInstall)
|
||||||
detectJavaModal.value.hide()
|
detectJavaModal.value.hide()
|
||||||
|
mixpanel.track('JavaAutoDetect', {
|
||||||
|
path: javaInstall.path,
|
||||||
|
version: javaInstall.version,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@@ -83,7 +91,7 @@ function setJavaInstall(javaInstall) {
|
|||||||
|
|
||||||
.table {
|
.table {
|
||||||
.table-row {
|
.table-row {
|
||||||
grid-template-columns: 1fr 4fr 1.5fr;
|
grid-template-columns: 1fr 4fr min-content;
|
||||||
}
|
}
|
||||||
|
|
||||||
span {
|
span {
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ import { get_jre } from '@/helpers/jre.js'
|
|||||||
import { ref } from 'vue'
|
import { ref } from 'vue'
|
||||||
import { open } from '@tauri-apps/api/dialog'
|
import { open } from '@tauri-apps/api/dialog'
|
||||||
import JavaDetectionModal from '@/components/ui/JavaDetectionModal.vue'
|
import JavaDetectionModal from '@/components/ui/JavaDetectionModal.vue'
|
||||||
|
import mixpanel from 'mixpanel-browser'
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
version: {
|
version: {
|
||||||
@@ -85,6 +86,11 @@ async function testJava() {
|
|||||||
testingJava.value = false
|
testingJava.value = false
|
||||||
testingJavaSuccess.value = !!result
|
testingJavaSuccess.value = !!result
|
||||||
|
|
||||||
|
mixpanel.track('JavaTest', {
|
||||||
|
path: props.modelValue ? props.modelValue.path : '',
|
||||||
|
success: !!result,
|
||||||
|
})
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
testingJavaSuccess.value = null
|
testingJavaSuccess.value = null
|
||||||
}, 2000)
|
}, 2000)
|
||||||
@@ -101,6 +107,11 @@ async function handleJavaFileInput() {
|
|||||||
version: props.version.toString(),
|
version: props.version.toString(),
|
||||||
architecture: 'x86',
|
architecture: 'x86',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mixpanel.track('JavaManualSelect', {
|
||||||
|
path: filePath,
|
||||||
|
version: props.version,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
emit('update:modelValue', result)
|
emit('update:modelValue', result)
|
||||||
|
|||||||
@@ -113,6 +113,7 @@ import { useRouter } from 'vue-router'
|
|||||||
import { progress_bars_list } from '@/helpers/state.js'
|
import { progress_bars_list } from '@/helpers/state.js'
|
||||||
import ProgressBar from '@/components/ui/ProgressBar.vue'
|
import ProgressBar from '@/components/ui/ProgressBar.vue'
|
||||||
import { handleError } from '@/store/notifications.js'
|
import { handleError } from '@/store/notifications.js'
|
||||||
|
import mixpanel from 'mixpanel-browser'
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const card = ref(null)
|
const card = ref(null)
|
||||||
@@ -140,6 +141,12 @@ const stop = async (path) => {
|
|||||||
try {
|
try {
|
||||||
const processes = await getProfileProcesses(path ?? selectedProfile.value.path)
|
const processes = await getProfileProcesses(path ?? selectedProfile.value.path)
|
||||||
await killProfile(processes[0])
|
await killProfile(processes[0])
|
||||||
|
|
||||||
|
mixpanel.track('InstanceStop', {
|
||||||
|
loader: currentProcesses.value[0].metadata.loader,
|
||||||
|
game_version: currentProcesses.value[0].metadata.game_version,
|
||||||
|
source: 'AppBar',
|
||||||
|
})
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e)
|
console.error(e)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,12 +50,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="install">
|
<div class="install">
|
||||||
<Button
|
<Button color="primary" :disabled="installed || installing" @click.stop="install()">
|
||||||
:to="`/browse/${project.slug}`"
|
|
||||||
color="primary"
|
|
||||||
:disabled="installed || installing"
|
|
||||||
@click.stop="install()"
|
|
||||||
>
|
|
||||||
<DownloadIcon v-if="!installed" />
|
<DownloadIcon v-if="!installed" />
|
||||||
<CheckIcon v-else />
|
<CheckIcon v-else />
|
||||||
{{ installing ? 'Installing' : installed ? 'Installed' : 'Install' }}
|
{{ installing ? 'Installing' : installed ? 'Installed' : 'Install' }}
|
||||||
@@ -87,6 +82,7 @@ import { install as packInstall } from '@/helpers/pack.js'
|
|||||||
import { installVersionDependencies } from '@/helpers/utils.js'
|
import { installVersionDependencies } from '@/helpers/utils.js'
|
||||||
import { useFetch } from '@/helpers/fetch.js'
|
import { useFetch } from '@/helpers/fetch.js'
|
||||||
import { handleError } from '@/store/notifications.js'
|
import { handleError } from '@/store/notifications.js'
|
||||||
|
import mixpanel from 'mixpanel-browser'
|
||||||
dayjs.extend(relativeTime)
|
dayjs.extend(relativeTime)
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
@@ -159,6 +155,13 @@ async function install() {
|
|||||||
props.project.title,
|
props.project.title,
|
||||||
props.project.icon_url
|
props.project.icon_url
|
||||||
).catch(handleError)
|
).catch(handleError)
|
||||||
|
|
||||||
|
mixpanel.track('PackInstall', {
|
||||||
|
id: props.project.project_id,
|
||||||
|
version_id: queuedVersionData.id,
|
||||||
|
title: props.project.title,
|
||||||
|
source: 'SearchCard',
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
props.confirmModal.show(
|
props.confirmModal.show(
|
||||||
props.project.project_id,
|
props.project.project_id,
|
||||||
@@ -174,16 +177,33 @@ async function install() {
|
|||||||
props.instance,
|
props.instance,
|
||||||
props.project.title,
|
props.project.title,
|
||||||
versions,
|
versions,
|
||||||
() => (installed.value = true)
|
() => (installed.value = true),
|
||||||
|
props.project.project_id,
|
||||||
|
props.project.project_type
|
||||||
)
|
)
|
||||||
installing.value = false
|
installing.value = false
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
await installMod(props.instance.path, queuedVersionData.id).catch(handleError)
|
await installMod(props.instance.path, queuedVersionData.id).catch(handleError)
|
||||||
installVersionDependencies(props.instance, queuedVersionData)
|
await installVersionDependencies(props.instance, queuedVersionData)
|
||||||
|
|
||||||
|
mixpanel.track('ProjectInstall', {
|
||||||
|
loader: props.instance.metadata.loader,
|
||||||
|
game_version: props.instance.metadata.game_version,
|
||||||
|
id: props.project.project_id,
|
||||||
|
project_type: props.project.project_type,
|
||||||
|
version_id: queuedVersionData.id,
|
||||||
|
title: props.project.title,
|
||||||
|
source: 'SearchCard',
|
||||||
|
})
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
props.modInstallModal.show(props.project.project_id, versions)
|
props.modInstallModal.show(
|
||||||
|
props.project.project_id,
|
||||||
|
versions,
|
||||||
|
props.project.title,
|
||||||
|
props.project.project_type
|
||||||
|
)
|
||||||
installing.value = false
|
installing.value = false
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,9 @@ import { handleError } from '@/store/state.js'
|
|||||||
|
|
||||||
export const useFetch = async (url, item) => {
|
export const useFetch = async (url, item) => {
|
||||||
try {
|
try {
|
||||||
return await ofetch(url)
|
return await ofetch(url, {
|
||||||
|
headers: { 'User-Agent': 'modrinth/theseus (support@modrinth.com)' },
|
||||||
|
})
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
handleError({ message: `Error fetching ${item}` })
|
handleError({ message: `Error fetching ${item}` })
|
||||||
console.error(err)
|
console.error(err)
|
||||||
|
|||||||
@@ -27,13 +27,8 @@ export async function get_logs_by_datetime(profileUuid, datetimeString) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get a profile's stdout only by datetime_string (the folder name, when the log was created)
|
/// Get a profile's stdout only by datetime_string (the folder name, when the log was created)
|
||||||
export async function get_stdout_by_datetime(profileUuid, datetimeString) {
|
export async function get_output_by_datetime(profileUuid, datetimeString) {
|
||||||
return await invoke('logs_get_stdout_by_datetime', { profileUuid, datetimeString })
|
return await invoke('logs_get_output_by_datetime', { profileUuid, datetimeString })
|
||||||
}
|
|
||||||
|
|
||||||
/// Get a profile's stderr only by datetime_string (the folder name, when the log was created)
|
|
||||||
export async function get_stderr_by_datetime(profileUuid, datetimeString) {
|
|
||||||
return await invoke('logs_get_stderr_by_datetime', { profileUuid, datetimeString })
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Delete a profile's log by datetime_string (the folder name, when the log was created)
|
/// Delete a profile's log by datetime_string (the folder name, when the log was created)
|
||||||
|
|||||||
@@ -47,16 +47,10 @@ export async function get_all_running_profiles() {
|
|||||||
return await invoke('process_get_all_running_profiles')
|
return await invoke('process_get_all_running_profiles')
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets process stderr by UUID
|
|
||||||
/// Returns String
|
|
||||||
export async function get_stderr_by_uuid(uuid) {
|
|
||||||
return await invoke('process_get_stderr_by_uuid', { uuid })
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Gets process stdout by UUID
|
/// Gets process stdout by UUID
|
||||||
/// Returns String
|
/// Returns String
|
||||||
export async function get_stdout_by_uuid(uuid) {
|
export async function get_output_by_uuid(uuid) {
|
||||||
return await invoke('process_get_stdout_by_uuid', { uuid })
|
return await invoke('process_get_output_by_uuid', { uuid })
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Kills a process by UUID
|
/// Kills a process by UUID
|
||||||
|
|||||||
@@ -3,6 +3,10 @@ import { useFetch } from '@/helpers/fetch.js'
|
|||||||
import { handleError } from '@/store/notifications.js'
|
import { handleError } from '@/store/notifications.js'
|
||||||
import { invoke } from '@tauri-apps/api/tauri'
|
import { invoke } from '@tauri-apps/api/tauri'
|
||||||
|
|
||||||
|
export async function isDev() {
|
||||||
|
return await invoke('is_dev')
|
||||||
|
}
|
||||||
|
|
||||||
export async function showInFolder(path) {
|
export async function showInFolder(path) {
|
||||||
return await invoke('show_in_folder', { path })
|
return await invoke('show_in_folder', { path })
|
||||||
}
|
}
|
||||||
@@ -23,6 +27,8 @@ export const releaseColor = (releaseType) => {
|
|||||||
export const installVersionDependencies = async (profile, version) => {
|
export const installVersionDependencies = async (profile, version) => {
|
||||||
for (const dep of version.dependencies) {
|
for (const dep of version.dependencies) {
|
||||||
if (dep.dependency_type !== 'required') continue
|
if (dep.dependency_type !== 'required') continue
|
||||||
|
// disallow fabric api install on quilt
|
||||||
|
if (dep.project_id === 'P7dR8mSH' && profile.metadata.loader === 'quilt') continue
|
||||||
if (dep.version_id) {
|
if (dep.version_id) {
|
||||||
if (
|
if (
|
||||||
dep.project_id &&
|
dep.project_id &&
|
||||||
@@ -45,7 +51,9 @@ export const installVersionDependencies = async (profile, version) => {
|
|||||||
v.game_versions.includes(profile.metadata.game_version) &&
|
v.game_versions.includes(profile.metadata.game_version) &&
|
||||||
v.loaders.includes(profile.metadata.loader)
|
v.loaders.includes(profile.metadata.loader)
|
||||||
)
|
)
|
||||||
await installMod(profile.path, latest.id).catch(handleError)
|
if (latest) {
|
||||||
|
await installMod(profile.path, latest.id).catch(handleError)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -476,7 +476,7 @@ const showLoaders = computed(
|
|||||||
<div class="search-container">
|
<div class="search-container">
|
||||||
<aside class="filter-panel">
|
<aside class="filter-panel">
|
||||||
<div v-if="instanceContext" class="small-instance">
|
<div v-if="instanceContext" class="small-instance">
|
||||||
<div class="instance">
|
<router-link :to="`/instance/${encodeURIComponent(instanceContext.path)}`" class="instance">
|
||||||
<Avatar
|
<Avatar
|
||||||
:src="
|
:src="
|
||||||
!instanceContext.metadata.icon ||
|
!instanceContext.metadata.icon ||
|
||||||
@@ -497,18 +497,20 @@ const showLoaders = computed(
|
|||||||
{{ instanceContext.metadata.game_version }}
|
{{ instanceContext.metadata.game_version }}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</router-link>
|
||||||
<Checkbox
|
<Checkbox
|
||||||
v-model="ignoreInstanceGameVersions"
|
v-model="ignoreInstanceGameVersions"
|
||||||
label="Override game versions"
|
label="Override game versions"
|
||||||
class="filter-checkbox"
|
class="filter-checkbox"
|
||||||
@update:model-value="onSearchChangeToTop(1)"
|
@update:model-value="onSearchChangeToTop(1)"
|
||||||
|
@click.prevent.stop
|
||||||
/>
|
/>
|
||||||
<Checkbox
|
<Checkbox
|
||||||
v-model="ignoreInstanceLoaders"
|
v-model="ignoreInstanceLoaders"
|
||||||
label="Override loaders"
|
label="Override loaders"
|
||||||
class="filter-checkbox"
|
class="filter-checkbox"
|
||||||
@update:model-value="onSearchChangeToTop(1)"
|
@update:model-value="onSearchChangeToTop(1)"
|
||||||
|
@click.prevent.stop
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<Card class="search-panel-card">
|
<Card class="search-panel-card">
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { handleError, useTheming } from '@/store/state'
|
|||||||
import { get, set } from '@/helpers/settings'
|
import { get, set } from '@/helpers/settings'
|
||||||
import { get_max_memory } from '@/helpers/jre'
|
import { get_max_memory } from '@/helpers/jre'
|
||||||
import JavaSelector from '@/components/ui/JavaSelector.vue'
|
import JavaSelector from '@/components/ui/JavaSelector.vue'
|
||||||
|
import mixpanel from 'mixpanel-browser'
|
||||||
|
|
||||||
const themeStore = useTheming()
|
const themeStore = useTheming()
|
||||||
|
|
||||||
@@ -26,6 +27,12 @@ watch(
|
|||||||
async (oldSettings, newSettings) => {
|
async (oldSettings, newSettings) => {
|
||||||
const setSettings = JSON.parse(JSON.stringify(newSettings))
|
const setSettings = JSON.parse(JSON.stringify(newSettings))
|
||||||
|
|
||||||
|
if (setSettings.opt_out_analytics) {
|
||||||
|
mixpanel.opt_out_tracking()
|
||||||
|
} else {
|
||||||
|
mixpanel.opt_in_tracking()
|
||||||
|
}
|
||||||
|
|
||||||
if (setSettings.java_globals.JAVA_8?.path === '') {
|
if (setSettings.java_globals.JAVA_8?.path === '') {
|
||||||
setSettings.java_globals.JAVA_8 = undefined
|
setSettings.java_globals.JAVA_8 = undefined
|
||||||
}
|
}
|
||||||
@@ -116,6 +123,26 @@ watch(
|
|||||||
"
|
"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="adjacent-input">
|
||||||
|
<label for="advanced-rendering">
|
||||||
|
<span class="label__title">Advanced rendering</span>
|
||||||
|
<span class="label__description">
|
||||||
|
Enables advanced rendering such as blur effects that may cause performance issues
|
||||||
|
without hardware-accelerated rendering.
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
<Toggle
|
||||||
|
id="advanced-rendering"
|
||||||
|
:model-value="themeStore.advancedRendering"
|
||||||
|
:checked="themeStore.advancedRendering"
|
||||||
|
@update:model-value="
|
||||||
|
(e) => {
|
||||||
|
themeStore.advancedRendering = e
|
||||||
|
settings.advanced_rendering = themeStore.advancedRendering
|
||||||
|
}
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</Card>
|
</Card>
|
||||||
<Card>
|
<Card>
|
||||||
<div class="label">
|
<div class="label">
|
||||||
@@ -158,6 +185,23 @@ watch(
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</Card>
|
</Card>
|
||||||
|
<Card>
|
||||||
|
<div class="label">
|
||||||
|
<h3>
|
||||||
|
<span class="label__title size-card-header">Privacy</span>
|
||||||
|
</h3>
|
||||||
|
</div>
|
||||||
|
<div class="adjacent-input">
|
||||||
|
<label for="opt-out-analytics">
|
||||||
|
<span class="label__title">Disable analytics</span>
|
||||||
|
<span class="label__description">
|
||||||
|
Modrinth collects anonymized analytics and usage data to improve our user experience and
|
||||||
|
customize your experience. Opting out will disable this data collection.
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
<Toggle id="opt-out-analytics" v-model="settings.opt_out_analytics" />
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
<Card>
|
<Card>
|
||||||
<div class="label">
|
<div class="label">
|
||||||
<h3>
|
<h3>
|
||||||
|
|||||||
@@ -25,7 +25,7 @@
|
|||||||
v-else-if="playing === true"
|
v-else-if="playing === true"
|
||||||
color="danger"
|
color="danger"
|
||||||
class="instance-button"
|
class="instance-button"
|
||||||
@click="stopInstance"
|
@click="stopInstance('InstancePage')"
|
||||||
@mouseover="checkProcess"
|
@mouseover="checkProcess"
|
||||||
>
|
>
|
||||||
<StopCircleIcon />
|
<StopCircleIcon />
|
||||||
@@ -35,7 +35,7 @@
|
|||||||
v-else-if="playing === false && loading === false"
|
v-else-if="playing === false && loading === false"
|
||||||
color="primary"
|
color="primary"
|
||||||
class="instance-button"
|
class="instance-button"
|
||||||
@click="startInstance"
|
@click="startInstance('InstancePage')"
|
||||||
@mouseover="checkProcess"
|
@mouseover="checkProcess"
|
||||||
>
|
>
|
||||||
<PlayIcon />
|
<PlayIcon />
|
||||||
@@ -93,8 +93,6 @@
|
|||||||
<template #open_folder> <ClipboardCopyIcon /> Open Folder </template>
|
<template #open_folder> <ClipboardCopyIcon /> Open Folder </template>
|
||||||
<template #copy_link> <ClipboardCopyIcon /> Copy Link </template>
|
<template #copy_link> <ClipboardCopyIcon /> Copy Link </template>
|
||||||
<template #open_link> <ClipboardCopyIcon /> Open In Modrinth <ExternalIcon /> </template>
|
<template #open_link> <ClipboardCopyIcon /> Open In Modrinth <ExternalIcon /> </template>
|
||||||
<template #repair> <HammerIcon /> Repair </template>
|
|
||||||
<template #delete> <TrashIcon /> Delete </template>
|
|
||||||
</ContextMenu>
|
</ContextMenu>
|
||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
@@ -109,14 +107,12 @@ import {
|
|||||||
PlayIcon,
|
PlayIcon,
|
||||||
StopCircleIcon,
|
StopCircleIcon,
|
||||||
EditIcon,
|
EditIcon,
|
||||||
HammerIcon,
|
|
||||||
TrashIcon,
|
|
||||||
FolderOpenIcon,
|
FolderOpenIcon,
|
||||||
ClipboardCopyIcon,
|
ClipboardCopyIcon,
|
||||||
PlusIcon,
|
PlusIcon,
|
||||||
ExternalIcon,
|
ExternalIcon,
|
||||||
} from 'omorphia'
|
} from 'omorphia'
|
||||||
import { get, install, remove, run } from '@/helpers/profile'
|
import { get, run } from '@/helpers/profile'
|
||||||
import {
|
import {
|
||||||
get_all_running_profile_paths,
|
get_all_running_profile_paths,
|
||||||
get_uuids_by_profile_path,
|
get_uuids_by_profile_path,
|
||||||
@@ -129,6 +125,7 @@ import { convertFileSrc } from '@tauri-apps/api/tauri'
|
|||||||
import { handleError, useBreadcrumbs, useLoading } from '@/store/state'
|
import { handleError, useBreadcrumbs, useLoading } from '@/store/state'
|
||||||
import { showInFolder } from '@/helpers/utils.js'
|
import { showInFolder } from '@/helpers/utils.js'
|
||||||
import ContextMenu from '@/components/ui/ContextMenu.vue'
|
import ContextMenu from '@/components/ui/ContextMenu.vue'
|
||||||
|
import mixpanel from 'mixpanel-browser'
|
||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
|
|
||||||
@@ -151,11 +148,17 @@ const playing = ref(false)
|
|||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
const options = ref(null)
|
const options = ref(null)
|
||||||
|
|
||||||
const startInstance = async () => {
|
const startInstance = async (context) => {
|
||||||
loading.value = true
|
loading.value = true
|
||||||
uuid.value = await run(route.params.id).catch(handleError)
|
uuid.value = await run(route.params.id).catch(handleError)
|
||||||
loading.value = false
|
loading.value = false
|
||||||
playing.value = true
|
playing.value = true
|
||||||
|
|
||||||
|
mixpanel.track('InstanceStart', {
|
||||||
|
loader: instance.value.metadata.loader,
|
||||||
|
game_version: instance.value.metadata.game_version,
|
||||||
|
source: context,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const checkProcess = async () => {
|
const checkProcess = async () => {
|
||||||
@@ -171,25 +174,21 @@ const checkProcess = async () => {
|
|||||||
|
|
||||||
await checkProcess()
|
await checkProcess()
|
||||||
|
|
||||||
const stopInstance = async () => {
|
const stopInstance = async (context) => {
|
||||||
playing.value = false
|
playing.value = false
|
||||||
if (!uuid.value) {
|
if (!uuid.value) {
|
||||||
const uuids = await get_uuids_by_profile_path(instance.value.path).catch(handleError)
|
const uuids = await get_uuids_by_profile_path(instance.value.path).catch(handleError)
|
||||||
uuid.value = uuids[0] // populate Uuid to listen for in the process_listener
|
uuid.value = uuids[0] // populate Uuid to listen for in the process_listener
|
||||||
uuids.forEach(async (u) => await kill_by_uuid(u).catch(handleError))
|
uuids.forEach(async (u) => await kill_by_uuid(u).catch(handleError))
|
||||||
} else await kill_by_uuid(uuid.value).catch(handleError)
|
} else await kill_by_uuid(uuid.value).catch(handleError)
|
||||||
|
|
||||||
|
mixpanel.track('InstanceStop', {
|
||||||
|
loader: instance.value.metadata.loader,
|
||||||
|
game_version: instance.value.metadata.game_version,
|
||||||
|
source: context,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const unlistenProfiles = await profile_listener(async (event) => {
|
|
||||||
if (event.path === route.params.id) {
|
|
||||||
instance.value = await get(route.params.id).catch(handleError)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
const unlistenProcesses = await process_listener((e) => {
|
|
||||||
if (e.event === 'finished' && uuid.value === e.uuid) playing.value = false
|
|
||||||
})
|
|
||||||
|
|
||||||
const handleRightClick = (event) => {
|
const handleRightClick = (event) => {
|
||||||
const baseOptions = [
|
const baseOptions = [
|
||||||
{ name: 'add_content' },
|
{ name: 'add_content' },
|
||||||
@@ -197,15 +196,6 @@ const handleRightClick = (event) => {
|
|||||||
{ name: 'edit' },
|
{ name: 'edit' },
|
||||||
{ name: 'open_folder' },
|
{ name: 'open_folder' },
|
||||||
{ name: 'copy_path' },
|
{ name: 'copy_path' },
|
||||||
{ type: 'divider' },
|
|
||||||
{
|
|
||||||
name: 'repair',
|
|
||||||
color: 'contrast',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'delete',
|
|
||||||
color: 'danger',
|
|
||||||
},
|
|
||||||
]
|
]
|
||||||
|
|
||||||
options.value.showMenu(
|
options.value.showMenu(
|
||||||
@@ -233,10 +223,10 @@ const handleOptionsClick = async (args) => {
|
|||||||
console.log(args)
|
console.log(args)
|
||||||
switch (args.option) {
|
switch (args.option) {
|
||||||
case 'play':
|
case 'play':
|
||||||
await startInstance()
|
await startInstance('InstancePageContextMenu')
|
||||||
break
|
break
|
||||||
case 'stop':
|
case 'stop':
|
||||||
await stopInstance()
|
await stopInstance('InstancePageContextMenu')
|
||||||
break
|
break
|
||||||
case 'add_content':
|
case 'add_content':
|
||||||
await router.push({
|
await router.push({
|
||||||
@@ -249,33 +239,25 @@ const handleOptionsClick = async (args) => {
|
|||||||
path: `/instance/${encodeURIComponent(route.params.id)}/options`,
|
path: `/instance/${encodeURIComponent(route.params.id)}/options`,
|
||||||
})
|
})
|
||||||
break
|
break
|
||||||
case 'repair':
|
|
||||||
await install(instance.value.path).catch(handleError)
|
|
||||||
break
|
|
||||||
case 'delete':
|
|
||||||
await remove(instance.value.path).catch(handleError)
|
|
||||||
break
|
|
||||||
case 'open_folder':
|
case 'open_folder':
|
||||||
await showInFolder(instance.value.path)
|
await showInFolder(instance.value.path)
|
||||||
break
|
break
|
||||||
case 'copy_path':
|
case 'copy_path':
|
||||||
await navigator.clipboard.writeText(instance.value.path)
|
await navigator.clipboard.writeText(instance.value.path)
|
||||||
break
|
break
|
||||||
case 'open_link':
|
|
||||||
window.__TAURI_INVOKE__('tauri', {
|
|
||||||
__tauriModule: 'Shell',
|
|
||||||
message: {
|
|
||||||
cmd: 'open',
|
|
||||||
path: args.item.link,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
break
|
|
||||||
case 'copy_link':
|
|
||||||
await navigator.clipboard.writeText(args.item.link)
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const unlistenProfiles = await profile_listener(async (event) => {
|
||||||
|
if (event.path === route.params.id) {
|
||||||
|
instance.value = await get(route.params.id).catch(handleError)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const unlistenProcesses = await process_listener((e) => {
|
||||||
|
if (e.event === 'finished' && uuid.value === e.uuid) playing.value = false
|
||||||
|
})
|
||||||
|
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
unlistenProcesses()
|
unlistenProcesses()
|
||||||
unlistenProfiles()
|
unlistenProfiles()
|
||||||
|
|||||||
@@ -51,11 +51,11 @@ import {
|
|||||||
SendIcon,
|
SendIcon,
|
||||||
TrashIcon,
|
TrashIcon,
|
||||||
} from 'omorphia'
|
} from 'omorphia'
|
||||||
import { delete_logs_by_datetime, get_logs, get_stdout_by_datetime } from '@/helpers/logs.js'
|
import { delete_logs_by_datetime, get_logs, get_output_by_datetime } from '@/helpers/logs.js'
|
||||||
import { nextTick, onBeforeUnmount, onMounted, onUnmounted, ref, watch } from 'vue'
|
import { nextTick, onBeforeUnmount, onMounted, onUnmounted, ref, watch } from 'vue'
|
||||||
import dayjs from 'dayjs'
|
import dayjs from 'dayjs'
|
||||||
import calendar from 'dayjs/plugin/calendar'
|
import calendar from 'dayjs/plugin/calendar'
|
||||||
import { get_stdout_by_uuid, get_uuids_by_profile_path } from '@/helpers/process.js'
|
import { get_output_by_uuid, get_uuids_by_profile_path } from '@/helpers/process.js'
|
||||||
import { useRoute } from 'vue-router'
|
import { useRoute } from 'vue-router'
|
||||||
import { process_listener } from '@/helpers/events.js'
|
import { process_listener } from '@/helpers/events.js'
|
||||||
import { handleError } from '@/store/notifications.js'
|
import { handleError } from '@/store/notifications.js'
|
||||||
@@ -78,7 +78,7 @@ async function getLiveLog() {
|
|||||||
if (uuids.length === 0) {
|
if (uuids.length === 0) {
|
||||||
returnValue = 'No live game detected. \nStart your game to proceed'
|
returnValue = 'No live game detected. \nStart your game to proceed'
|
||||||
} else {
|
} else {
|
||||||
returnValue = await get_stdout_by_uuid(uuids[0]).catch(handleError)
|
returnValue = await get_output_by_uuid(uuids[0]).catch(handleError)
|
||||||
}
|
}
|
||||||
|
|
||||||
return { name: 'Live Log', stdout: returnValue, live: true }
|
return { name: 'Live Log', stdout: returnValue, live: true }
|
||||||
@@ -120,13 +120,17 @@ watch(selectedLogIndex, async (newIndex) => {
|
|||||||
|
|
||||||
if (newIndex !== 0) {
|
if (newIndex !== 0) {
|
||||||
logs.value[newIndex].stdout = 'Loading...'
|
logs.value[newIndex].stdout = 'Loading...'
|
||||||
logs.value[newIndex].stdout = await get_stdout_by_datetime(
|
logs.value[newIndex].stdout = await get_output_by_datetime(
|
||||||
props.instance.uuid,
|
props.instance.uuid,
|
||||||
logs.value[newIndex].datetime_string
|
logs.value[newIndex].datetime_string
|
||||||
).catch(handleError)
|
).catch(handleError)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if (logs.value.length >= 1) {
|
||||||
|
selectedLogIndex.value = 1
|
||||||
|
}
|
||||||
|
|
||||||
const deleteLog = async () => {
|
const deleteLog = async () => {
|
||||||
if (logs.value[selectedLogIndex.value] && selectedLogIndex.value !== 0) {
|
if (logs.value[selectedLogIndex.value] && selectedLogIndex.value !== 0) {
|
||||||
let deleteIndex = selectedLogIndex.value
|
let deleteIndex = selectedLogIndex.value
|
||||||
@@ -165,9 +169,13 @@ interval.value = setInterval(async () => {
|
|||||||
}, 250)
|
}, 250)
|
||||||
|
|
||||||
const unlistenProcesses = await process_listener(async (e) => {
|
const unlistenProcesses = await process_listener(async (e) => {
|
||||||
|
if (e.event === 'launched') {
|
||||||
|
selectedLogIndex.value = 0
|
||||||
|
}
|
||||||
if (e.event === 'finished') {
|
if (e.event === 'finished') {
|
||||||
userScrolled.value = false
|
userScrolled.value = false
|
||||||
await setLogs()
|
await setLogs()
|
||||||
|
selectedLogIndex.value = 1
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -37,7 +37,7 @@
|
|||||||
>
|
>
|
||||||
<template #search>
|
<template #search>
|
||||||
<SearchIcon />
|
<SearchIcon />
|
||||||
<span class="no-wrap"> Search addons </span>
|
<span class="no-wrap"> Add content </span>
|
||||||
</template>
|
</template>
|
||||||
<template #from_file>
|
<template #from_file>
|
||||||
<FolderOpenIcon />
|
<FolderOpenIcon />
|
||||||
@@ -216,6 +216,7 @@ import {
|
|||||||
update_project,
|
update_project,
|
||||||
} from '@/helpers/profile.js'
|
} from '@/helpers/profile.js'
|
||||||
import { handleError } from '@/store/notifications.js'
|
import { handleError } from '@/store/notifications.js'
|
||||||
|
import mixpanel from 'mixpanel-browser'
|
||||||
import { open } from '@tauri-apps/api/dialog'
|
import { open } from '@tauri-apps/api/dialog'
|
||||||
import { listen } from '@tauri-apps/api/event'
|
import { listen } from '@tauri-apps/api/event'
|
||||||
|
|
||||||
@@ -255,6 +256,7 @@ const initProjects = (initInstance) => {
|
|||||||
updateVersion: project.metadata.update_version,
|
updateVersion: project.metadata.update_version,
|
||||||
outdated: !!project.metadata.update_version,
|
outdated: !!project.metadata.update_version,
|
||||||
project_type: project.metadata.project.project_type,
|
project_type: project.metadata.project.project_type,
|
||||||
|
id: project.metadata.project.id,
|
||||||
})
|
})
|
||||||
} else if (project.metadata.type === 'inferred') {
|
} else if (project.metadata.type === 'inferred') {
|
||||||
projects.value.push({
|
projects.value.push({
|
||||||
@@ -286,6 +288,11 @@ const initProjects = (initInstance) => {
|
|||||||
|
|
||||||
initProjects(props.instance)
|
initProjects(props.instance)
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.instance.projects,
|
||||||
|
() => initProjects(props.instance)
|
||||||
|
)
|
||||||
|
|
||||||
const searchFilter = ref('')
|
const searchFilter = ref('')
|
||||||
const selectAll = ref(false)
|
const selectAll = ref(false)
|
||||||
const sortFilter = ref('')
|
const sortFilter = ref('')
|
||||||
@@ -385,6 +392,13 @@ async function updateAll() {
|
|||||||
for (const project of setProjects) {
|
for (const project of setProjects) {
|
||||||
projects.value[project].updating = false
|
projects.value[project].updating = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mixpanel.track('InstanceUpdateAll', {
|
||||||
|
loader: props.instance.metadata.loader,
|
||||||
|
game_version: props.instance.metadata.game_version,
|
||||||
|
count: setProjects.length,
|
||||||
|
selected: selected.value.length > 1,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async function updateProject(mod) {
|
async function updateProject(mod) {
|
||||||
@@ -395,30 +409,54 @@ async function updateProject(mod) {
|
|||||||
mod.outdated = false
|
mod.outdated = false
|
||||||
mod.version = mod.updateVersion.version_number
|
mod.version = mod.updateVersion.version_number
|
||||||
mod.updateVersion = null
|
mod.updateVersion = null
|
||||||
|
|
||||||
|
mixpanel.track('InstanceProjectUpdate', {
|
||||||
|
loader: props.instance.metadata.loader,
|
||||||
|
game_version: props.instance.metadata.game_version,
|
||||||
|
id: mod.id,
|
||||||
|
name: mod.name,
|
||||||
|
project_type: mod.project_type,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async function toggleDisableMod(mod) {
|
async function toggleDisableMod(mod) {
|
||||||
mod.path = await toggle_disable_project(props.instance.path, mod.path).catch(handleError)
|
mod.path = await toggle_disable_project(props.instance.path, mod.path).catch(handleError)
|
||||||
mod.disabled = !mod.disabled
|
mod.disabled = !mod.disabled
|
||||||
|
|
||||||
|
mixpanel.track('InstanceProjectDisable', {
|
||||||
|
loader: props.instance.metadata.loader,
|
||||||
|
game_version: props.instance.metadata.game_version,
|
||||||
|
id: mod.id,
|
||||||
|
name: mod.name,
|
||||||
|
project_type: mod.project_type,
|
||||||
|
disabled: mod.disabled,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async function removeMod(mod) {
|
async function removeMod(mod) {
|
||||||
await remove_project(props.instance.path, mod.path).catch(handleError)
|
await remove_project(props.instance.path, mod.path).catch(handleError)
|
||||||
projects.value = projects.value.filter((x) => mod.path !== x.path)
|
projects.value = projects.value.filter((x) => mod.path !== x.path)
|
||||||
|
|
||||||
|
mixpanel.track('InstanceProjectRemove', {
|
||||||
|
loader: props.instance.metadata.loader,
|
||||||
|
game_version: props.instance.metadata.game_version,
|
||||||
|
id: mod.id,
|
||||||
|
name: mod.name,
|
||||||
|
project_type: mod.project_type,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleContentOptionClick = async (args) => {
|
const handleContentOptionClick = async (args) => {
|
||||||
if (args.option === 'search') {
|
if (args.option === 'search') {
|
||||||
await router.push({
|
await router.push({
|
||||||
path: `/browse/${props.instance.metadata.loader === 'vanilla' ? 'datapack' : 'mod'}`,
|
path: `/browse/${props.instance.metadata.loader === 'vanilla' ? 'datapack' : 'mod'}`,
|
||||||
|
query: { i: props.instance.path },
|
||||||
})
|
})
|
||||||
} else if (args.option === 'from_file') {
|
} else if (args.option === 'from_file') {
|
||||||
const newProject = await open({ multiple: true })
|
const newProject = await open({ multiple: true })
|
||||||
console.log(newProject)
|
|
||||||
if (!newProject) return
|
if (!newProject) return
|
||||||
|
|
||||||
for (const project of newProject) {
|
for (const project of newProject) {
|
||||||
console.log(project)
|
|
||||||
await add_project_from_path(props.instance.path, project, 'mod').catch(handleError)
|
await add_project_from_path(props.instance.path, project, 'mod').catch(handleError)
|
||||||
initProjects(await get(props.instance.path).catch(handleError))
|
initProjects(await get(props.instance.path).catch(handleError))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,9 +5,14 @@
|
|||||||
description="If you proceed, all data for your instance will be removed. You will not be able to recover it."
|
description="If you proceed, all data for your instance will be removed. You will not be able to recover it."
|
||||||
:has-to-type="false"
|
:has-to-type="false"
|
||||||
proceed-label="Delete"
|
proceed-label="Delete"
|
||||||
|
:noblur="!themeStore.advancedRendering"
|
||||||
@proceed="removeProfile"
|
@proceed="removeProfile"
|
||||||
/>
|
/>
|
||||||
<Modal ref="changeVersionsModal" header="Change instance versions">
|
<Modal
|
||||||
|
ref="changeVersionsModal"
|
||||||
|
header="Change instance versions"
|
||||||
|
:noblur="!themeStore.advancedRendering"
|
||||||
|
>
|
||||||
<div class="change-versions-modal universal-body">
|
<div class="change-versions-modal universal-body">
|
||||||
<div class="input-row">
|
<div class="input-row">
|
||||||
<p class="input-label">Loader</p>
|
<p class="input-label">Loader</p>
|
||||||
@@ -334,6 +339,8 @@ import { open } from '@tauri-apps/api/dialog'
|
|||||||
import { get_fabric_versions, get_forge_versions, get_quilt_versions } from '@/helpers/metadata.js'
|
import { get_fabric_versions, get_forge_versions, get_quilt_versions } from '@/helpers/metadata.js'
|
||||||
import { get_game_versions, get_loaders } from '@/helpers/tags.js'
|
import { get_game_versions, get_loaders } from '@/helpers/tags.js'
|
||||||
import { handleError } from '@/store/notifications.js'
|
import { handleError } from '@/store/notifications.js'
|
||||||
|
import mixpanel from 'mixpanel-browser'
|
||||||
|
import { useTheming } from '@/store/theme.js'
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
|
||||||
@@ -344,6 +351,8 @@ const props = defineProps({
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const themeStore = useTheming()
|
||||||
|
|
||||||
const title = ref(props.instance.metadata.name)
|
const title = ref(props.instance.metadata.name)
|
||||||
const icon = ref(props.instance.metadata.icon)
|
const icon = ref(props.instance.metadata.icon)
|
||||||
const groups = ref(props.instance.metadata.groups)
|
const groups = ref(props.instance.metadata.groups)
|
||||||
@@ -360,6 +369,7 @@ const availableGroups = ref([
|
|||||||
async function resetIcon() {
|
async function resetIcon() {
|
||||||
icon.value = null
|
icon.value = null
|
||||||
await edit_icon(props.instance.path, null).catch(handleError)
|
await edit_icon(props.instance.path, null).catch(handleError)
|
||||||
|
mixpanel.track('InstanceRemoveIcon')
|
||||||
}
|
}
|
||||||
|
|
||||||
async function setIcon() {
|
async function setIcon() {
|
||||||
@@ -377,6 +387,8 @@ async function setIcon() {
|
|||||||
|
|
||||||
icon.value = value
|
icon.value = value
|
||||||
await edit_icon(props.instance.path, icon.value).catch(handleError)
|
await edit_icon(props.instance.path, icon.value).catch(handleError)
|
||||||
|
|
||||||
|
mixpanel.track('InstanceSetIcon')
|
||||||
}
|
}
|
||||||
|
|
||||||
const globalSettings = await get().catch(handleError)
|
const globalSettings = await get().catch(handleError)
|
||||||
@@ -428,6 +440,7 @@ watch(
|
|||||||
metadata: {
|
metadata: {
|
||||||
name: title.value.trim().substring(0, 16) ?? 'Instance',
|
name: title.value.trim().substring(0, 16) ?? 'Instance',
|
||||||
groups: groups.value.map((x) => x.trim().substring(0, 32)).filter((x) => x.length > 0),
|
groups: groups.value.map((x) => x.trim().substring(0, 32)).filter((x) => x.length > 0),
|
||||||
|
loader_version: props.instance.metadata.loader_version,
|
||||||
},
|
},
|
||||||
java: {},
|
java: {},
|
||||||
}
|
}
|
||||||
@@ -481,6 +494,11 @@ async function repairProfile() {
|
|||||||
repairing.value = true
|
repairing.value = true
|
||||||
await install(props.instance.path).catch(handleError)
|
await install(props.instance.path).catch(handleError)
|
||||||
repairing.value = false
|
repairing.value = false
|
||||||
|
|
||||||
|
mixpanel.track('InstanceRepair', {
|
||||||
|
loader: props.instance.metadata.loader,
|
||||||
|
game_version: props.instance.metadata.game_version,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const removing = ref(false)
|
const removing = ref(false)
|
||||||
@@ -489,6 +507,11 @@ async function removeProfile() {
|
|||||||
await remove(props.instance.path).catch(handleError)
|
await remove(props.instance.path).catch(handleError)
|
||||||
removing.value = false
|
removing.value = false
|
||||||
|
|
||||||
|
mixpanel.track('InstanceRemove', {
|
||||||
|
loader: props.instance.metadata.loader,
|
||||||
|
game_version: props.instance.metadata.game_version,
|
||||||
|
})
|
||||||
|
|
||||||
await router.push({ path: '/' })
|
await router.push({ path: '/' })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,10 @@ export default {
|
|||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
.markdown-body {
|
.markdown-body {
|
||||||
|
:deep(table) {
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
|
|
||||||
:deep(hr),
|
:deep(hr),
|
||||||
:deep(h1),
|
:deep(h1),
|
||||||
:deep(h2) {
|
:deep(h2) {
|
||||||
|
|||||||
@@ -93,6 +93,7 @@ import {
|
|||||||
Button,
|
Button,
|
||||||
} from 'omorphia'
|
} from 'omorphia'
|
||||||
import { ref } from 'vue'
|
import { ref } from 'vue'
|
||||||
|
import mixpanel from 'mixpanel-browser'
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
project: {
|
project: {
|
||||||
@@ -111,6 +112,10 @@ const nextImage = () => {
|
|||||||
expandedGalleryIndex.value = 0
|
expandedGalleryIndex.value = 0
|
||||||
}
|
}
|
||||||
expandedGalleryItem.value = props.project.gallery[expandedGalleryIndex.value]
|
expandedGalleryItem.value = props.project.gallery[expandedGalleryIndex.value]
|
||||||
|
mixpanel.track('GalleryImageNext', {
|
||||||
|
project_id: props.project.id,
|
||||||
|
url: expandedGalleryItem.value.url,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const previousImage = () => {
|
const previousImage = () => {
|
||||||
@@ -119,12 +124,21 @@ const previousImage = () => {
|
|||||||
expandedGalleryIndex.value = props.project.gallery.length - 1
|
expandedGalleryIndex.value = props.project.gallery.length - 1
|
||||||
}
|
}
|
||||||
expandedGalleryItem.value = props.project.gallery[expandedGalleryIndex.value]
|
expandedGalleryItem.value = props.project.gallery[expandedGalleryIndex.value]
|
||||||
|
mixpanel.track('GalleryImagePrevious', {
|
||||||
|
project_id: props.project.id,
|
||||||
|
url: expandedGalleryItem.value,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const expandImage = (item, index) => {
|
const expandImage = (item, index) => {
|
||||||
expandedGalleryItem.value = item
|
expandedGalleryItem.value = item
|
||||||
expandedGalleryIndex.value = index
|
expandedGalleryIndex.value = index
|
||||||
zoomedIn.value = false
|
zoomedIn.value = false
|
||||||
|
|
||||||
|
mixpanel.track('GalleryImageExpand', {
|
||||||
|
project_id: props.project.id,
|
||||||
|
url: item.url,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<div class="root-container">
|
<div class="root-container">
|
||||||
<div v-if="data" class="project-sidebar">
|
<div v-if="data" class="project-sidebar">
|
||||||
<div v-if="instance" class="small-instance">
|
<div v-if="instance" class="small-instance">
|
||||||
<div class="instance">
|
<router-link class="instance" :to="`/instance/${encodeURIComponent(instance.path)}`">
|
||||||
<Avatar
|
<Avatar
|
||||||
:src="
|
:src="
|
||||||
!instance.metadata.icon ||
|
!instance.metadata.icon ||
|
||||||
@@ -22,7 +22,7 @@
|
|||||||
{{ instance.metadata.game_version }}
|
{{ instance.metadata.game_version }}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</router-link>
|
||||||
</div>
|
</div>
|
||||||
<Card class="sidebar-card" @contextmenu.prevent.stop="handleRightClick">
|
<Card class="sidebar-card" @contextmenu.prevent.stop="handleRightClick">
|
||||||
<Avatar size="lg" :src="data.icon_url" />
|
<Avatar size="lg" :src="data.icon_url" />
|
||||||
@@ -32,17 +32,11 @@
|
|||||||
</div>
|
</div>
|
||||||
<Categories
|
<Categories
|
||||||
class="tags"
|
class="tags"
|
||||||
type=""
|
:categories="
|
||||||
:categories="[
|
categories.filter(
|
||||||
...categories.filter(
|
|
||||||
(cat) => data.categories.includes(cat.name) && cat.project_type === 'mod'
|
(cat) => data.categories.includes(cat.name) && cat.project_type === 'mod'
|
||||||
),
|
)
|
||||||
...loaders.filter(
|
"
|
||||||
(loader) =>
|
|
||||||
data.categories.includes(loader.name) &&
|
|
||||||
loader.supported_project_types?.includes('modpack')
|
|
||||||
),
|
|
||||||
]"
|
|
||||||
>
|
>
|
||||||
<EnvironmentIndicator
|
<EnvironmentIndicator
|
||||||
:client-side="data.client_side"
|
:client-side="data.client_side"
|
||||||
@@ -258,7 +252,7 @@ import {
|
|||||||
KoFiIcon,
|
KoFiIcon,
|
||||||
OpenCollectiveIcon,
|
OpenCollectiveIcon,
|
||||||
} from '@/assets/external'
|
} from '@/assets/external'
|
||||||
import { get_categories, get_loaders } from '@/helpers/tags'
|
import { get_categories } from '@/helpers/tags'
|
||||||
import { install as packInstall } from '@/helpers/pack'
|
import { install as packInstall } from '@/helpers/pack'
|
||||||
import {
|
import {
|
||||||
list,
|
list,
|
||||||
@@ -268,7 +262,7 @@ import {
|
|||||||
} from '@/helpers/profile'
|
} from '@/helpers/profile'
|
||||||
import dayjs from 'dayjs'
|
import dayjs from 'dayjs'
|
||||||
import relativeTime from 'dayjs/plugin/relativeTime'
|
import relativeTime from 'dayjs/plugin/relativeTime'
|
||||||
import { useRoute, useRouter } from 'vue-router'
|
import { useRoute } from 'vue-router'
|
||||||
import { ref, shallowRef, watch } from 'vue'
|
import { ref, shallowRef, watch } from 'vue'
|
||||||
import { installVersionDependencies } from '@/helpers/utils'
|
import { installVersionDependencies } from '@/helpers/utils'
|
||||||
import InstallConfirmModal from '@/components/ui/InstallConfirmModal.vue'
|
import InstallConfirmModal from '@/components/ui/InstallConfirmModal.vue'
|
||||||
@@ -279,9 +273,9 @@ import { useFetch } from '@/helpers/fetch.js'
|
|||||||
import { handleError } from '@/store/notifications.js'
|
import { handleError } from '@/store/notifications.js'
|
||||||
import { convertFileSrc } from '@tauri-apps/api/tauri'
|
import { convertFileSrc } from '@tauri-apps/api/tauri'
|
||||||
import ContextMenu from '@/components/ui/ContextMenu.vue'
|
import ContextMenu from '@/components/ui/ContextMenu.vue'
|
||||||
|
import mixpanel from 'mixpanel-browser'
|
||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const router = useRouter()
|
|
||||||
const breadcrumbs = useBreadcrumbs()
|
const breadcrumbs = useBreadcrumbs()
|
||||||
|
|
||||||
const confirmModal = ref(null)
|
const confirmModal = ref(null)
|
||||||
@@ -291,32 +285,46 @@ const incompatibilityWarning = ref(null)
|
|||||||
const options = ref(null)
|
const options = ref(null)
|
||||||
const installing = ref(false)
|
const installing = ref(false)
|
||||||
|
|
||||||
const [data, versions, members, dependencies, categories, loaders, instance] = await Promise.all([
|
const data = shallowRef(null)
|
||||||
useFetch(`https://api.modrinth.com/v2/project/${route.params.id}`, 'project').then(shallowRef),
|
const versions = shallowRef([])
|
||||||
useFetch(`https://api.modrinth.com/v2/project/${route.params.id}/version`, 'project').then(
|
const members = shallowRef([])
|
||||||
shallowRef
|
const dependencies = shallowRef([])
|
||||||
),
|
const categories = shallowRef([])
|
||||||
useFetch(`https://api.modrinth.com/v2/project/${route.params.id}/members`, 'project').then(
|
const instance = ref(null)
|
||||||
shallowRef
|
|
||||||
),
|
|
||||||
useFetch(`https://api.modrinth.com/v2/project/${route.params.id}/dependencies`, 'project').then(
|
|
||||||
shallowRef
|
|
||||||
),
|
|
||||||
get_loaders().then(ref).catch(handleError),
|
|
||||||
get_categories().then(ref).catch(handleError),
|
|
||||||
route.query.i ? getInstance(route.query.i, true).then(ref) : Promise.resolve().then(ref),
|
|
||||||
])
|
|
||||||
|
|
||||||
const installed = ref(
|
const installed = ref(false)
|
||||||
instance.value && (await check_installed(instance.value.path, data.value.id).catch(handleError))
|
|
||||||
)
|
|
||||||
|
|
||||||
breadcrumbs.setName('Project', data.value.title)
|
async function fetchProjectData() {
|
||||||
|
;[
|
||||||
|
data.value,
|
||||||
|
versions.value,
|
||||||
|
members.value,
|
||||||
|
dependencies.value,
|
||||||
|
categories.value,
|
||||||
|
instance.value,
|
||||||
|
] = await Promise.all([
|
||||||
|
useFetch(`https://api.modrinth.com/v2/project/${route.params.id}`, 'project'),
|
||||||
|
useFetch(`https://api.modrinth.com/v2/project/${route.params.id}/version`, 'project'),
|
||||||
|
useFetch(`https://api.modrinth.com/v2/project/${route.params.id}/members`, 'project'),
|
||||||
|
useFetch(`https://api.modrinth.com/v2/project/${route.params.id}/dependencies`, 'project'),
|
||||||
|
get_categories().catch(handleError),
|
||||||
|
route.query.i ? getInstance(route.query.i, true).catch(handleError) : Promise.resolve(),
|
||||||
|
])
|
||||||
|
|
||||||
|
installed.value =
|
||||||
|
instance.value?.path &&
|
||||||
|
(await check_installed(instance.value.path, data.value.id).catch(handleError))
|
||||||
|
breadcrumbs.setName('Project', data.value.title)
|
||||||
|
}
|
||||||
|
|
||||||
|
await fetchProjectData()
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => route.params.id,
|
() => route.params.id,
|
||||||
() => {
|
async () => {
|
||||||
if (route.params.id) router.go()
|
if (route.params.id && route.path.startsWith('/project')) {
|
||||||
|
await fetchProjectData()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -356,6 +364,13 @@ async function install(version) {
|
|||||||
data.value.title,
|
data.value.title,
|
||||||
data.value.icon_url
|
data.value.icon_url
|
||||||
).catch(handleError)
|
).catch(handleError)
|
||||||
|
|
||||||
|
mixpanel.track('PackInstall', {
|
||||||
|
id: data.value.id,
|
||||||
|
version_id: queuedVersionData.id,
|
||||||
|
title: data.value.title,
|
||||||
|
source: 'ProjectPage',
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
confirmModal.value.show(
|
confirmModal.value.show(
|
||||||
data.value.id,
|
data.value.id,
|
||||||
@@ -381,14 +396,26 @@ async function install(version) {
|
|||||||
instance.value,
|
instance.value,
|
||||||
data.value.title,
|
data.value.title,
|
||||||
versions.value,
|
versions.value,
|
||||||
markInstalled
|
markInstalled,
|
||||||
|
data.value.id,
|
||||||
|
data.value.project_type
|
||||||
)
|
)
|
||||||
installing.value = false
|
installing.value = false
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
queuedVersionData = selectedVersion
|
queuedVersionData = selectedVersion
|
||||||
await installMod(instance.value.path, selectedVersion.id).catch(handleError)
|
await installMod(instance.value.path, selectedVersion.id).catch(handleError)
|
||||||
installVersionDependencies(instance.value, queuedVersionData)
|
await installVersionDependencies(instance.value, queuedVersionData)
|
||||||
|
|
||||||
|
mixpanel.track('ProjectInstall', {
|
||||||
|
loader: instance.value.metadata.loader,
|
||||||
|
game_version: instance.value.metadata.game_version,
|
||||||
|
id: data.value.id,
|
||||||
|
project_type: data.value.project_type,
|
||||||
|
version_id: queuedVersionData.id,
|
||||||
|
title: data.value.title,
|
||||||
|
source: 'ProjectPage',
|
||||||
|
})
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const gameVersion = instance.value.metadata.game_version
|
const gameVersion = instance.value.metadata.game_version
|
||||||
@@ -403,12 +430,24 @@ async function install(version) {
|
|||||||
if (compatible) {
|
if (compatible) {
|
||||||
await installMod(instance.value.path, queuedVersionData.id).catch(handleError)
|
await installMod(instance.value.path, queuedVersionData.id).catch(handleError)
|
||||||
await installVersionDependencies(instance.value, queuedVersionData)
|
await installVersionDependencies(instance.value, queuedVersionData)
|
||||||
|
|
||||||
|
mixpanel.track('ProjectInstall', {
|
||||||
|
loader: instance.value.metadata.loader,
|
||||||
|
game_version: instance.value.metadata.game_version,
|
||||||
|
id: data.value.id,
|
||||||
|
project_type: data.value.project_type,
|
||||||
|
version_id: queuedVersionData.id,
|
||||||
|
title: data.value.title,
|
||||||
|
source: 'ProjectPage',
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
incompatibilityWarning.value.show(
|
incompatibilityWarning.value.show(
|
||||||
instance.value,
|
instance.value,
|
||||||
data.value.title,
|
data.value.title,
|
||||||
[queuedVersionData],
|
[queuedVersionData],
|
||||||
markInstalled
|
markInstalled,
|
||||||
|
data.value.id,
|
||||||
|
data.value.project_type
|
||||||
)
|
)
|
||||||
installing.value = false
|
installing.value = false
|
||||||
return
|
return
|
||||||
@@ -416,13 +455,12 @@ async function install(version) {
|
|||||||
}
|
}
|
||||||
installed.value = true
|
installed.value = true
|
||||||
} else {
|
} else {
|
||||||
if (version) {
|
modInstallModal.value.show(
|
||||||
modInstallModal.value.show(data.value.id, [
|
data.value.id,
|
||||||
versions.value.find((v) => v.id === queuedVersionData.id),
|
version ? [versions.value.find((v) => v.id === queuedVersionData.id)] : versions.value,
|
||||||
])
|
data.value.title,
|
||||||
} else {
|
data.value.project_type
|
||||||
modInstallModal.value.show(data.value.id, versions.value)
|
)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -622,7 +660,7 @@ const handleOptionsClick = (args) => {
|
|||||||
.instance {
|
.instance {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 0.5rem;
|
gap: 0.5rem;
|
||||||
margin-bottom: 0.5rem;
|
margin-bottom: 0;
|
||||||
|
|
||||||
.title {
|
.title {
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
|
|||||||
@@ -1,9 +1,17 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<Card>
|
<Card>
|
||||||
|
<Breadcrumbs
|
||||||
|
:current-title="version.name"
|
||||||
|
:link-stack="[
|
||||||
|
{
|
||||||
|
href: `/project/${route.params.id}/versions`,
|
||||||
|
label: 'Versions',
|
||||||
|
},
|
||||||
|
]"
|
||||||
|
/>
|
||||||
<div class="version-title">
|
<div class="version-title">
|
||||||
<h2>{{ version.name }}</h2>
|
<h2>{{ version.name }}</h2>
|
||||||
<span v-if="version.featured">Auto-Featured</span>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="button-group">
|
<div class="button-group">
|
||||||
<Button color="primary" :action="() => install(version.id)" :disabled="installed">
|
<Button color="primary" :action="() => install(version.id)" :disabled="installed">
|
||||||
@@ -11,10 +19,6 @@
|
|||||||
<CheckIcon v-else />
|
<CheckIcon v-else />
|
||||||
{{ installed ? 'Installed' : 'Install' }}
|
{{ installed ? 'Installed' : 'Install' }}
|
||||||
</Button>
|
</Button>
|
||||||
<Button :link="`/project/${route.params.id}/versions`">
|
|
||||||
<LeftArrowIcon />
|
|
||||||
Back to list
|
|
||||||
</Button>
|
|
||||||
<Button>
|
<Button>
|
||||||
<ReportIcon />
|
<ReportIcon />
|
||||||
Report
|
Report
|
||||||
@@ -65,10 +69,15 @@
|
|||||||
</Button>
|
</Button>
|
||||||
</Card>
|
</Card>
|
||||||
</Card>
|
</Card>
|
||||||
<Card v-if="displayDependencies[0]">
|
<Card v-if="displayDependencies.length > 0">
|
||||||
<h2>Dependencies</h2>
|
<h2>Dependencies</h2>
|
||||||
<div v-for="dependency in displayDependencies" :key="dependency.title">
|
<div v-for="dependency in displayDependencies" :key="dependency.title">
|
||||||
<router-link v-if="dependency.link" class="btn dependency" :to="dependency.link">
|
<router-link
|
||||||
|
v-if="dependency.link"
|
||||||
|
class="btn dependency"
|
||||||
|
:to="dependency.link"
|
||||||
|
@click="testTest"
|
||||||
|
>
|
||||||
<Avatar size="sm" :src="dependency.icon" />
|
<Avatar size="sm" :src="dependency.icon" />
|
||||||
<div>
|
<div>
|
||||||
<span class="title"> {{ dependency.title }} </span> <br />
|
<span class="title"> {{ dependency.title }} </span> <br />
|
||||||
@@ -173,17 +182,17 @@ import {
|
|||||||
DownloadIcon,
|
DownloadIcon,
|
||||||
FileIcon,
|
FileIcon,
|
||||||
Avatar,
|
Avatar,
|
||||||
LeftArrowIcon,
|
|
||||||
ReportIcon,
|
ReportIcon,
|
||||||
Badge,
|
Badge,
|
||||||
ExternalIcon,
|
ExternalIcon,
|
||||||
CopyCode,
|
CopyCode,
|
||||||
CheckIcon,
|
CheckIcon,
|
||||||
|
Breadcrumbs,
|
||||||
formatBytes,
|
formatBytes,
|
||||||
renderString,
|
renderString,
|
||||||
} from 'omorphia'
|
} from 'omorphia'
|
||||||
import { releaseColor } from '@/helpers/utils'
|
import { releaseColor } from '@/helpers/utils'
|
||||||
import { ref, defineProps } from 'vue'
|
import { ref, defineProps, watch, computed } from 'vue'
|
||||||
import { useRoute } from 'vue-router'
|
import { useRoute } from 'vue-router'
|
||||||
import { useBreadcrumbs } from '@/store/breadcrumbs'
|
import { useBreadcrumbs } from '@/store/breadcrumbs'
|
||||||
|
|
||||||
@@ -221,9 +230,21 @@ const props = defineProps({
|
|||||||
const version = ref(props.versions.find((version) => version.id === route.params.version))
|
const version = ref(props.versions.find((version) => version.id === route.params.version))
|
||||||
breadcrumbs.setName('Version', version.value.name)
|
breadcrumbs.setName('Version', version.value.name)
|
||||||
|
|
||||||
const author = ref(props.members.find((member) => member.user.id === version.value.author_id))
|
watch(
|
||||||
|
() => props.versions,
|
||||||
|
async () => {
|
||||||
|
if (route.params.version) {
|
||||||
|
version.value = props.versions.find((version) => version.id === route.params.version)
|
||||||
|
breadcrumbs.setName('Version', version.value.name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
const displayDependencies = ref(
|
const author = computed(() =>
|
||||||
|
props.members.find((member) => member.user.id === version.value.author_id)
|
||||||
|
)
|
||||||
|
|
||||||
|
const displayDependencies = computed(() =>
|
||||||
version.value.dependencies.map((dependency) => {
|
version.value.dependencies.map((dependency) => {
|
||||||
const version = props.dependencies.versions.find((obj) => obj.id === dependency.version_id)
|
const version = props.dependencies.versions.find((obj) => obj.id === dependency.version_id)
|
||||||
if (version) {
|
if (version) {
|
||||||
@@ -236,13 +257,25 @@ const displayDependencies = ref(
|
|||||||
subtitle: `Version ${version.version_number} is ${dependency.dependency_type}`,
|
subtitle: `Version ${version.version_number} is ${dependency.dependency_type}`,
|
||||||
link: `/project/${project.slug}/version/${version.id}`,
|
link: `/project/${project.slug}/version/${version.id}`,
|
||||||
}
|
}
|
||||||
} else
|
} else {
|
||||||
return {
|
const project = props.dependencies.projects.find((obj) => obj.id === dependency.project_id)
|
||||||
icon: null,
|
|
||||||
title: dependency.file_name,
|
if (project) {
|
||||||
subtitle: `Added via overrides`,
|
return {
|
||||||
link: null,
|
icon: project?.icon_url,
|
||||||
|
title: project?.title || project?.name,
|
||||||
|
subtitle: `${dependency.dependency_type}`,
|
||||||
|
link: `/project/${project.slug}`,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
icon: null,
|
||||||
|
title: dependency.file_name,
|
||||||
|
subtitle: `Added via overrides`,
|
||||||
|
link: null,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ export const useTheming = defineStore('themeStore', {
|
|||||||
state: () => ({
|
state: () => ({
|
||||||
themeOptions: ['dark'],
|
themeOptions: ['dark'],
|
||||||
collapsedNavigation: false,
|
collapsedNavigation: false,
|
||||||
|
advancedRendering: true,
|
||||||
selectedTheme: 'dark',
|
selectedTheme: 'dark',
|
||||||
darkTheme: true,
|
darkTheme: true,
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -92,51 +92,7 @@ async fn main() -> theseus::Result<()> {
|
|||||||
None,
|
None,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
//
|
|
||||||
// install(&profile_path).await.unwrap();
|
|
||||||
|
|
||||||
// let mut value = list().await?;
|
|
||||||
// let profile_path = value.iter().next().map(|x| x.0).unwrap();
|
|
||||||
|
|
||||||
println!("Adding sodium");
|
|
||||||
let sodium_path = profile::add_project_from_version(
|
|
||||||
&profile_path,
|
|
||||||
"rAfhHfow".to_string(),
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
let mod_menu_path = profile::add_project_from_version(
|
|
||||||
&profile_path,
|
|
||||||
"gSoPJyVn".to_string(),
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
println!("Disabling sodium");
|
|
||||||
profile::toggle_disable_project(&profile_path, &sodium_path).await?;
|
|
||||||
|
|
||||||
profile::remove_project(&profile_path, &mod_menu_path).await?;
|
|
||||||
|
|
||||||
// let profile_path = pack::install_pack_from_version_id(
|
|
||||||
// "CeeCkHke".to_string(),
|
|
||||||
// "Technical Electrical".to_string(),
|
|
||||||
// None,
|
|
||||||
// )
|
|
||||||
// .await
|
|
||||||
// .unwrap();
|
|
||||||
|
|
||||||
// async closure for testing any desired edits
|
|
||||||
// (ie: changing the java runtime of an added profile)
|
|
||||||
println!("Editing.");
|
|
||||||
profile::edit(&profile_path, |_profile| {
|
|
||||||
// Add some hooks, for instance!
|
|
||||||
// profile.hooks = Some(Hooks {
|
|
||||||
// pre_launch: Some("echo This is before Minecraft runs!".to_string()),
|
|
||||||
// wrapper: None,
|
|
||||||
// post_exit: None,
|
|
||||||
// });
|
|
||||||
async { Ok(()) }
|
|
||||||
})
|
|
||||||
.await?;
|
|
||||||
State::sync().await?;
|
State::sync().await?;
|
||||||
|
|
||||||
// Attempt to run game
|
// Attempt to run game
|
||||||
@@ -157,10 +113,8 @@ async fn main() -> theseus::Result<()> {
|
|||||||
// Wait 5 seconds
|
// Wait 5 seconds
|
||||||
println!("Waiting 5 seconds to gather logs...");
|
println!("Waiting 5 seconds to gather logs...");
|
||||||
sleep(Duration::from_secs(5)).await;
|
sleep(Duration::from_secs(5)).await;
|
||||||
let stdout = process::get_stdout_by_uuid(&uuid).await?;
|
let stdout = process::get_output_by_uuid(&uuid).await?;
|
||||||
let stderr = process::get_stderr_by_uuid(&uuid).await?;
|
|
||||||
println!("Logs after 5sec <<< {stdout} >>> end stdout");
|
println!("Logs after 5sec <<< {stdout} >>> end stdout");
|
||||||
println!("Logs after 5sec <<< {stderr} >>> end stderr");
|
|
||||||
|
|
||||||
println!(
|
println!(
|
||||||
"All running process UUID {:?}",
|
"All running process UUID {:?}",
|
||||||
|
|||||||
Reference in New Issue
Block a user