feat(gui): launcher window (create fleet, node controls, actions)
This commit is contained in:
Generated
+632
-1
@@ -11,6 +11,20 @@ dependencies = [
|
|||||||
"uuid",
|
"uuid",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "accesskit_atspi_common"
|
||||||
|
version = "0.18.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1e8c61bee90b42a772d39d06a740207dc71a4e780004ace1db8d99fb1baaa954"
|
||||||
|
dependencies = [
|
||||||
|
"accesskit",
|
||||||
|
"accesskit_consumer 0.36.0",
|
||||||
|
"atspi-common",
|
||||||
|
"phf",
|
||||||
|
"serde",
|
||||||
|
"zvariant",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "accesskit_consumer"
|
name = "accesskit_consumer"
|
||||||
version = "0.35.0"
|
version = "0.35.0"
|
||||||
@@ -21,6 +35,86 @@ dependencies = [
|
|||||||
"hashbrown 0.16.1",
|
"hashbrown 0.16.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "accesskit_consumer"
|
||||||
|
version = "0.36.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "25e0d7e25d06f4dc21d1774d67146e9e80d6789216cbd4d1e88185b0095dba60"
|
||||||
|
dependencies = [
|
||||||
|
"accesskit",
|
||||||
|
"hashbrown 0.16.1",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "accesskit_consumer"
|
||||||
|
version = "0.38.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5d10a236f96f87d70732e44520046785431ef01d5bcd6b041317bfadd2f88245"
|
||||||
|
dependencies = [
|
||||||
|
"accesskit",
|
||||||
|
"hashbrown 0.16.1",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "accesskit_macos"
|
||||||
|
version = "0.26.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ce02dc63b43f0c9296af9ac946312a2dc8814427d7a64d2d600971dac55b6076"
|
||||||
|
dependencies = [
|
||||||
|
"accesskit",
|
||||||
|
"accesskit_consumer 0.38.0",
|
||||||
|
"hashbrown 0.16.1",
|
||||||
|
"objc2 0.5.3",
|
||||||
|
"objc2-app-kit 0.2.2",
|
||||||
|
"objc2-foundation 0.2.2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "accesskit_unix"
|
||||||
|
version = "0.21.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b016ca8db0ea0ea2ceff29a9d6240391492d960716aa471967c00e8cc8cb197c"
|
||||||
|
dependencies = [
|
||||||
|
"accesskit",
|
||||||
|
"accesskit_atspi_common",
|
||||||
|
"async-channel",
|
||||||
|
"async-executor",
|
||||||
|
"async-task",
|
||||||
|
"atspi",
|
||||||
|
"futures-lite",
|
||||||
|
"futures-util",
|
||||||
|
"serde",
|
||||||
|
"zbus",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "accesskit_windows"
|
||||||
|
version = "0.32.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "eff7009f1a532e917d66970a1e80c965140c6cfbbabbdde3d64e5431e6c78e21"
|
||||||
|
dependencies = [
|
||||||
|
"accesskit",
|
||||||
|
"accesskit_consumer 0.35.0",
|
||||||
|
"hashbrown 0.16.1",
|
||||||
|
"static_assertions",
|
||||||
|
"windows",
|
||||||
|
"windows-core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "accesskit_winit"
|
||||||
|
version = "0.32.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1fe9a94394896352cc4660ca2288bd4ef883d83238853c038b44070c8f134313"
|
||||||
|
dependencies = [
|
||||||
|
"accesskit",
|
||||||
|
"accesskit_macos",
|
||||||
|
"accesskit_unix",
|
||||||
|
"accesskit_windows",
|
||||||
|
"raw-window-handle",
|
||||||
|
"winit",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "adler2"
|
name = "adler2"
|
||||||
version = "2.0.1"
|
version = "2.0.1"
|
||||||
@@ -106,6 +200,12 @@ version = "0.7.8"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d3fb67a6e08acf24fdeccbac2cb6ac4305825bd1f117462e0e6f2f193345ad56"
|
checksum = "d3fb67a6e08acf24fdeccbac2cb6ac4305825bd1f117462e0e6f2f193345ad56"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "as-raw-xcb-connection"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "175571dd1d178ced59193a6fc02dde1b972eb0bc56c892cde9beeceac5bf0f6b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ash"
|
name = "ash"
|
||||||
version = "0.38.0+1.3.281"
|
version = "0.38.0+1.3.281"
|
||||||
@@ -115,6 +215,137 @@ dependencies = [
|
|||||||
"libloading",
|
"libloading",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "async-broadcast"
|
||||||
|
version = "0.7.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "435a87a52755b8f27fcf321ac4f04b2802e337c8c4872923137471ec39c37532"
|
||||||
|
dependencies = [
|
||||||
|
"event-listener",
|
||||||
|
"event-listener-strategy",
|
||||||
|
"futures-core",
|
||||||
|
"pin-project-lite",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "async-channel"
|
||||||
|
version = "2.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "924ed96dd52d1b75e9c1a3e6275715fd320f5f9439fb5a4a11fa51f4221158d2"
|
||||||
|
dependencies = [
|
||||||
|
"concurrent-queue",
|
||||||
|
"event-listener-strategy",
|
||||||
|
"futures-core",
|
||||||
|
"pin-project-lite",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "async-executor"
|
||||||
|
version = "1.14.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c96bf972d85afc50bf5ab8fe2d54d1586b4e0b46c97c50a0c9e71e2f7bcd812a"
|
||||||
|
dependencies = [
|
||||||
|
"async-task",
|
||||||
|
"concurrent-queue",
|
||||||
|
"fastrand",
|
||||||
|
"futures-lite",
|
||||||
|
"pin-project-lite",
|
||||||
|
"slab",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "async-io"
|
||||||
|
version = "2.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "456b8a8feb6f42d237746d4b3e9a178494627745c3c56c6ea55d92ba50d026fc"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"cfg-if",
|
||||||
|
"concurrent-queue",
|
||||||
|
"futures-io",
|
||||||
|
"futures-lite",
|
||||||
|
"parking",
|
||||||
|
"polling",
|
||||||
|
"rustix 1.1.5",
|
||||||
|
"slab",
|
||||||
|
"windows-sys 0.61.2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "async-lock"
|
||||||
|
version = "3.4.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "290f7f2596bd5b78a9fec8088ccd89180d7f9f55b94b0576823bbbdc72ee8311"
|
||||||
|
dependencies = [
|
||||||
|
"event-listener",
|
||||||
|
"event-listener-strategy",
|
||||||
|
"pin-project-lite",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "async-process"
|
||||||
|
version = "2.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fc50921ec0055cdd8a16de48773bfeec5c972598674347252c0399676be7da75"
|
||||||
|
dependencies = [
|
||||||
|
"async-channel",
|
||||||
|
"async-io",
|
||||||
|
"async-lock",
|
||||||
|
"async-signal",
|
||||||
|
"async-task",
|
||||||
|
"blocking",
|
||||||
|
"cfg-if",
|
||||||
|
"event-listener",
|
||||||
|
"futures-lite",
|
||||||
|
"rustix 1.1.5",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "async-recursion"
|
||||||
|
version = "1.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4f8abc12baad266b1c8cec146854c195b5864b4221d4b2ca7296a7ae82d9e451"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 3.0.9",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "async-signal"
|
||||||
|
version = "0.2.14"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "52b5aaafa020cf5053a01f2a60e8ff5dccf550f0f77ec54a4e47285ac2bab485"
|
||||||
|
dependencies = [
|
||||||
|
"async-io",
|
||||||
|
"async-lock",
|
||||||
|
"atomic-waker",
|
||||||
|
"cfg-if",
|
||||||
|
"futures-core",
|
||||||
|
"futures-io",
|
||||||
|
"rustix 1.1.5",
|
||||||
|
"signal-hook-registry",
|
||||||
|
"slab",
|
||||||
|
"windows-sys 0.61.2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "async-task"
|
||||||
|
version = "4.7.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "async-trait"
|
||||||
|
version = "0.1.92"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "82f6aeea286b8eb4dd3431a1be1b59d290ace00f5bfd8e2a159bc2a05e2c1667"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 3.0.9",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "atomic-polyfill"
|
name = "atomic-polyfill"
|
||||||
version = "1.0.3"
|
version = "1.0.3"
|
||||||
@@ -130,6 +361,43 @@ version = "1.1.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
|
checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "atspi"
|
||||||
|
version = "0.29.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c77886257be21c9cd89a4ae7e64860c6f0eefca799bb79127913052bd0eefb3d"
|
||||||
|
dependencies = [
|
||||||
|
"atspi-common",
|
||||||
|
"atspi-proxies",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "atspi-common"
|
||||||
|
version = "0.13.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "20c5617155740c98003016429ad13fe43ce7a77b007479350a9f8bf95a29f63d"
|
||||||
|
dependencies = [
|
||||||
|
"enumflags2",
|
||||||
|
"serde",
|
||||||
|
"static_assertions",
|
||||||
|
"zbus",
|
||||||
|
"zbus-lockstep",
|
||||||
|
"zbus-lockstep-macros",
|
||||||
|
"zbus_names",
|
||||||
|
"zvariant",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "atspi-proxies"
|
||||||
|
version = "0.13.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2230e48787ed3eb4088996eab66a32ca20c0b67bbd4fd6cdfe79f04f1f04c9fc"
|
||||||
|
dependencies = [
|
||||||
|
"atspi-common",
|
||||||
|
"serde",
|
||||||
|
"zbus",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "autocfg"
|
name = "autocfg"
|
||||||
version = "1.5.1"
|
version = "1.5.1"
|
||||||
@@ -199,6 +467,19 @@ dependencies = [
|
|||||||
"objc2 0.6.5",
|
"objc2 0.6.5",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "blocking"
|
||||||
|
version = "1.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a70e4329df6cb94385eed412ec92375c3cdd8a6e502493d1229b6414e4036dfa"
|
||||||
|
dependencies = [
|
||||||
|
"async-channel",
|
||||||
|
"async-task",
|
||||||
|
"futures-io",
|
||||||
|
"futures-lite",
|
||||||
|
"piper",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bluer"
|
name = "bluer"
|
||||||
version = "0.17.4"
|
version = "0.17.4"
|
||||||
@@ -745,6 +1026,7 @@ version = "0.36.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "98466000559d66ba4db786a30448b01483946add4188e7f10f522a27b4fb89cc"
|
checksum = "98466000559d66ba4db786a30448b01483946add4188e7f10f522a27b4fb89cc"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"accesskit_winit",
|
||||||
"arboard",
|
"arboard",
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
"egui",
|
"egui",
|
||||||
@@ -818,6 +1100,33 @@ version = "0.6.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d"
|
checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "endi"
|
||||||
|
version = "1.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "66b7e2430c6dff6a955451e2cfc438f09cea1965a9d6f87f7e3b90decc014099"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "enumflags2"
|
||||||
|
version = "0.7.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1027f7680c853e056ebcec683615fb6fbbc07dbaa13b4d5d9442b146ded4ecef"
|
||||||
|
dependencies = [
|
||||||
|
"enumflags2_derive",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "enumflags2_derive"
|
||||||
|
version = "0.7.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "67c78a4d8fdf9953a5c9d458f9efe940fd97a0cab0941c075a813ac594733827"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.119",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "epaint"
|
name = "epaint"
|
||||||
version = "0.36.2"
|
version = "0.36.2"
|
||||||
@@ -880,6 +1189,26 @@ dependencies = [
|
|||||||
"num-traits",
|
"num-traits",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "event-listener"
|
||||||
|
version = "5.4.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5a23add41df1562121a9393cb065eab5146a1242410f23a644851e90cfd669d2"
|
||||||
|
dependencies = [
|
||||||
|
"parking",
|
||||||
|
"pin-project-lite",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "event-listener-strategy"
|
||||||
|
version = "0.5.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93"
|
||||||
|
dependencies = [
|
||||||
|
"event-listener",
|
||||||
|
"pin-project-lite",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fastrand"
|
name = "fastrand"
|
||||||
version = "2.5.0"
|
version = "2.5.0"
|
||||||
@@ -1020,6 +1349,19 @@ version = "0.3.34"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "53c0fa8157de1303bfffdaa1cc2a673bfffb60102f76b0ef4441659124373fed"
|
checksum = "53c0fa8157de1303bfffdaa1cc2a673bfffb60102f76b0ef4441659124373fed"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-lite"
|
||||||
|
version = "2.6.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f78e10609fe0e0b3f4157ffab1876319b5b0db102a2c60dc4626306dc46b44ad"
|
||||||
|
dependencies = [
|
||||||
|
"fastrand",
|
||||||
|
"futures-core",
|
||||||
|
"futures-io",
|
||||||
|
"parking",
|
||||||
|
"pin-project-lite",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-macro"
|
name = "futures-macro"
|
||||||
version = "0.3.34"
|
version = "0.3.34"
|
||||||
@@ -1492,7 +1834,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "90ceaa75eb0036a32b6b9833962eb18137449e9817e2e586006471925b727fd5"
|
checksum = "90ceaa75eb0036a32b6b9833962eb18137449e9817e2e586006471925b727fd5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"accesskit",
|
"accesskit",
|
||||||
"accesskit_consumer",
|
"accesskit_consumer 0.35.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1636,6 +1978,15 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "memoffset"
|
||||||
|
version = "0.9.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "miniz_oxide"
|
name = "miniz_oxide"
|
||||||
version = "0.8.9"
|
version = "0.8.9"
|
||||||
@@ -2180,6 +2531,22 @@ dependencies = [
|
|||||||
"num-traits",
|
"num-traits",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ordered-stream"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9aa2b01e1d916879f73a53d01d1d6cee68adbb31d6d9177a8cfce093cced1d50"
|
||||||
|
dependencies = [
|
||||||
|
"futures-core",
|
||||||
|
"pin-project-lite",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "parking"
|
||||||
|
version = "2.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "parking_lot"
|
name = "parking_lot"
|
||||||
version = "0.12.5"
|
version = "0.12.5"
|
||||||
@@ -2222,6 +2589,49 @@ version = "2.3.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220"
|
checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "phf"
|
||||||
|
version = "0.13.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c1562dc717473dbaa4c1f85a36410e03c047b2e7df7f45ee938fbef64ae7fadf"
|
||||||
|
dependencies = [
|
||||||
|
"phf_macros",
|
||||||
|
"phf_shared",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "phf_generator"
|
||||||
|
version = "0.13.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "135ace3a761e564ec88c03a77317a7c6b80bb7f7135ef2544dbe054243b89737"
|
||||||
|
dependencies = [
|
||||||
|
"fastrand",
|
||||||
|
"phf_shared",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "phf_macros"
|
||||||
|
version = "0.13.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "812f032b54b1e759ccd5f8b6677695d5268c588701effba24601f6932f8269ef"
|
||||||
|
dependencies = [
|
||||||
|
"phf_generator",
|
||||||
|
"phf_shared",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.119",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "phf_shared"
|
||||||
|
version = "0.13.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e57fef6bc5981e38c2ce2d63bfa546861309f875b8a75f092d1d54ae2d64f266"
|
||||||
|
dependencies = [
|
||||||
|
"siphasher",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pin-project"
|
name = "pin-project"
|
||||||
version = "1.1.13"
|
version = "1.1.13"
|
||||||
@@ -2248,6 +2658,17 @@ version = "0.2.17"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd"
|
checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "piper"
|
||||||
|
version = "0.2.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c835479a4443ded371d6c535cbfd8d31ad92c5d23ae9770a61bc155e4992a3c1"
|
||||||
|
dependencies = [
|
||||||
|
"atomic-waker",
|
||||||
|
"fastrand",
|
||||||
|
"futures-io",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pkg-config"
|
name = "pkg-config"
|
||||||
version = "0.3.34"
|
version = "0.3.34"
|
||||||
@@ -2599,6 +3020,17 @@ dependencies = [
|
|||||||
"zmij",
|
"zmij",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_repr"
|
||||||
|
version = "0.1.21"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8d3b1629de253c70a0508c3899572da79ca359fdab27c7920ff00406df418906"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 3.0.9",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_spanned"
|
name = "serde_spanned"
|
||||||
version = "1.1.2"
|
version = "1.1.2"
|
||||||
@@ -2646,6 +3078,12 @@ version = "0.1.5"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e"
|
checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "siphasher"
|
||||||
|
version = "1.0.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "33f4fe9184a62d842c9ef383018f3306d8ba224fd9d836f56d7288308847c256"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "skrifa"
|
name = "skrifa"
|
||||||
version = "0.44.0"
|
version = "0.44.0"
|
||||||
@@ -3084,14 +3522,29 @@ checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"log",
|
"log",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
|
"tracing-attributes",
|
||||||
"tracing-core",
|
"tracing-core",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tracing-attributes"
|
||||||
|
version = "0.1.31"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.119",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tracing-core"
|
name = "tracing-core"
|
||||||
version = "0.1.36"
|
version = "0.1.36"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a"
|
checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a"
|
||||||
|
dependencies = [
|
||||||
|
"once_cell",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "type-map"
|
name = "type-map"
|
||||||
@@ -3108,6 +3561,17 @@ version = "1.20.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20"
|
checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "uds_windows"
|
||||||
|
version = "1.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f2f6fb2847f6742cd76af783a2a2c49e9375d0a111c7bef6f71cd9e738c72d6e"
|
||||||
|
dependencies = [
|
||||||
|
"memoffset",
|
||||||
|
"tempfile",
|
||||||
|
"windows-sys 0.61.2",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-general-category"
|
name = "unicode-general-category"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
@@ -3140,6 +3604,7 @@ checksum = "4a0e2d11620c50695fe12bbbfde96b3477fe606e7284c22d505c12ce51214514"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"getrandom 0.4.3",
|
"getrandom 0.4.3",
|
||||||
"js-sys",
|
"js-sys",
|
||||||
|
"serde_core",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -3822,6 +4287,7 @@ dependencies = [
|
|||||||
"atomic-waker",
|
"atomic-waker",
|
||||||
"bitflags 2.13.2",
|
"bitflags 2.13.2",
|
||||||
"block2 0.5.1",
|
"block2 0.5.1",
|
||||||
|
"bytemuck",
|
||||||
"calloop 0.13.0",
|
"calloop 0.13.0",
|
||||||
"cfg_aliases",
|
"cfg_aliases",
|
||||||
"concurrent-queue",
|
"concurrent-queue",
|
||||||
@@ -3838,6 +4304,7 @@ dependencies = [
|
|||||||
"objc2-foundation 0.2.2",
|
"objc2-foundation 0.2.2",
|
||||||
"objc2-ui-kit 0.2.2",
|
"objc2-ui-kit 0.2.2",
|
||||||
"orbclient",
|
"orbclient",
|
||||||
|
"percent-encoding",
|
||||||
"pin-project",
|
"pin-project",
|
||||||
"raw-window-handle",
|
"raw-window-handle",
|
||||||
"redox_syscall 0.4.1",
|
"redox_syscall 0.4.1",
|
||||||
@@ -3855,6 +4322,8 @@ dependencies = [
|
|||||||
"web-sys",
|
"web-sys",
|
||||||
"web-time",
|
"web-time",
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.52.0",
|
||||||
|
"x11-dl",
|
||||||
|
"x11rb",
|
||||||
"xkbcommon-dl",
|
"xkbcommon-dl",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -3873,13 +4342,28 @@ version = "0.57.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e"
|
checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "x11-dl"
|
||||||
|
version = "2.21.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "38735924fedd5314a6e548792904ed8c6de6636285cb9fec04d5b1db85c1516f"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"once_cell",
|
||||||
|
"pkg-config",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "x11rb"
|
name = "x11rb"
|
||||||
version = "0.13.2"
|
version = "0.13.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9993aa5be5a26815fe2c3eacfc1fde061fc1a1f094bf1ad2a18bf9c495dd7414"
|
checksum = "9993aa5be5a26815fe2c3eacfc1fde061fc1a1f094bf1ad2a18bf9c495dd7414"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"as-raw-xcb-connection",
|
||||||
"gethostname",
|
"gethostname",
|
||||||
|
"libc",
|
||||||
|
"libloading",
|
||||||
|
"once_cell",
|
||||||
"rustix 1.1.5",
|
"rustix 1.1.5",
|
||||||
"x11rb-protocol",
|
"x11rb-protocol",
|
||||||
]
|
]
|
||||||
@@ -3921,6 +4405,112 @@ version = "0.8.29"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e450f9b2ed1dff33c94c12589a87338689467b9c4f5d8a5710bd09a847d2c8a7"
|
checksum = "e450f9b2ed1dff33c94c12589a87338689467b9c4f5d8a5710bd09a847d2c8a7"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zbus"
|
||||||
|
version = "5.19.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5db4be7c075cb421e4b7ee645541604239bd243ba7c357511f4ff3a74b555907"
|
||||||
|
dependencies = [
|
||||||
|
"async-broadcast",
|
||||||
|
"async-executor",
|
||||||
|
"async-io",
|
||||||
|
"async-lock",
|
||||||
|
"async-process",
|
||||||
|
"async-recursion",
|
||||||
|
"async-task",
|
||||||
|
"async-trait",
|
||||||
|
"blocking",
|
||||||
|
"enumflags2",
|
||||||
|
"event-listener",
|
||||||
|
"futures-core",
|
||||||
|
"futures-lite",
|
||||||
|
"hex",
|
||||||
|
"libc",
|
||||||
|
"ordered-stream",
|
||||||
|
"rustix 1.1.5",
|
||||||
|
"serde",
|
||||||
|
"serde_repr",
|
||||||
|
"tracing",
|
||||||
|
"uds_windows",
|
||||||
|
"uuid",
|
||||||
|
"windows-sys 0.61.2",
|
||||||
|
"winnow",
|
||||||
|
"zbus_macros",
|
||||||
|
"zbus_names",
|
||||||
|
"zvariant",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zbus-lockstep"
|
||||||
|
version = "0.5.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6998de05217a084b7578728a9443d04ea4cd80f2a0839b8d78770b76ccd45863"
|
||||||
|
dependencies = [
|
||||||
|
"zbus_xml",
|
||||||
|
"zvariant",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zbus-lockstep-macros"
|
||||||
|
version = "0.5.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "10da05367f3a7b7553c8cdf8fa91aee6b64afebe32b51c95177957efc47ca3a0"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.119",
|
||||||
|
"zbus-lockstep",
|
||||||
|
"zbus_xml",
|
||||||
|
"zvariant",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zbus_macros"
|
||||||
|
version = "5.19.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2990635d09ade6df1868f72f8cac69a876a90981e8bd3c40b1be413f8dc88f40"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro-crate",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 3.0.9",
|
||||||
|
"zbus_names",
|
||||||
|
"zvariant",
|
||||||
|
"zvariant_utils",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zbus_names"
|
||||||
|
version = "4.3.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d8bf88b4a3ff53e883001e0e0115b297a9d53c31b9c1edd2bfdd853e3428624e"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
"winnow",
|
||||||
|
"zvariant",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zbus_xml"
|
||||||
|
version = "5.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d1586c021a01ca0a9216dcd874e546382e156a5cbab5fab6cb5f10087e22682a"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
"winnow",
|
||||||
|
"zbus_names",
|
||||||
|
"zvariant",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zcheapstr"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d1afec51604565183aeb5c54c20aeab286120d4e4460f7f76e3e8bb8c0d99473"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zerocopy"
|
name = "zerocopy"
|
||||||
version = "0.8.63"
|
version = "0.8.63"
|
||||||
@@ -3967,3 +4557,44 @@ checksum = "27bc9d5b815bc103f142aa054f561d9187d191692ec7c2d1e2b4737f8dbd7296"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"zune-core",
|
"zune-core",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zvariant"
|
||||||
|
version = "5.15.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c1d34c27cc6cdd1f458427519dd6b8612f7b7e3f7b9a0b2355d041dda9869147"
|
||||||
|
dependencies = [
|
||||||
|
"endi",
|
||||||
|
"enumflags2",
|
||||||
|
"serde",
|
||||||
|
"winnow",
|
||||||
|
"zcheapstr",
|
||||||
|
"zvariant_derive",
|
||||||
|
"zvariant_utils",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zvariant_derive"
|
||||||
|
version = "5.15.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "864155e69b4352db0c7f374917bf45d1e0c8d17659c8b3dbf9795f3673f8c497"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro-crate",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 3.0.9",
|
||||||
|
"zvariant_utils",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zvariant_utils"
|
||||||
|
version = "4.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bad0294361a320b694a328460dc73add56c306150f5cb6bfafc44446120008a3"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"serde",
|
||||||
|
"syn 3.0.9",
|
||||||
|
"winnow",
|
||||||
|
]
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ serde_json = "1"
|
|||||||
notify = "8"
|
notify = "8"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
egui_kittest = { version = "0.36", features = ["wgpu"] }
|
egui_kittest = { version = "0.36", features = ["wgpu", "eframe"] }
|
||||||
tempfile = "3"
|
tempfile = "3"
|
||||||
|
|
||||||
# Like fuzz/, this crate sits outside the workspace (the GUI is a separate
|
# Like fuzz/, this crate sits outside the workspace (the GUI is a separate
|
||||||
|
|||||||
@@ -0,0 +1,330 @@
|
|||||||
|
//! The launcher window: fleet creation, node/container controls, and
|
||||||
|
//! per-node window spawns.
|
||||||
|
//!
|
||||||
|
//! [`Launcher::update`] renders and queues intents — it never spawns a
|
||||||
|
//! process (except the one-time bus daemon inside `Fleet::create`, which is
|
||||||
|
//! a non-blocking `spawn`). Everything else drains through
|
||||||
|
//! [`Launcher::drain_actions`], called by `main.rs` after each frame; the
|
||||||
|
//! headless tests drive `update` and assert on the queued actions.
|
||||||
|
|
||||||
|
use std::collections::{HashMap, VecDeque};
|
||||||
|
use std::path::PathBuf;
|
||||||
|
use std::process::Child;
|
||||||
|
|
||||||
|
use egui::Context;
|
||||||
|
|
||||||
|
use crate::config::fleet_dir;
|
||||||
|
use crate::docker::{ContainerId, Docker};
|
||||||
|
use crate::fleet::{Fleet, Mode};
|
||||||
|
|
||||||
|
/// One node container the launcher knows about.
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub struct ContainerEntry {
|
||||||
|
/// The node name (also the dir and container-name stem).
|
||||||
|
pub name: String,
|
||||||
|
/// The container id `docker run -d` returned.
|
||||||
|
pub id: ContainerId,
|
||||||
|
/// How the node connects to its peers.
|
||||||
|
pub mode: Mode,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An intent the UI queued; `main.rs` executes these by draining the queue.
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub enum LauncherAction {
|
||||||
|
/// Add the node to the fleet and start its container.
|
||||||
|
StartContainer {
|
||||||
|
/// The node name.
|
||||||
|
name: String,
|
||||||
|
/// How the node connects to its peers.
|
||||||
|
mode: Mode,
|
||||||
|
},
|
||||||
|
/// Stop a running container.
|
||||||
|
StopContainer(ContainerId),
|
||||||
|
/// Remove a stopped container.
|
||||||
|
RemoveContainer(ContainerId),
|
||||||
|
/// Spawn a dedicated window process for this node.
|
||||||
|
OpenWindow {
|
||||||
|
/// The node name.
|
||||||
|
name: String,
|
||||||
|
/// The node's config dir (the `--node` arg).
|
||||||
|
dir: PathBuf,
|
||||||
|
/// The container the window controls.
|
||||||
|
id: ContainerId,
|
||||||
|
/// How the node connects to its peers.
|
||||||
|
mode: Mode,
|
||||||
|
},
|
||||||
|
/// Build the runtime image.
|
||||||
|
BuildImage,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The launcher window's full state.
|
||||||
|
pub struct Launcher {
|
||||||
|
/// The created fleet; `None` until Create succeeds.
|
||||||
|
pub fleet: Option<Fleet>,
|
||||||
|
/// The docker frontend.
|
||||||
|
pub docker: Docker,
|
||||||
|
/// Known node containers (only successful starts land here).
|
||||||
|
pub containers: Vec<ContainerEntry>,
|
||||||
|
/// Spawned node-window processes.
|
||||||
|
pub children: Vec<Child>,
|
||||||
|
/// Intents queued by [`Launcher::update`], drained by `main.rs`.
|
||||||
|
pub actions: VecDeque<LauncherAction>,
|
||||||
|
|
||||||
|
/// The fleet-name field.
|
||||||
|
pub fleet_name: String,
|
||||||
|
/// The node-name field for Add.
|
||||||
|
pub node_name: String,
|
||||||
|
/// The bt peer field (bt mode only; the pinned `StartContainer` action
|
||||||
|
/// carries no peer, so it is read from here at drain time).
|
||||||
|
pub node_peer: String,
|
||||||
|
/// The mode picker.
|
||||||
|
pub mode: Mode,
|
||||||
|
/// The selected row's name (drives the log pane).
|
||||||
|
pub selected: Option<String>,
|
||||||
|
/// The selected container's last-fetched log tail.
|
||||||
|
pub log_tail: Option<String>,
|
||||||
|
/// The latest error to surface.
|
||||||
|
pub error: Option<String>,
|
||||||
|
|
||||||
|
/// `docker inspect` results, refreshed at most once per second.
|
||||||
|
running: HashMap<ContainerId, bool>,
|
||||||
|
/// When the running map was last refreshed.
|
||||||
|
last_running_check: f64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Launcher {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Launcher {
|
||||||
|
/// An empty launcher: no fleet, no containers, sim mode.
|
||||||
|
pub fn new() -> Launcher {
|
||||||
|
Launcher {
|
||||||
|
fleet: None,
|
||||||
|
docker: Docker,
|
||||||
|
containers: Vec::new(),
|
||||||
|
children: Vec::new(),
|
||||||
|
actions: VecDeque::new(),
|
||||||
|
fleet_name: String::new(),
|
||||||
|
node_name: String::new(),
|
||||||
|
node_peer: String::new(),
|
||||||
|
mode: Mode::Sim,
|
||||||
|
selected: None,
|
||||||
|
log_tail: None,
|
||||||
|
error: None,
|
||||||
|
running: HashMap::new(),
|
||||||
|
last_running_check: f64::NEG_INFINITY,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Render the launcher and queue intents. Side effects are limited to
|
||||||
|
/// the fleet creation itself (a non-blocking daemon spawn) and one
|
||||||
|
/// `docker logs` fetch when a row is selected.
|
||||||
|
pub fn update(&mut self, ctx: &Context) {
|
||||||
|
let now = ctx.input(|i| i.time);
|
||||||
|
if now - self.last_running_check > 1.0 {
|
||||||
|
self.last_running_check = now;
|
||||||
|
self.running = self
|
||||||
|
.containers
|
||||||
|
.iter()
|
||||||
|
.map(|c| (c.id.clone(), self.docker.is_running(&c.id)))
|
||||||
|
.collect();
|
||||||
|
}
|
||||||
|
|
||||||
|
// egui 0.36 is Ui-based: rebuild the root Ui the eframe App would
|
||||||
|
// have passed, so the panels have a parent.
|
||||||
|
let mut ui = egui::Ui::new(
|
||||||
|
ctx.clone(),
|
||||||
|
egui::Id::new("tines-gui-root"),
|
||||||
|
egui::UiBuilder::new().max_rect(ctx.content_rect()),
|
||||||
|
);
|
||||||
|
|
||||||
|
egui::Panel::top("controls").show(&mut ui, |ui| {
|
||||||
|
ui.horizontal(|ui| {
|
||||||
|
ui.label("Mode:");
|
||||||
|
ui.selectable_value(&mut self.mode, Mode::Bt, "Bt");
|
||||||
|
ui.selectable_value(&mut self.mode, Mode::Sim, "Sim");
|
||||||
|
});
|
||||||
|
ui.horizontal(|ui| {
|
||||||
|
ui.label("Fleet name:");
|
||||||
|
ui.text_edit_singleline(&mut self.fleet_name);
|
||||||
|
if ui.button("Create").clicked() {
|
||||||
|
match Fleet::create(self.fleet_name.trim()) {
|
||||||
|
Ok(fleet) => {
|
||||||
|
self.fleet = Some(fleet);
|
||||||
|
self.error = None;
|
||||||
|
}
|
||||||
|
Err(e) => self.error = Some(format!("cannot create fleet: {e}")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if self.mode == Mode::Bt {
|
||||||
|
ui.horizontal(|ui| {
|
||||||
|
ui.label("Peer (bt):");
|
||||||
|
ui.text_edit_singleline(&mut self.node_peer);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
ui.horizontal(|ui| {
|
||||||
|
ui.label("Node name:");
|
||||||
|
ui.text_edit_singleline(&mut self.node_name);
|
||||||
|
if ui.button("Add").clicked() {
|
||||||
|
self.actions.push_back(LauncherAction::StartContainer {
|
||||||
|
name: self.node_name.trim().to_string(),
|
||||||
|
mode: self.mode,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if ui.button("Build image").clicked() {
|
||||||
|
self.actions.push_back(LauncherAction::BuildImage);
|
||||||
|
}
|
||||||
|
if let Some(error) = &self.error {
|
||||||
|
ui.colored_label(egui::Color32::from_rgb(0xff, 0x55, 0x55), error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
egui::CentralPanel::default().show(&mut ui, |ui| {
|
||||||
|
egui::Grid::new("nodes")
|
||||||
|
.striped(true)
|
||||||
|
.min_col_width(80.0)
|
||||||
|
.show(ui, |ui| {
|
||||||
|
ui.label("node");
|
||||||
|
ui.label("mode");
|
||||||
|
ui.label("state");
|
||||||
|
ui.label("");
|
||||||
|
ui.end_row();
|
||||||
|
for entry in &self.containers {
|
||||||
|
let running = self.running.get(&entry.id).copied().unwrap_or(false);
|
||||||
|
let name = entry.name.clone();
|
||||||
|
if ui
|
||||||
|
.selectable_label(self.selected.as_deref() == Some(&name), &entry.name)
|
||||||
|
.clicked()
|
||||||
|
{
|
||||||
|
self.selected = Some(name.clone());
|
||||||
|
self.log_tail = self.docker.logs(&entry.id, 50).ok();
|
||||||
|
}
|
||||||
|
ui.label(match entry.mode {
|
||||||
|
Mode::Bt => "bt",
|
||||||
|
Mode::Sim => "sim",
|
||||||
|
});
|
||||||
|
ui.label(if running { "running" } else { "stopped" });
|
||||||
|
ui.horizontal(|ui| {
|
||||||
|
if ui.button("Open").clicked() {
|
||||||
|
self.actions.push_back(LauncherAction::OpenWindow {
|
||||||
|
name: name.clone(),
|
||||||
|
dir: fleet_dir(self.fleet_name.trim()).join(&name),
|
||||||
|
id: entry.id.clone(),
|
||||||
|
mode: entry.mode,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if ui.button("Stop").clicked() {
|
||||||
|
self.actions
|
||||||
|
.push_back(LauncherAction::StopContainer(entry.id.clone()));
|
||||||
|
}
|
||||||
|
if ui.button("Remove").clicked() {
|
||||||
|
self.actions
|
||||||
|
.push_back(LauncherAction::RemoveContainer(entry.id.clone()));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
ui.end_row();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
egui::Panel::bottom("logs").show(&mut ui, |ui| {
|
||||||
|
ui.heading(match &self.selected {
|
||||||
|
Some(name) => format!("logs — {name}"),
|
||||||
|
None => "logs — select a container".to_string(),
|
||||||
|
});
|
||||||
|
if let Some(tail) = &self.log_tail {
|
||||||
|
egui::ScrollArea::vertical()
|
||||||
|
.max_height(120.0)
|
||||||
|
.auto_shrink([false, false])
|
||||||
|
.show(ui, |ui| {
|
||||||
|
ui.monospace(tail);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Execute every queued intent. This is the only place containers are
|
||||||
|
/// started/stopped/removed and node windows spawned; `main.rs` calls it
|
||||||
|
/// after each frame.
|
||||||
|
pub fn drain_actions(&mut self) {
|
||||||
|
while let Some(action) = self.actions.pop_front() {
|
||||||
|
match action {
|
||||||
|
LauncherAction::StartContainer { name, mode } => {
|
||||||
|
let Some(fleet) = self.fleet.as_ref() else {
|
||||||
|
self.error = Some("create a fleet first".to_string());
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
let peer = (mode == Mode::Bt && !self.node_peer.trim().is_empty())
|
||||||
|
.then(|| self.node_peer.trim().to_string());
|
||||||
|
if let Err(e) = fleet.add_node(&name, None, mode, peer.as_deref()) {
|
||||||
|
self.error = Some(format!("cannot add node {name}: {e}"));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let started = match mode {
|
||||||
|
Mode::Bt => self.docker.start_bt(&name, self.fleet_name.trim()),
|
||||||
|
Mode::Sim => self.docker.start_sim(&name, self.fleet_name.trim()),
|
||||||
|
};
|
||||||
|
match started {
|
||||||
|
Ok(id) => self.containers.push(ContainerEntry { name, id, mode }),
|
||||||
|
Err(e) => self.error = Some(format!("cannot start {name}: {e}")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LauncherAction::StopContainer(id) => {
|
||||||
|
if let Err(e) = self.docker.stop(&id) {
|
||||||
|
self.error = Some(format!("cannot stop {}: {e}", id.0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LauncherAction::RemoveContainer(id) => {
|
||||||
|
if let Err(e) = self.docker.remove(&id) {
|
||||||
|
self.error = Some(format!("cannot remove {}: {e}", id.0));
|
||||||
|
}
|
||||||
|
self.containers.retain(|c| c.id != id);
|
||||||
|
if self.selected.as_ref() == Some(&id.0) {
|
||||||
|
self.selected = None;
|
||||||
|
self.log_tail = None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LauncherAction::OpenWindow {
|
||||||
|
name,
|
||||||
|
dir,
|
||||||
|
id,
|
||||||
|
mode,
|
||||||
|
} => {
|
||||||
|
let mode_arg = match mode {
|
||||||
|
Mode::Bt => "bt",
|
||||||
|
Mode::Sim => "sim",
|
||||||
|
};
|
||||||
|
match std::env::current_exe().and_then(|exe| {
|
||||||
|
std::process::Command::new(exe)
|
||||||
|
.arg("--node")
|
||||||
|
.arg(&dir)
|
||||||
|
.arg(&id.0)
|
||||||
|
.arg(mode_arg)
|
||||||
|
.spawn()
|
||||||
|
}) {
|
||||||
|
Ok(child) => self.children.push(child),
|
||||||
|
Err(e) => {
|
||||||
|
self.error = Some(format!("cannot open window for {name}: {e}"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LauncherAction::BuildImage => {
|
||||||
|
if let Err(e) = self.docker.build_image() {
|
||||||
|
self.error = Some(format!("image build failed: {e}"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl eframe::App for Launcher {
|
||||||
|
fn ui(&mut self, ui: &mut egui::Ui, _frame: &mut eframe::Frame) {
|
||||||
|
Launcher::update(self, ui.ctx());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,4 +11,5 @@ pub mod config;
|
|||||||
pub mod docker;
|
pub mod docker;
|
||||||
pub mod fleet;
|
pub mod fleet;
|
||||||
pub mod ipc_client;
|
pub mod ipc_client;
|
||||||
|
pub mod launcher;
|
||||||
pub mod theme;
|
pub mod theme;
|
||||||
|
|||||||
+68
-5
@@ -1,9 +1,72 @@
|
|||||||
//! The console binary. Task 8 wires the real UI; for now the launcher
|
//! tines-gui entry point: no args opens the launcher window;
|
||||||
//! sentence is the whole program.
|
//! `--node <dir> <container-id> <mode>` opens a node window (Task 8b).
|
||||||
|
|
||||||
fn main() {
|
use eframe::egui;
|
||||||
|
|
||||||
|
fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
let args: Vec<String> = std::env::args().collect();
|
let args: Vec<String> = std::env::args().collect();
|
||||||
if args.len() < 2 {
|
match args.as_slice() {
|
||||||
println!("tines-gui: launcher");
|
[_, flag, dir, id, mode] if flag == "--node" => {
|
||||||
|
let _ = (dir, id, mode);
|
||||||
|
eprintln!("tines-gui: node window is Task 8b — not wired yet");
|
||||||
|
std::process::exit(1);
|
||||||
|
}
|
||||||
|
[_] => run_launcher()?,
|
||||||
|
_ => {
|
||||||
|
eprintln!("usage: tines-gui [--node <dir> <container-id> <mode>]");
|
||||||
|
std::process::exit(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The launcher window: renders via `Launcher::update`, then drains the
|
||||||
|
/// action queue — the only place subprocess spawns happen.
|
||||||
|
struct LauncherApp {
|
||||||
|
launcher: tines_gui::launcher::Launcher,
|
||||||
|
theme: tines_gui::theme::OmarchyTheme,
|
||||||
|
watching: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl eframe::App for LauncherApp {
|
||||||
|
fn ui(&mut self, ui: &mut egui::Ui, _frame: &mut eframe::Frame) {
|
||||||
|
let ctx = ui.ctx().clone();
|
||||||
|
self.theme = tines_gui::theme::OmarchyTheme::load();
|
||||||
|
self.theme.apply(&ctx);
|
||||||
|
if !self.watching {
|
||||||
|
let ctx = ctx.clone();
|
||||||
|
if tines_gui::theme::OmarchyTheme::watch(move || ctx.request_repaint()).is_ok() {
|
||||||
|
self.watching = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.launcher.update(&ctx);
|
||||||
|
self.launcher.drain_actions();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn run_launcher() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||||
|
let viewport = egui::ViewportBuilder::default()
|
||||||
|
.with_app_id("tines-gui")
|
||||||
|
.with_title("tines — fleet console")
|
||||||
|
.with_inner_size([760.0, 520.0]);
|
||||||
|
let options = eframe::NativeOptions {
|
||||||
|
viewport,
|
||||||
|
glow_options: eframe::egui_glow::GlowConfiguration {
|
||||||
|
vsync: false,
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
eframe::run_native(
|
||||||
|
"tines-gui",
|
||||||
|
options,
|
||||||
|
Box::new(|_cc| {
|
||||||
|
Ok(Box::new(LauncherApp {
|
||||||
|
launcher: tines_gui::launcher::Launcher::new(),
|
||||||
|
theme: tines_gui::theme::OmarchyTheme::load(),
|
||||||
|
watching: false,
|
||||||
|
}))
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.map_err(|e| format!("eframe: {e}").into())
|
||||||
|
}
|
||||||
|
|||||||
@@ -39,6 +39,26 @@ impl OmarchyTheme {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Apply the palette: egui visuals plus an opaque background fill so
|
||||||
|
/// the window is never transparent on Wayland. Call every frame.
|
||||||
|
pub fn apply(&self, ctx: &egui::Context) {
|
||||||
|
let mut visuals = egui::Visuals::dark();
|
||||||
|
visuals.panel_fill = self.background;
|
||||||
|
visuals.window_fill = self.background;
|
||||||
|
visuals.window_stroke = egui::Stroke::NONE;
|
||||||
|
visuals.override_text_color = Some(self.foreground);
|
||||||
|
visuals.selection.bg_fill = self.accent;
|
||||||
|
visuals.widgets.hovered.bg_stroke = egui::Stroke::new(1.0, self.accent);
|
||||||
|
visuals.widgets.active.bg_stroke = egui::Stroke::new(1.0, self.accent);
|
||||||
|
visuals.widgets.noninteractive.bg_stroke = egui::Stroke::new(1.0, self.accent);
|
||||||
|
ctx.set_visuals(visuals);
|
||||||
|
let painter = ctx.layer_painter(egui::LayerId::new(
|
||||||
|
egui::Order::Background,
|
||||||
|
egui::Id::new("tines-gui-bg"),
|
||||||
|
));
|
||||||
|
painter.rect_filled(ctx.content_rect(), 0.0, self.background);
|
||||||
|
}
|
||||||
|
|
||||||
/// Watch the omarchy `current` theme dir (recursively) and call
|
/// Watch the omarchy `current` theme dir (recursively) and call
|
||||||
/// `on_change` whenever it changes — the caller repaints from there.
|
/// `on_change` whenever it changes — the caller repaints from there.
|
||||||
/// Returns an error only if the watcher cannot be installed.
|
/// Returns an error only if the watcher cannot be installed.
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
//! Shared test setup for the integration suites. Compiled per test binary;
|
||||||
|
//! only declare `mod common;` in tests that use these helpers.
|
||||||
|
|
||||||
|
use std::os::unix::fs::PermissionsExt;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
use std::sync::OnceLock;
|
||||||
|
|
||||||
|
/// One shared scratch setup per test binary: a temp dir that becomes both
|
||||||
|
/// XDG_STATE_HOME (fleet dirs) and a PATH dir holding a fake `tines-busd`.
|
||||||
|
/// Env is process-global, so it is set exactly once before any test touches
|
||||||
|
/// `fleet_dir` — a per-test `set_var` from parallel test threads would race.
|
||||||
|
pub fn env_with_fake_busd() -> &'static PathBuf {
|
||||||
|
static DIR: OnceLock<PathBuf> = OnceLock::new();
|
||||||
|
DIR.get_or_init(|| {
|
||||||
|
let dir = std::env::temp_dir().join(format!("tines-gui-test-{}", std::process::id()));
|
||||||
|
let _ = std::fs::remove_dir_all(&dir);
|
||||||
|
std::fs::create_dir_all(&dir).unwrap();
|
||||||
|
|
||||||
|
// Fake tines-busd: create the socket named by argv[1], then stay
|
||||||
|
// alive so the spawning Fleet keeps a live child.
|
||||||
|
let fake = dir.join("tines-busd");
|
||||||
|
std::fs::write(&fake, "#!/bin/sh\ntouch \"$1\"\nsleep 60\n").unwrap();
|
||||||
|
std::fs::set_permissions(&fake, std::fs::Permissions::from_mode(0o755)).unwrap();
|
||||||
|
|
||||||
|
let path = format!(
|
||||||
|
"{}:{}",
|
||||||
|
dir.display(),
|
||||||
|
std::env::var("PATH").unwrap_or_default()
|
||||||
|
);
|
||||||
|
// SAFETY: set once, before any fleet_dir call; this process is a
|
||||||
|
// test binary that exits afterwards, so nothing else observes it.
|
||||||
|
unsafe {
|
||||||
|
std::env::set_var("XDG_STATE_HOME", &dir);
|
||||||
|
std::env::set_var("PATH", path);
|
||||||
|
}
|
||||||
|
dir
|
||||||
|
})
|
||||||
|
}
|
||||||
+10
-42
@@ -1,48 +1,16 @@
|
|||||||
//! Fleet layout and node-config tests. The bus daemon is a fake `tines-busd`
|
//! Fleet layout and node-config tests. The bus daemon is a fake `tines-busd`
|
||||||
//! seeded onto PATH (the real binary isn't on PATH for unit tests): it
|
//! seeded onto PATH (see `common`; the real binary isn't on PATH for unit
|
||||||
//! records its argv and creates the socket file, so the fleet's spawn
|
//! tests): it creates the socket file named by argv[1], so the fleet's
|
||||||
//! protocol is what's under test — the real daemon is covered by tines-bus's
|
//! spawn protocol is what's under test — the real daemon is covered by
|
||||||
//! own suite and Task 4's e2e.
|
//! tines-bus's own suite and Task 4's e2e.
|
||||||
|
|
||||||
|
mod common;
|
||||||
|
|
||||||
use std::os::unix::fs::PermissionsExt;
|
use std::os::unix::fs::PermissionsExt;
|
||||||
use std::path::PathBuf;
|
|
||||||
use std::sync::OnceLock;
|
|
||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
use tines_gui::fleet::{Fleet, Mode};
|
use tines_gui::fleet::{Fleet, Mode};
|
||||||
|
|
||||||
/// One shared scratch setup for every test in this binary: a temp dir that
|
|
||||||
/// becomes both XDG_STATE_HOME (fleet dirs) and a PATH dir holding the fake
|
|
||||||
/// `tines-busd`. Env is process-global, so it is set exactly once before any
|
|
||||||
/// test touches fleet_dir.
|
|
||||||
fn setup() -> &'static PathBuf {
|
|
||||||
static DIR: OnceLock<PathBuf> = OnceLock::new();
|
|
||||||
DIR.get_or_init(|| {
|
|
||||||
let dir = std::env::temp_dir().join(format!("tines-gui-fleet-test-{}", std::process::id()));
|
|
||||||
let _ = std::fs::remove_dir_all(&dir);
|
|
||||||
std::fs::create_dir_all(&dir).unwrap();
|
|
||||||
|
|
||||||
// Fake tines-busd: touch the socket named by argv[1], then stay alive.
|
|
||||||
let fake = dir.join("tines-busd");
|
|
||||||
std::fs::write(&fake, "#!/bin/sh\ntouch \"$1\"\nsleep 60\n").unwrap();
|
|
||||||
use std::os::unix::fs::PermissionsExt;
|
|
||||||
std::fs::set_permissions(&fake, std::fs::Permissions::from_mode(0o755)).unwrap();
|
|
||||||
|
|
||||||
let path = format!(
|
|
||||||
"{}:{}",
|
|
||||||
dir.display(),
|
|
||||||
std::env::var("PATH").unwrap_or_default()
|
|
||||||
);
|
|
||||||
// SAFETY: set once, before any fleet_dir call; this process is a
|
|
||||||
// test binary that exits afterwards, so nothing else observes it.
|
|
||||||
unsafe {
|
|
||||||
std::env::set_var("XDG_STATE_HOME", &dir);
|
|
||||||
std::env::set_var("PATH", path);
|
|
||||||
}
|
|
||||||
dir
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn fleet_name(tag: &str) -> String {
|
fn fleet_name(tag: &str) -> String {
|
||||||
format!(
|
format!(
|
||||||
"test-{tag}-{}",
|
"test-{tag}-{}",
|
||||||
@@ -52,7 +20,7 @@ fn fleet_name(tag: &str) -> String {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn fleet_dir_layout() {
|
fn fleet_dir_layout() {
|
||||||
setup();
|
common::env_with_fake_busd();
|
||||||
let fleet = Fleet::create(&fleet_name("layout")).expect("fleet creates");
|
let fleet = Fleet::create(&fleet_name("layout")).expect("fleet creates");
|
||||||
let dir = tines_gui::config::fleet_dir(&fleet_name("layout"));
|
let dir = tines_gui::config::fleet_dir(&fleet_name("layout"));
|
||||||
let meta = std::fs::metadata(&dir).expect("fleet dir exists");
|
let meta = std::fs::metadata(&dir).expect("fleet dir exists");
|
||||||
@@ -75,7 +43,7 @@ fn fleet_dir_layout() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn add_node_bus_config_mounts_data() {
|
fn add_node_bus_config_mounts_data() {
|
||||||
setup();
|
common::env_with_fake_busd();
|
||||||
let fleet_name = fleet_name("bus");
|
let fleet_name = fleet_name("bus");
|
||||||
let fleet = Fleet::create(&fleet_name).expect("fleet creates");
|
let fleet = Fleet::create(&fleet_name).expect("fleet creates");
|
||||||
let spec = fleet
|
let spec = fleet
|
||||||
@@ -95,7 +63,7 @@ fn add_node_bus_config_mounts_data() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn add_node_bt_config_has_peer() {
|
fn add_node_bt_config_has_peer() {
|
||||||
setup();
|
common::env_with_fake_busd();
|
||||||
let fleet_name = fleet_name("bt");
|
let fleet_name = fleet_name("bt");
|
||||||
let fleet = Fleet::create(&fleet_name).expect("fleet creates");
|
let fleet = Fleet::create(&fleet_name).expect("fleet creates");
|
||||||
let peer = "22".repeat(16);
|
let peer = "22".repeat(16);
|
||||||
@@ -114,7 +82,7 @@ fn add_node_bt_config_has_peer() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn generated_id_roundtrips() {
|
fn generated_id_roundtrips() {
|
||||||
setup();
|
common::env_with_fake_busd();
|
||||||
let fleet_name = fleet_name("gen");
|
let fleet_name = fleet_name("gen");
|
||||||
let fleet = Fleet::create(&fleet_name).expect("fleet creates");
|
let fleet = Fleet::create(&fleet_name).expect("fleet creates");
|
||||||
let spec = fleet
|
let spec = fleet
|
||||||
|
|||||||
@@ -0,0 +1,108 @@
|
|||||||
|
//! Launcher UI tests (egui_kittest, headless). No real docker or daemon:
|
||||||
|
//! the fake `tines-busd` is seeded on PATH (see `common`), and the
|
||||||
|
//! containers are injected directly into the launcher's state.
|
||||||
|
|
||||||
|
mod common;
|
||||||
|
|
||||||
|
use egui::accesskit;
|
||||||
|
use egui_kittest::Harness;
|
||||||
|
use egui_kittest::kittest::Queryable;
|
||||||
|
use tines_gui::config::fleet_dir;
|
||||||
|
use tines_gui::docker::ContainerId;
|
||||||
|
use tines_gui::fleet::Mode;
|
||||||
|
use tines_gui::launcher::{ContainerEntry, Launcher, LauncherAction};
|
||||||
|
|
||||||
|
/// The test-side action drain: peek at what the UI queued (main.rs owns the
|
||||||
|
/// real drain with the subprocess spawns).
|
||||||
|
fn drain(launcher: &mut Launcher) -> Vec<LauncherAction> {
|
||||||
|
launcher.actions.drain(..).collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn create_fleet_action_queues_spawn() {
|
||||||
|
common::env_with_fake_busd();
|
||||||
|
let mut harness = Harness::new_eframe(|_cc| Launcher::new());
|
||||||
|
harness.run();
|
||||||
|
|
||||||
|
// Type the fleet name into the first text field, then click Create.
|
||||||
|
harness
|
||||||
|
.get_all_by_role(accesskit::Role::TextInput)
|
||||||
|
.next()
|
||||||
|
.expect("fleet name field")
|
||||||
|
.focus();
|
||||||
|
harness.run();
|
||||||
|
harness
|
||||||
|
.get_all_by_role(accesskit::Role::TextInput)
|
||||||
|
.next()
|
||||||
|
.expect("fleet name field")
|
||||||
|
.type_text("yard");
|
||||||
|
harness.run();
|
||||||
|
harness.get_by_label("Create").click();
|
||||||
|
harness.run();
|
||||||
|
|
||||||
|
let launcher = harness.state();
|
||||||
|
assert!(
|
||||||
|
launcher.fleet.is_some(),
|
||||||
|
"Create must set the fleet (spawning the bus daemon)"
|
||||||
|
);
|
||||||
|
// The action queue must be drainable; fleet creation itself is not an
|
||||||
|
// action (it is the fleet field).
|
||||||
|
let launcher = harness.state_mut();
|
||||||
|
assert!(drain(launcher).is_empty());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn open_window_queues_spawn() {
|
||||||
|
common::env_with_fake_busd();
|
||||||
|
let mut harness = Harness::new_eframe(|_cc| {
|
||||||
|
let mut launcher = Launcher::new();
|
||||||
|
launcher.fleet_name = "yard".to_string();
|
||||||
|
launcher.containers.push(ContainerEntry {
|
||||||
|
name: "alpha".to_string(),
|
||||||
|
id: ContainerId("deadbeef".to_string()),
|
||||||
|
mode: Mode::Sim,
|
||||||
|
});
|
||||||
|
launcher
|
||||||
|
});
|
||||||
|
harness.run();
|
||||||
|
|
||||||
|
harness.get_by_label("Open").click();
|
||||||
|
harness.run();
|
||||||
|
|
||||||
|
let actions = drain(harness.state_mut());
|
||||||
|
assert_eq!(
|
||||||
|
actions,
|
||||||
|
vec![LauncherAction::OpenWindow {
|
||||||
|
name: "alpha".to_string(),
|
||||||
|
dir: fleet_dir("yard").join("alpha"),
|
||||||
|
id: ContainerId("deadbeef".to_string()),
|
||||||
|
mode: Mode::Sim,
|
||||||
|
}]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn stop_queues_stop_action() {
|
||||||
|
common::env_with_fake_busd();
|
||||||
|
let mut harness = Harness::new_eframe(|_cc| {
|
||||||
|
let mut launcher = Launcher::new();
|
||||||
|
launcher.containers.push(ContainerEntry {
|
||||||
|
name: "bravo".to_string(),
|
||||||
|
id: ContainerId("cafebabe".to_string()),
|
||||||
|
mode: Mode::Bt,
|
||||||
|
});
|
||||||
|
launcher
|
||||||
|
});
|
||||||
|
harness.run();
|
||||||
|
|
||||||
|
harness.get_by_label("Stop").click();
|
||||||
|
harness.run();
|
||||||
|
|
||||||
|
let actions = drain(harness.state_mut());
|
||||||
|
assert_eq!(
|
||||||
|
actions,
|
||||||
|
vec![LauncherAction::StopContainer(ContainerId(
|
||||||
|
"cafebabe".to_string()
|
||||||
|
))]
|
||||||
|
);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user