chore: merge release-v0.2.4 into main
This commit is contained in:
@@ -17,7 +17,7 @@
|
|||||||
"seccomp=unconfined"
|
"seccomp=unconfined"
|
||||||
],
|
],
|
||||||
|
|
||||||
"postCreateCommand": "cargo install cross typos-cli",
|
"postCreateCommand": "rustup target add x86_64-unknown-linux-musl && cargo install cross typos-cli",
|
||||||
|
|
||||||
"mounts": [
|
"mounts": [
|
||||||
"source=/etc/timezone,target=/etc/timezone,type=bind,readonly"
|
"source=/etc/timezone,target=/etc/timezone,type=bind,readonly"
|
||||||
|
|||||||
+22
-2
@@ -1,7 +1,27 @@
|
|||||||
### 2023-02-04
|
### 2023-03-02
|
||||||
|
|
||||||
|
### Chores
|
||||||
|
+ dependencies updated, [aac3ef2b1def3345d749d813d9b76020d6b5e5ca], [4723be7fb2eb101024bb9d5a514e2c6cc51eb6f6], [c69ab4f7c3b873f25ea46958add37be78d23e9cf], [ba6437862dae0f422660a602aeabd6217d023fac], [2bb4c338903e09856053894d9646307e31d32f1c]
|
||||||
|
+ dev container install x86 musl toolchain, [e650034d50f01a7598876d4f2887df691700e06a]
|
||||||
|
|
||||||
|
### Docs
|
||||||
|
+ typos removed, [23ad9a5fb3cacf3fb8cb70c65ca9133ed9949e45], [cebb975cb82f653407ec801fd8c726ca6ed68289], [fdc67c9249a239bac97a78b20c9378472865209c]
|
||||||
|
+ comments improved, [ec962295a8789ff8010604e974969bf618ea7108]
|
||||||
|
|
||||||
|
### Features
|
||||||
|
+ mouse capture is now more specific, should have substantial performance impact, 10x reduction in cpu usage when mouse is moved observed, as well as fixing intermittent mouse events output bug, [0a1b53111627206cc7436589e5b7212e1b72edb8], [93f7c07f708885f8870da5dfb6d57c62f93c9c78], [c74f6c1179b5f62989eb74f395a56b43a8781b03]
|
||||||
|
+ improve the styling of the help information popup, [28de74b866f07c8543e46be3cab929eff28953fd]
|
||||||
|
+ use checked_sub & checked_div for bounds checks, [72279e26ae996353c95a75527f704bac1e4bcf4d]
|
||||||
|
|
||||||
### Fixes
|
### Fixes
|
||||||
+ Container runner `FROM scratch` (missing from v0.2.2 D'oh), this now should actually reduce Docker image size by ~60%, [0bd317b7ce6f9f42a614c488099b5fc7a14d91c7]
|
+ correctly set gui error, [340893a860e99ec4029d12613f2a6de3cb7b47e2]
|
||||||
|
|
||||||
|
### Refactors
|
||||||
|
+ dead code removed, [b8f5792d1865d3a398cd7f23aa9473a55dc6ea44]
|
||||||
|
+ improve the get_width function, [04c26fe8fc7c79506921b9cff42825b1ee132737]
|
||||||
|
+ place ui methods into a Ui struct, [3437df59884f084624031fceb34ea3012a8e2251]
|
||||||
|
+ get_horizotal/vertical constraints into single method, [e8f5cf9c6f8cd5f807a05fb61e31d7cd1426486f]
|
||||||
|
+ docker update_everything variables, [074cb957f274675a468f08fecb1c43ff7453217d]
|
||||||
|
|
||||||
|
|
||||||
see <a href='https://github.com/mrjackwills/oxker/blob/main/CHANGELOG.md'>CHANGELOG.md</a> for more details
|
see <a href='https://github.com/mrjackwills/oxker/blob/main/CHANGELOG.md'>CHANGELOG.md</a> for more details
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ jobs:
|
|||||||
run: cargo install cross --git https://github.com/cross-rs/cross
|
run: cargo install cross --git https://github.com/cross-rs/cross
|
||||||
|
|
||||||
# Build for linux x86_64
|
# Build for linux x86_64
|
||||||
|
# Should this actually build for musl?
|
||||||
- name: build release linux_x86_64
|
- name: build release linux_x86_64
|
||||||
run: cargo build --release
|
run: cargo build --release
|
||||||
# Compress output into tar
|
# Compress output into tar
|
||||||
|
|||||||
@@ -1,3 +1,29 @@
|
|||||||
|
# <a href='https://github.com/mrjackwills/oxker/releases/tag/v0.2.4'>v0.2.4</a>
|
||||||
|
### 2023-03-02
|
||||||
|
|
||||||
|
### Chores
|
||||||
|
+ dependencies updated, [aac3ef2b](https://github.com/mrjackwills/oxker/commit/aac3ef2b1def3345d749d813d9b76020d6b5e5ca), [4723be7f](https://github.com/mrjackwills/oxker/commit/4723be7fb2eb101024bb9d5a514e2c6cc51eb6f6), [c69ab4f7](https://github.com/mrjackwills/oxker/commit/c69ab4f7c3b873f25ea46958add37be78d23e9cf), [ba643786](https://github.com/mrjackwills/oxker/commit/ba6437862dae0f422660a602aeabd6217d023fac), [2bb4c338](https://github.com/mrjackwills/oxker/commit/2bb4c338903e09856053894d9646307e31d32f1c)
|
||||||
|
+ dev container install x86 musl toolchain, [e650034d](https://github.com/mrjackwills/oxker/commit/e650034d50f01a7598876d4f2887df691700e06a)
|
||||||
|
|
||||||
|
### Docs
|
||||||
|
+ typos removed, [23ad9a5f](https://github.com/mrjackwills/oxker/commit/23ad9a5fb3cacf3fb8cb70c65ca9133ed9949e45), [cebb975c](https://github.com/mrjackwills/oxker/commit/cebb975cb82f653407ec801fd8c726ca6ed68289), [fdc67c92](https://github.com/mrjackwills/oxker/commit/fdc67c9249a239bac97a78b20c9378472865209c)
|
||||||
|
+ comments improved, [ec962295](https://github.com/mrjackwills/oxker/commit/ec962295a8789ff8010604e974969bf618ea7108)
|
||||||
|
|
||||||
|
### Features
|
||||||
|
+ mouse capture is now more specific, should have substantial performance impact, 10x reduction in cpu usage when mouse is moved observed, as well as fixing intermittent mouse events output bug, [0a1b5311](https://github.com/mrjackwills/oxker/commit/0a1b53111627206cc7436589e5b7212e1b72edb8), [93f7c07f](https://github.com/mrjackwills/oxker/commit/93f7c07f708885f8870da5dfb6d57c62f93c9c78), [c74f6c11](https://github.com/mrjackwills/oxker/commit/c74f6c1179b5f62989eb74f395a56b43a8781b03)
|
||||||
|
+ improve the styling of the help information popup, [28de74b8](https://github.com/mrjackwills/oxker/commit/28de74b866f07c8543e46be3cab929eff28953fd)
|
||||||
|
+ use checked_sub & checked_div for bounds checks, [72279e26](https://github.com/mrjackwills/oxker/commit/72279e26ae996353c95a75527f704bac1e4bcf4d)
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
+ correctly set gui error, [340893a8](https://github.com/mrjackwills/oxker/commit/340893a860e99ec4029d12613f2a6de3cb7b47e2)
|
||||||
|
|
||||||
|
### Refactors
|
||||||
|
+ dead code removed, [b8f5792d](https://github.com/mrjackwills/oxker/commit/b8f5792d1865d3a398cd7f23aa9473a55dc6ea44)
|
||||||
|
+ improve the get_width function, [04c26fe8](https://github.com/mrjackwills/oxker/commit/04c26fe8fc7c79506921b9cff42825b1ee132737)
|
||||||
|
+ place ui methods into a Ui struct, [3437df59](https://github.com/mrjackwills/oxker/commit/3437df59884f084624031fceb34ea3012a8e2251)
|
||||||
|
+ get_horizotal/vertical constraints into single method, [e8f5cf9c](https://github.com/mrjackwills/oxker/commit/e8f5cf9c6f8cd5f807a05fb61e31d7cd1426486f)
|
||||||
|
+ docker update_everything variables, [074cb957](https://github.com/mrjackwills/oxker/commit/074cb957f274675a468f08fecb1c43ff7453217d)
|
||||||
|
|
||||||
# <a href='https://github.com/mrjackwills/oxker/releases/tag/v0.2.3'>v0.2.3</a>
|
# <a href='https://github.com/mrjackwills/oxker/releases/tag/v0.2.3'>v0.2.3</a>
|
||||||
### 2023-02-04
|
### 2023-02-04
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -4,7 +4,7 @@ oxker encourages any, and all, suggestions, bug reports, pull requests, and/or f
|
|||||||
|
|
||||||
## Submitting Issues
|
## Submitting Issues
|
||||||
|
|
||||||
Please use the oxker [issue templates for](https://github.com/mrjackwills/oxker/issues/new/choose) any Bug Report, Feature Suggestions,
|
Please use the oxker [issue templates](https://github.com/mrjackwills/oxker/issues/new/choose) for any Bug Report, Feature Suggestions,
|
||||||
Refactor Idea, or Security Vulnerabilities.
|
Refactor Idea, or Security Vulnerabilities.
|
||||||
|
|
||||||
Don't hesitate to submit any issues or pull requests, regardless of size.
|
Don't hesitate to submit any issues or pull requests, regardless of size.
|
||||||
|
|||||||
Generated
+62
-76
@@ -13,9 +13,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anyhow"
|
name = "anyhow"
|
||||||
version = "1.0.68"
|
version = "1.0.69"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2cb2f989d18dd141ab8ae82f64d1a8cdd37e0840f73a406896cf5e99502fab61"
|
checksum = "224afbd727c3d6e4b90103ece64b8d1b67fbb1973b1046c2281eed3f3803f800"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "autocfg"
|
name = "autocfg"
|
||||||
@@ -131,9 +131,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap"
|
name = "clap"
|
||||||
version = "4.1.4"
|
version = "4.1.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f13b9c79b5d1dd500d20ef541215a6423c75829ef43117e1b4d17fd8af0b5d76"
|
checksum = "c3d7ae14b20b94cb02149ed21a86c423859cbe18dc7ed69845cace50e52b40a5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"clap_derive",
|
"clap_derive",
|
||||||
@@ -148,9 +148,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap_derive"
|
name = "clap_derive"
|
||||||
version = "4.1.0"
|
version = "4.1.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "684a277d672e91966334af371f1a7b5833f9aa00b07c84e92fbce95e00208ce8"
|
checksum = "44bec8e5c9d09e439c4335b1af0abaab56dcf3b94999a936e1bb47b9134288f0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"heck",
|
"heck",
|
||||||
"proc-macro-error",
|
"proc-macro-error",
|
||||||
@@ -161,9 +161,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap_lex"
|
name = "clap_lex"
|
||||||
version = "0.3.1"
|
version = "0.3.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "783fe232adfca04f90f56201b26d79682d4cd2625e0bc7290b95123afe558ade"
|
checksum = "350b9cf31731f9957399229e9b2adc51eeabdfbe9d71d9a0552275fd12710d09"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"os_str_bytes",
|
"os_str_bytes",
|
||||||
]
|
]
|
||||||
@@ -202,9 +202,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crossterm"
|
name = "crossterm"
|
||||||
version = "0.26.0"
|
version = "0.26.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "77f67c7faacd4db07a939f55d66a983a5355358a1f17d32cc9a8d01d1266b9ce"
|
checksum = "a84cda67535339806297f1b331d6dd6320470d2a0fe65381e79ee9e156dd3d13"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"crossterm_winapi",
|
"crossterm_winapi",
|
||||||
@@ -227,9 +227,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cxx"
|
name = "cxx"
|
||||||
version = "1.0.89"
|
version = "1.0.91"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bc831ee6a32dd495436e317595e639a587aa9907bef96fe6e6abc290ab6204e9"
|
checksum = "86d3488e7665a7a483b57e25bdd90d0aeb2bc7608c8d0346acf2ad3f1caf1d62"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cc",
|
"cc",
|
||||||
"cxxbridge-flags",
|
"cxxbridge-flags",
|
||||||
@@ -239,9 +239,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cxx-build"
|
name = "cxx-build"
|
||||||
version = "1.0.89"
|
version = "1.0.91"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "94331d54f1b1a8895cd81049f7eaaaef9d05a7dcb4d1fd08bf3ff0806246789d"
|
checksum = "48fcaf066a053a41a81dfb14d57d99738b767febb8b735c3016e469fac5da690"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cc",
|
"cc",
|
||||||
"codespan-reporting",
|
"codespan-reporting",
|
||||||
@@ -254,15 +254,15 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cxxbridge-flags"
|
name = "cxxbridge-flags"
|
||||||
version = "1.0.89"
|
version = "1.0.91"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "48dcd35ba14ca9b40d6e4b4b39961f23d835dbb8eed74565ded361d93e1feb8a"
|
checksum = "a2ef98b8b717a829ca5603af80e1f9e2e48013ab227b68ef37872ef84ee479bf"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cxxbridge-macro"
|
name = "cxxbridge-macro"
|
||||||
version = "1.0.89"
|
version = "1.0.91"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "81bbeb29798b407ccd82a3324ade1a7286e0d29851475990b612670f6f5124d2"
|
checksum = "086c685979a698443656e5cf7856c95c642295a38599f12fb1ff76fb28d19892"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -370,9 +370,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "h2"
|
name = "h2"
|
||||||
version = "0.3.15"
|
version = "0.3.16"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5f9f29bc9dda355256b2916cf526ab02ce0aeaaaf2bad60d65ef3f12f11dd0f4"
|
checksum = "5be7b54589b581f624f566bf5d8eb2bab1db736c51528720b6bd36b96b55924d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"fnv",
|
"fnv",
|
||||||
@@ -410,9 +410,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hermit-abi"
|
name = "hermit-abi"
|
||||||
version = "0.3.0"
|
version = "0.3.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "856b5cb0902c2b6d65d5fd97dfa30f9b70c7538e770b98eab5ed52d8db923e01"
|
checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hex"
|
name = "hex"
|
||||||
@@ -422,9 +422,9 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "http"
|
name = "http"
|
||||||
version = "0.2.8"
|
version = "0.2.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "75f43d41e26995c17e71ee126451dd3941010b0514a81a9d11f3b341debc2399"
|
checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"fnv",
|
"fnv",
|
||||||
@@ -543,19 +543,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "1abeb7a0dd0f8181267ff8adc397075586500b81b28a73e8a0208b00fc170fb3"
|
checksum = "1abeb7a0dd0f8181267ff8adc397075586500b81b28a73e8a0208b00fc170fb3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"windows-sys 0.45.0",
|
"windows-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "is-terminal"
|
name = "is-terminal"
|
||||||
version = "0.4.3"
|
version = "0.4.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "22e18b0a45d56fe973d6db23972bf5bc46f988a4a2385deac9cc29572f09daef"
|
checksum = "21b6b32576413a8e69b90e952e4a026476040d81017b80445deda5f2d3921857"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"hermit-abi 0.3.0",
|
"hermit-abi 0.3.1",
|
||||||
"io-lifetimes",
|
"io-lifetimes",
|
||||||
"rustix",
|
"rustix",
|
||||||
"windows-sys 0.45.0",
|
"windows-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -627,14 +627,14 @@ checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mio"
|
name = "mio"
|
||||||
version = "0.8.5"
|
version = "0.8.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e5d732bc30207a6423068df043e3d02e0735b155ad7ce1a6f76fe2baa5b158de"
|
checksum = "5b9d9a46eff5b4ff64b45a9e316a6d1e0bc719ef429cbec4dc630684212bfdf9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
"wasi",
|
"wasi",
|
||||||
"windows-sys 0.42.0",
|
"windows-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -678,9 +678,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "once_cell"
|
name = "once_cell"
|
||||||
version = "1.17.0"
|
version = "1.17.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66"
|
checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "os_str_bytes"
|
name = "os_str_bytes"
|
||||||
@@ -696,13 +696,13 @@ checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxker"
|
name = "oxker"
|
||||||
version = "0.2.3"
|
version = "0.2.4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"bollard",
|
"bollard",
|
||||||
"cansi",
|
"cansi",
|
||||||
"clap",
|
"clap",
|
||||||
"crossterm 0.26.0",
|
"crossterm 0.26.1",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"parking_lot",
|
"parking_lot",
|
||||||
"tokio",
|
"tokio",
|
||||||
@@ -732,7 +732,7 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
"redox_syscall",
|
"redox_syscall",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
"windows-sys 0.45.0",
|
"windows-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -805,9 +805,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.50"
|
version = "1.0.51"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6ef7d57beacfaf2d8aee5937dab7b7f28de3cb8b1828479bb5de2a7106f2bae2"
|
checksum = "5d727cae5b39d21da60fa540906919ad737832fe0b1c165da3a34d6548c849d6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
@@ -871,7 +871,7 @@ dependencies = [
|
|||||||
"io-lifetimes",
|
"io-lifetimes",
|
||||||
"libc",
|
"libc",
|
||||||
"linux-raw-sys",
|
"linux-raw-sys",
|
||||||
"windows-sys 0.45.0",
|
"windows-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -914,9 +914,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_json"
|
name = "serde_json"
|
||||||
version = "1.0.91"
|
version = "1.0.93"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "877c235533714907a8c2464236f5c4b2a17262ef1bd71f38f35ea592c8da6883"
|
checksum = "cad406b69c91885b5107daf2c29572f6c8cdb3c66826821e286c533490c0bc76"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"itoa",
|
"itoa",
|
||||||
"ryu",
|
"ryu",
|
||||||
@@ -972,9 +972,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "signal-hook"
|
name = "signal-hook"
|
||||||
version = "0.3.14"
|
version = "0.3.15"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a253b5e89e2698464fc26b545c9edceb338e18a89effeeecfea192c3025be29d"
|
checksum = "732768f1176d21d09e076c23a93123d40bba92d50c4058da34d45c8de8e682b9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"signal-hook-registry",
|
"signal-hook-registry",
|
||||||
@@ -993,18 +993,18 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "signal-hook-registry"
|
name = "signal-hook-registry"
|
||||||
version = "1.4.0"
|
version = "1.4.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0"
|
checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "slab"
|
name = "slab"
|
||||||
version = "0.4.7"
|
version = "0.4.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef"
|
checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"autocfg",
|
"autocfg",
|
||||||
]
|
]
|
||||||
@@ -1033,9 +1033,9 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "1.0.107"
|
version = "1.0.109"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5"
|
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -1073,18 +1073,19 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thread_local"
|
name = "thread_local"
|
||||||
version = "1.1.4"
|
version = "1.1.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180"
|
checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "time"
|
name = "time"
|
||||||
version = "0.3.17"
|
version = "0.3.20"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a561bf4617eebd33bca6434b988f39ed798e527f51a1e797d0ee4f61c0a38376"
|
checksum = "cd0cbfecb4d19b5ea75bb31ad904eb5b9fa13f21079c3b92017ebdf4999a5890"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"itoa",
|
"itoa",
|
||||||
"serde",
|
"serde",
|
||||||
@@ -1100,9 +1101,9 @@ checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "time-macros"
|
name = "time-macros"
|
||||||
version = "0.2.6"
|
version = "0.2.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d967f99f534ca7e495c575c62638eebc2898a8c84c119b89e250477bc4ba16b2"
|
checksum = "fd80a657e71da814b8e5d60d3374fc6d35045062245d80224748ae522dd76f36"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"time-core",
|
"time-core",
|
||||||
]
|
]
|
||||||
@@ -1124,9 +1125,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio"
|
name = "tokio"
|
||||||
version = "1.25.0"
|
version = "1.26.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c8e00990ebabbe4c14c08aca901caed183ecd5c09562a12c824bb53d3c3fd3af"
|
checksum = "03201d01c3c27a29c8a5cee5b55a93ddae1ccf6f08f65365c2c918f8c1b76f64"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"autocfg",
|
"autocfg",
|
||||||
"bytes",
|
"bytes",
|
||||||
@@ -1139,7 +1140,7 @@ dependencies = [
|
|||||||
"signal-hook-registry",
|
"signal-hook-registry",
|
||||||
"socket2",
|
"socket2",
|
||||||
"tokio-macros",
|
"tokio-macros",
|
||||||
"windows-sys 0.42.0",
|
"windows-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1155,9 +1156,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio-util"
|
name = "tokio-util"
|
||||||
version = "0.7.4"
|
version = "0.7.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0bb2e075f03b3d66d8d8785356224ba688d2906a371015e225beeb65ca92c740"
|
checksum = "5427d89453009325de0d8f342c9490009f76e999cb7672d77e46267448f7e6b2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"futures-core",
|
"futures-core",
|
||||||
@@ -1426,21 +1427,6 @@ version = "0.4.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows-sys"
|
|
||||||
version = "0.42.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7"
|
|
||||||
dependencies = [
|
|
||||||
"windows_aarch64_gnullvm",
|
|
||||||
"windows_aarch64_msvc",
|
|
||||||
"windows_i686_gnu",
|
|
||||||
"windows_i686_msvc",
|
|
||||||
"windows_x86_64_gnu",
|
|
||||||
"windows_x86_64_gnullvm",
|
|
||||||
"windows_x86_64_msvc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-sys"
|
name = "windows-sys"
|
||||||
version = "0.45.0"
|
version = "0.45.0"
|
||||||
|
|||||||
+2
-2
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "oxker"
|
name = "oxker"
|
||||||
version = "0.2.3"
|
version = "0.2.4"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
authors = ["Jack Wills <email@mrjackwills.com>"]
|
authors = ["Jack Wills <email@mrjackwills.com>"]
|
||||||
description = "A simple tui to view & control docker containers"
|
description = "A simple tui to view & control docker containers"
|
||||||
@@ -19,7 +19,7 @@ clap={version="4.1", features = ["derive", "unicode", "color"] }
|
|||||||
crossterm = "0.26"
|
crossterm = "0.26"
|
||||||
futures-util = "0.3"
|
futures-util = "0.3"
|
||||||
parking_lot = {version= "0.12"}
|
parking_lot = {version= "0.12"}
|
||||||
tokio = {version = "1.25", features=["full"]}
|
tokio = {version = "1.26", features=["full"]}
|
||||||
tracing = "0.1"
|
tracing = "0.1"
|
||||||
tracing-subscriber = "0.3"
|
tracing-subscriber = "0.3"
|
||||||
tui = "0.19"
|
tui = "0.19"
|
||||||
|
|||||||
@@ -21,34 +21,45 @@
|
|||||||
### Cargo
|
### Cargo
|
||||||
Published on <a href='https://www.crates.io/crates/oxker' target='_blank' rel='noopener noreferrer'>crates.io</a>, so if you have cargo installed, simply run
|
Published on <a href='https://www.crates.io/crates/oxker' target='_blank' rel='noopener noreferrer'>crates.io</a>, so if you have cargo installed, simply run
|
||||||
|
|
||||||
```cargo install oxker```
|
|
||||||
|
```shell
|
||||||
|
cargo install oxker
|
||||||
|
```
|
||||||
|
|
||||||
### Docker
|
### Docker
|
||||||
Published on <a href='https://hub.docker.com/r/mrjackwills/oxker' target='_blank' rel='noopener noreferrer'>Docker Hub</a>, with images built for `linux/amd64`, `linux/arm64`, and `linux/arm/v6`
|
Published on <a href='https://hub.docker.com/r/mrjackwills/oxker' target='_blank' rel='noopener noreferrer'>Docker Hub</a>, with images built for `linux/amd64`, `linux/arm64`, and `linux/arm/v6`
|
||||||
|
|
||||||
`docker run --rm -it -v /var/run/docker.sock:/var/run/docker.sock:ro --pull=always mrjackwills/oxker`
|
```shell
|
||||||
|
docker run --rm -it -v /var/run/docker.sock:/var/run/docker.sock:ro --pull=always mrjackwills/oxker
|
||||||
|
```
|
||||||
|
|
||||||
### Nix
|
### Nix
|
||||||
Using nix flakes, oxker can be ran directly with
|
Using nix flakes, oxker can be ran directly with
|
||||||
|
|
||||||
```nix run nixpkgs#oxker```
|
```shell
|
||||||
|
nix run nixpkgs#oxker
|
||||||
|
```
|
||||||
|
|
||||||
Without flakes, you can build a shell that contains oxker using
|
Without flakes, you can build a shell that contains oxker using
|
||||||
|
|
||||||
```nix-shell -p oxker```
|
```shell
|
||||||
|
nix-shell -p oxker
|
||||||
|
```
|
||||||
|
|
||||||
### AUR
|
### AUR
|
||||||
|
|
||||||
oxker can be installed from the [AUR](https://aur.archlinux.org/packages/oxker) with using an [AUR helper](https://wiki.archlinux.org/title/AUR_helpers):
|
oxker can be installed from the [AUR](https://aur.archlinux.org/packages/oxker) with using an [AUR helper](https://wiki.archlinux.org/title/AUR_helpers):
|
||||||
|
|
||||||
```paru -S oxker```
|
```shell
|
||||||
|
paru -S oxker
|
||||||
|
```
|
||||||
|
|
||||||
### Pre-Built
|
### Pre-Built
|
||||||
See the <a href="https://github.com/mrjackwills/oxker/releases/latest" target='_blank' rel='noopener noreferrer'>pre-built binaries</a>
|
See the <a href="https://github.com/mrjackwills/oxker/releases/latest" target='_blank' rel='noopener noreferrer'>pre-built binaries</a>
|
||||||
|
|
||||||
or, download & install (x86_64 one liner)
|
or, download & install (x86_64 one liner)
|
||||||
|
|
||||||
```bash
|
```shell
|
||||||
wget https://www.github.com/mrjackwills/oxker/releases/latest/download/oxker_linux_x86_64.tar.gz &&
|
wget https://www.github.com/mrjackwills/oxker/releases/latest/download/oxker_linux_x86_64.tar.gz &&
|
||||||
tar xzvf oxker_linux_x86_64.tar.gz oxker &&
|
tar xzvf oxker_linux_x86_64.tar.gz oxker &&
|
||||||
install -Dm 755 oxker -t "${HOME}/.local/bin" &&
|
install -Dm 755 oxker -t "${HOME}/.local/bin" &&
|
||||||
@@ -59,19 +70,21 @@ or, for automatic platform selection, download, and installation (to `$HOME/.loc
|
|||||||
|
|
||||||
*One should always verify script content before running in a shell*
|
*One should always verify script content before running in a shell*
|
||||||
|
|
||||||
```bash
|
```shell
|
||||||
curl https://raw.githubusercontent.com/mrjackwills/oxker/main/install.sh | bash
|
curl https://raw.githubusercontent.com/mrjackwills/oxker/main/install.sh | bash
|
||||||
```
|
```
|
||||||
|
|
||||||
## Run
|
## Run
|
||||||
|
|
||||||
```oxker```
|
```shell
|
||||||
|
oxker
|
||||||
|
```
|
||||||
|
|
||||||
In application controls
|
In application controls
|
||||||
| button| result|
|
| button| result|
|
||||||
|--|--|
|
|--|--|
|
||||||
| ```( tab )``` or ```( shift+tab )``` | change panel, clicking on a panel also changes the selected panel|
|
| ```( tab )``` or ```( shift+tab )``` | change panel, clicking on a panel also changes the selected panel|
|
||||||
| ```( ↑ ↓ )``` or ```( j k )``` or ```(PgUp PgDown)``` or ```(Home End)```| change selected line in selected panel, mouse scroll also changes selected line |
|
| ```( ↑ ↓ )``` or ```( j k )``` or ```( PgUp PgDown )``` or ```( Home End )```| change selected line in selected panel, mouse scroll also changes selected line |
|
||||||
| ```( enter )```| execute selected docker command|
|
| ```( enter )```| execute selected docker command|
|
||||||
| ```( 1-9 )``` | sort containers by heading, clicking on headings also sorts the selected column |
|
| ```( 1-9 )``` | sort containers by heading, clicking on headings also sorts the selected column |
|
||||||
| ```( 0 )``` | stop sorting |
|
| ```( 0 )``` | stop sorting |
|
||||||
@@ -94,7 +107,9 @@ Available command line arguments
|
|||||||
|
|
||||||
### x86_64
|
### x86_64
|
||||||
|
|
||||||
```cargo build --release```
|
```shell
|
||||||
|
cargo build --release
|
||||||
|
```
|
||||||
|
|
||||||
### Raspberry pi
|
### Raspberry pi
|
||||||
|
|
||||||
@@ -102,13 +117,17 @@ requires docker & <a href='https://github.com/cross-rs/cross' target='_blank' re
|
|||||||
|
|
||||||
#### 64bit pi (pi 4, pi zero w 2)
|
#### 64bit pi (pi 4, pi zero w 2)
|
||||||
|
|
||||||
```cross build --target aarch64-unknown-linux-gnu --release```
|
```shell
|
||||||
|
cross build --target aarch64-unknown-linux-gnu --release
|
||||||
|
```
|
||||||
|
|
||||||
#### 32bit pi (pi zero w)
|
#### 32bit pi (pi zero w)
|
||||||
|
|
||||||
Tested, and fully working on pi zero w, running Raspberry Pi OS 32 bit, the initial logs parsing can take an extended period of time if thousands of lines long, suggest running with a -d argument of 5000
|
Tested, and fully working on pi zero w, running Raspberry Pi OS 32 bit, the initial logs parsing can take an extended period of time if thousands of lines long, suggest running with a -d argument of 5000
|
||||||
|
|
||||||
```cross build --target arm-unknown-linux-musleabihf --release```
|
```shell
|
||||||
|
cross build --target arm-unknown-linux-musleabihf --release
|
||||||
|
```
|
||||||
|
|
||||||
If no memory information available, try appending ```/boot/cmdline.txt``` with
|
If no memory information available, try appending ```/boot/cmdline.txt``` with
|
||||||
|
|
||||||
@@ -122,18 +141,28 @@ see <a href="https://forums.raspberrypi.com/viewtopic.php?t=203128" target='_bla
|
|||||||
|
|
||||||
As of yet untested, needs work
|
As of yet untested, needs work
|
||||||
|
|
||||||
```cargo test -- --test-threads=1```
|
```shell
|
||||||
|
cargo test -- --test-threads=1
|
||||||
|
```
|
||||||
|
|
||||||
Run some example docker images
|
Run some example docker images
|
||||||
|
|
||||||
using docker-compose.yml;
|
using docker-compose.yml;
|
||||||
|
|
||||||
```docker compose -f docker-compose.yml up -d```
|
```shell
|
||||||
|
docker compose -f docker-compose.yml up -d
|
||||||
|
```
|
||||||
|
|
||||||
or individually
|
or individually
|
||||||
|
|
||||||
```docker run --name redis -d redis:alpine3.17```
|
```shell
|
||||||
|
docker run --name redis -d redis:alpine3.17
|
||||||
|
```
|
||||||
|
|
||||||
```docker run --name postgres -e POSTGRES_PASSWORD=never_use_this_password_in_production -d postgres:alpine3.17```
|
```shell
|
||||||
|
docker run --name postgres -e POSTGRES_PASSWORD=never_use_this_password_in_production -d postgres:alpine3.17
|
||||||
|
```
|
||||||
|
|
||||||
```docker run -d --hostname my-rabbit --name rabbitmq rabbitmq:3```
|
```shell
|
||||||
|
docker run -d --hostname my-rabbit --name rabbitmq rabbitmq:3
|
||||||
|
```
|
||||||
|
|||||||
@@ -58,5 +58,5 @@ ENV OXKER_RUNTIME=container
|
|||||||
COPY --from=BUILDER /oxker /app/
|
COPY --from=BUILDER /oxker /app/
|
||||||
|
|
||||||
# Run the application
|
# Run the application
|
||||||
# this is used in the application itself, to stop itself show when running from a docker container, so DO NOT EDIT
|
# this is used in the application itself, to stop itself from listing itself, so DO NOT EDIT
|
||||||
ENTRYPOINT [ "./app/oxker"]
|
ENTRYPOINT [ "/app/oxker"]
|
||||||
|
|||||||
@@ -11,10 +11,10 @@ COPY ./target/x86_64-unknown-linux-musl/release/oxker /app/
|
|||||||
|
|
||||||
# Run the application
|
# Run the application
|
||||||
# this is used in the application itself, to stop itself show when running from a docker container, so DO NOT EDIT
|
# this is used in the application itself, to stop itself show when running from a docker container, so DO NOT EDIT
|
||||||
ENTRYPOINT [ "./app/oxker"]
|
ENTRYPOINT [ "/app/oxker"]
|
||||||
|
|
||||||
# Dev build for testing
|
# Dev build for testing
|
||||||
# docker build -t oxker_dev -f Dockerfile . && docker run --rm -it --volume /var/run/docker.sock:/var/run/docker.sock:ro oxker_dev
|
# docker build -t oxker_dev -f containerised/Dockerfile_dev . && docker run --rm -it --volume /var/run/docker.sock:/var/run/docker.sock:ro oxker_dev
|
||||||
|
|
||||||
# Dev build one liner, x86 host
|
# Dev build one liner, x86 host
|
||||||
# docker image prune -a; cargo build --release --target x86_64-unknown-linux-musl && docker build -t oxker_dev -f containerised/Dockerfile_dev . && docker run --rm -it --volume /var/run/docker.sock:/var/run/docker.sock:ro oxker_dev
|
# docker image prune -a; cargo build --release --target x86_64-unknown-linux-musl && docker build -t oxker_dev -f containerised/Dockerfile_dev . && docker run --rm -it --volume /var/run/docker.sock:/var/run/docker.sock:ro oxker_dev
|
||||||
|
|||||||
+3
-1
@@ -1,7 +1,7 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
# rust create_release
|
# rust create_release
|
||||||
# v0.2.1
|
# v0.2.2
|
||||||
|
|
||||||
STAR_LINE='****************************************'
|
STAR_LINE='****************************************'
|
||||||
CWD=$(pwd)
|
CWD=$(pwd)
|
||||||
@@ -231,6 +231,8 @@ release_flow() {
|
|||||||
|
|
||||||
echo -e "\ncargo fmt"
|
echo -e "\ncargo fmt"
|
||||||
cargo fmt
|
cargo fmt
|
||||||
|
echo -e "\n${PURPLE}cargo check${RESET}\n"
|
||||||
|
cargo check
|
||||||
|
|
||||||
release_continue "git add ."
|
release_continue "git add ."
|
||||||
git add .
|
git add .
|
||||||
|
|||||||
@@ -142,7 +142,7 @@ impl State {
|
|||||||
_ => Color::Red,
|
_ => Color::Red,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Dirty way to create order for the state, rather than impl Ord
|
/// Dirty way to create order for the state, rather than impl Ord
|
||||||
pub const fn order(self) -> u8 {
|
pub const fn order(self) -> u8 {
|
||||||
match self {
|
match self {
|
||||||
Self::Running => 0,
|
Self::Running => 0,
|
||||||
|
|||||||
+11
-38
@@ -203,7 +203,7 @@ impl AppData {
|
|||||||
self.containers.start();
|
self.containers.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
// select the last container
|
/// select the last container
|
||||||
pub fn containers_end(&mut self) {
|
pub fn containers_end(&mut self) {
|
||||||
self.containers.end();
|
self.containers.end();
|
||||||
}
|
}
|
||||||
@@ -213,7 +213,7 @@ impl AppData {
|
|||||||
self.containers.next();
|
self.containers.next();
|
||||||
}
|
}
|
||||||
|
|
||||||
// select the previous container
|
/// select the previous container
|
||||||
pub fn containers_previous(&mut self) {
|
pub fn containers_previous(&mut self) {
|
||||||
self.containers.previous();
|
self.containers.previous();
|
||||||
}
|
}
|
||||||
@@ -428,12 +428,6 @@ impl AppData {
|
|||||||
.to_string(),
|
.to_string(),
|
||||||
);
|
);
|
||||||
|
|
||||||
let rx_count = count(&container.rx.to_string());
|
|
||||||
let tx_count = count(&container.tx.to_string());
|
|
||||||
let image_count = count(&container.image);
|
|
||||||
let name_count = count(&container.name);
|
|
||||||
let state_count = count(&container.state.to_string());
|
|
||||||
let status_count = count(&container.status);
|
|
||||||
let mem_current_count = count(
|
let mem_current_count = count(
|
||||||
&container
|
&container
|
||||||
.mem_stats
|
.mem_stats
|
||||||
@@ -441,35 +435,16 @@ impl AppData {
|
|||||||
.unwrap_or(&ByteStats::default())
|
.unwrap_or(&ByteStats::default())
|
||||||
.to_string(),
|
.to_string(),
|
||||||
);
|
);
|
||||||
let mem_limit_count = count(&container.mem_limit.to_string());
|
|
||||||
|
|
||||||
if cpu_count > columns.cpu.1 {
|
columns.cpu.1 = columns.cpu.1.max(cpu_count);
|
||||||
columns.cpu.1 = cpu_count;
|
columns.image.1 = columns.image.1.max(count(&container.image));
|
||||||
};
|
columns.mem.1 = columns.mem.1.max(mem_current_count);
|
||||||
if image_count > columns.image.1 {
|
columns.mem.2 = columns.mem.2.max(count(&container.mem_limit.to_string()));
|
||||||
columns.image.1 = image_count;
|
columns.name.1 = columns.name.1.max(count(&container.name));
|
||||||
};
|
columns.net_rx.1 = columns.net_rx.1.max(count(&container.rx.to_string()));
|
||||||
if mem_current_count > columns.mem.1 {
|
columns.net_tx.1 = columns.net_tx.1.max(count(&container.tx.to_string()));
|
||||||
columns.mem.1 = mem_current_count;
|
columns.state.1 = columns.state.1.max(count(&container.state.to_string()));
|
||||||
};
|
columns.status.1 = columns.status.1.max(count(&container.status));
|
||||||
if mem_limit_count > columns.mem.2 {
|
|
||||||
columns.mem.2 = mem_limit_count;
|
|
||||||
};
|
|
||||||
if name_count > columns.name.1 {
|
|
||||||
columns.name.1 = name_count;
|
|
||||||
};
|
|
||||||
if state_count > columns.state.1 {
|
|
||||||
columns.state.1 = state_count;
|
|
||||||
};
|
|
||||||
if status_count > columns.status.1 {
|
|
||||||
columns.status.1 = status_count;
|
|
||||||
};
|
|
||||||
if rx_count > columns.net_rx.1 {
|
|
||||||
columns.net_rx.1 = rx_count;
|
|
||||||
};
|
|
||||||
if tx_count > columns.net_tx.1 {
|
|
||||||
columns.net_tx.1 = tx_count;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
columns
|
columns
|
||||||
}
|
}
|
||||||
@@ -519,9 +494,7 @@ impl AppData {
|
|||||||
container.mem_limit.update(mem_limit);
|
container.mem_limit.update(mem_limit);
|
||||||
}
|
}
|
||||||
// need to benchmark this?
|
// need to benchmark this?
|
||||||
// if self.get_sorted().is_some() {
|
|
||||||
self.sort_containers();
|
self.sort_containers();
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Update, or insert, containers
|
/// Update, or insert, containers
|
||||||
|
|||||||
+8
-11
@@ -7,10 +7,7 @@ use futures_util::StreamExt;
|
|||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use std::{
|
use std::{
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
sync::{
|
sync::{atomic::AtomicBool, Arc},
|
||||||
atomic::{AtomicBool, Ordering},
|
|
||||||
Arc,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
use tokio::{sync::mpsc::Receiver, task::JoinHandle};
|
use tokio::{sync::mpsc::Receiver, task::JoinHandle};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
@@ -34,7 +31,7 @@ enum SpawnId {
|
|||||||
/// Cpu & Mem stats take twice as long as the update interval to get a value, so will have two being executed at the same time
|
/// Cpu & Mem stats take twice as long as the update interval to get a value, so will have two being executed at the same time
|
||||||
/// SpawnId::Stats takes container_id and binate value to enable both cycles of the same container_id to be inserted into the hashmap
|
/// SpawnId::Stats takes container_id and binate value to enable both cycles of the same container_id to be inserted into the hashmap
|
||||||
/// Binate value is toggled when all handles have been spawned off
|
/// Binate value is toggled when all handles have been spawned off
|
||||||
/// Also effectively means that if the docker_update interval minimum will be 1000ms
|
/// Also effectively means that the docker_update interval minimum will be 1000ms
|
||||||
#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq)]
|
#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq)]
|
||||||
enum Binate {
|
enum Binate {
|
||||||
One,
|
One,
|
||||||
@@ -176,7 +173,7 @@ impl DockerData {
|
|||||||
|
|
||||||
/// Get all current containers, handle into ContainerItem in the app_data struct rather than here
|
/// Get all current containers, handle into ContainerItem in the app_data struct rather than here
|
||||||
/// Just make sure that items sent are guaranteed to have an id
|
/// Just make sure that items sent are guaranteed to have an id
|
||||||
/// If in a containerised runtime, will ignore any container that uses the q`./app/oxker` as an entry point, unless the `-s` flag is set
|
/// If in a containerised runtime, will ignore any container that uses the `/app/oxker` as an entry point, unless the `-s` flag is set
|
||||||
pub async fn update_all_containers(&mut self) -> Vec<(bool, ContainerId)> {
|
pub async fn update_all_containers(&mut self) -> Vec<(bool, ContainerId)> {
|
||||||
let containers = self
|
let containers = self
|
||||||
.docker
|
.docker
|
||||||
@@ -270,14 +267,14 @@ impl DockerData {
|
|||||||
async fn update_everything(&mut self) {
|
async fn update_everything(&mut self) {
|
||||||
let all_ids = self.update_all_containers().await;
|
let all_ids = self.update_all_containers().await;
|
||||||
if let Some(container) = self.app_data.lock().get_selected_container() {
|
if let Some(container) = self.app_data.lock().get_selected_container() {
|
||||||
let id = container.id.clone();
|
|
||||||
let last_updated = container.last_updated;
|
let last_updated = container.last_updated;
|
||||||
self.spawns
|
self.spawns
|
||||||
.lock()
|
.lock()
|
||||||
.entry(SpawnId::Log(id.clone()))
|
.entry(SpawnId::Log(container.id.clone()))
|
||||||
.or_insert_with(|| {
|
.or_insert_with(|| {
|
||||||
let docker = Arc::clone(&self.docker);
|
|
||||||
let app_data = Arc::clone(&self.app_data);
|
let app_data = Arc::clone(&self.app_data);
|
||||||
|
let docker = Arc::clone(&self.docker);
|
||||||
|
let id = container.id.clone();
|
||||||
let spawns = Arc::clone(&self.spawns);
|
let spawns = Arc::clone(&self.spawns);
|
||||||
tokio::spawn(Self::update_log(app_data, docker, id, last_updated, spawns))
|
tokio::spawn(Self::update_log(app_data, docker, id, last_updated, spawns))
|
||||||
});
|
});
|
||||||
@@ -407,7 +404,8 @@ impl DockerData {
|
|||||||
.values()
|
.values()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.for_each(tokio::task::JoinHandle::abort);
|
.for_each(tokio::task::JoinHandle::abort);
|
||||||
self.is_running.store(false, Ordering::SeqCst);
|
self.is_running
|
||||||
|
.store(false, std::sync::atomic::Ordering::SeqCst);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -436,7 +434,6 @@ impl DockerData {
|
|||||||
spawns: Arc::new(Mutex::new(HashMap::new())),
|
spawns: Arc::new(Mutex::new(HashMap::new())),
|
||||||
};
|
};
|
||||||
inner.initialise_container_data().await;
|
inner.initialise_container_data().await;
|
||||||
|
|
||||||
inner.message_handler().await;
|
inner.message_handler().await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+18
-23
@@ -4,9 +4,7 @@ use std::sync::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use crossterm::{
|
use crossterm::{
|
||||||
event::{
|
event::{DisableMouseCapture, KeyCode, MouseButton, MouseEvent, MouseEventKind},
|
||||||
DisableMouseCapture, EnableMouseCapture, KeyCode, MouseButton, MouseEvent, MouseEventKind,
|
|
||||||
},
|
|
||||||
execute,
|
execute,
|
||||||
};
|
};
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
@@ -21,7 +19,7 @@ use crate::{
|
|||||||
app_data::{AppData, DockerControls, Header},
|
app_data::{AppData, DockerControls, Header},
|
||||||
app_error::AppError,
|
app_error::AppError,
|
||||||
docker_data::DockerMessage,
|
docker_data::DockerMessage,
|
||||||
ui::{GuiState, SelectablePanel, Status},
|
ui::{GuiState, SelectablePanel, Status, Ui},
|
||||||
};
|
};
|
||||||
pub use message::InputMessages;
|
pub use message::InputMessages;
|
||||||
|
|
||||||
@@ -82,27 +80,23 @@ impl InputHandler {
|
|||||||
/// Toggle the mouse capture (via input of the 'm' key)
|
/// Toggle the mouse capture (via input of the 'm' key)
|
||||||
fn m_key(&mut self) {
|
fn m_key(&mut self) {
|
||||||
if self.mouse_capture {
|
if self.mouse_capture {
|
||||||
match execute!(std::io::stdout(), DisableMouseCapture) {
|
if execute!(std::io::stdout(), DisableMouseCapture).is_ok() {
|
||||||
Ok(_) => self
|
self.gui_state
|
||||||
.gui_state
|
|
||||||
.lock()
|
.lock()
|
||||||
.set_info_box("✖ mouse capture disabled".to_owned()),
|
.set_info_box("✖ mouse capture disabled".to_owned());
|
||||||
Err(_) => {
|
} else {
|
||||||
self.app_data
|
self.app_data
|
||||||
.lock()
|
.lock()
|
||||||
.set_error(AppError::MouseCapture(false));
|
.set_error(AppError::MouseCapture(false));
|
||||||
}
|
self.gui_state.lock().status_push(Status::Error);
|
||||||
}
|
}
|
||||||
|
} else if Ui::enable_mouse_capture().is_ok() {
|
||||||
|
self.gui_state
|
||||||
|
.lock()
|
||||||
|
.set_info_box("✓ mouse capture enabled".to_owned());
|
||||||
} else {
|
} else {
|
||||||
match execute!(std::io::stdout(), EnableMouseCapture) {
|
self.app_data.lock().set_error(AppError::MouseCapture(true));
|
||||||
Ok(_) => self
|
self.gui_state.lock().status_push(Status::Error);
|
||||||
.gui_state
|
|
||||||
.lock()
|
|
||||||
.set_info_box("✓ mouse capture enabled".to_owned()),
|
|
||||||
Err(_) => {
|
|
||||||
self.app_data.lock().set_error(AppError::MouseCapture(true));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// If the info box sleep handle is currently being executed, as in 'm' is pressed twice within a 4000ms window
|
// If the info box sleep handle is currently being executed, as in 'm' is pressed twice within a 4000ms window
|
||||||
@@ -134,7 +128,8 @@ impl InputHandler {
|
|||||||
.lock()
|
.lock()
|
||||||
.status_contains(&[Status::Error, Status::Init]);
|
.status_contains(&[Status::Error, Status::Init]);
|
||||||
if error_init || self.docker_sender.send(DockerMessage::Quit).await.is_err() {
|
if error_init || self.docker_sender.send(DockerMessage::Quit).await.is_err() {
|
||||||
self.is_running.store(false, Ordering::SeqCst);
|
self.is_running
|
||||||
|
.store(false, std::sync::atomic::Ordering::SeqCst);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+5
-7
@@ -1,13 +1,13 @@
|
|||||||
#![forbid(unsafe_code)]
|
#![forbid(unsafe_code)]
|
||||||
#![warn(
|
#![warn(
|
||||||
|
clippy::nursery,
|
||||||
|
clippy::pedantic,
|
||||||
clippy::expect_used,
|
clippy::expect_used,
|
||||||
clippy::todo,
|
clippy::todo,
|
||||||
clippy::unused_async,
|
clippy::unused_async,
|
||||||
clippy::unwrap_used
|
clippy::unwrap_used
|
||||||
)]
|
)]
|
||||||
// Warning - These are indeed pedantic
|
// Warning - These are indeed pedantic
|
||||||
#![warn(clippy::pedantic)]
|
|
||||||
#![warn(clippy::nursery)]
|
|
||||||
#![allow(
|
#![allow(
|
||||||
clippy::module_name_repetitions,
|
clippy::module_name_repetitions,
|
||||||
clippy::doc_markdown,
|
clippy::doc_markdown,
|
||||||
@@ -34,12 +34,12 @@ mod input_handler;
|
|||||||
mod parse_args;
|
mod parse_args;
|
||||||
mod ui;
|
mod ui;
|
||||||
|
|
||||||
use ui::{create_ui, GuiState, Status};
|
use ui::{GuiState, Status, Ui};
|
||||||
|
|
||||||
use crate::docker_data::DockerMessage;
|
use crate::docker_data::DockerMessage;
|
||||||
|
|
||||||
// this is the entry point when running as a Docker Container, and is used, in conjunction with the `CONTAINER_ENV` ENV, to check if we are running as a Docker Container
|
// this is the entry point when running as a Docker Container, and is used, in conjunction with the `CONTAINER_ENV` ENV, to check if we are running as a Docker Container
|
||||||
const ENTRY_POINT: &str = "./app/oxker";
|
const ENTRY_POINT: &str = "/app/oxker";
|
||||||
const ENV_KEY: &str = "OXKER_RUNTIME";
|
const ENV_KEY: &str = "OXKER_RUNTIME";
|
||||||
const ENV_VALUE: &str = "container";
|
const ENV_VALUE: &str = "container";
|
||||||
|
|
||||||
@@ -132,9 +132,7 @@ async fn main() {
|
|||||||
handler_init(&app_data, &docker_sx, &gui_state, input_rx, &is_running);
|
handler_init(&app_data, &docker_sx, &gui_state, input_rx, &is_running);
|
||||||
|
|
||||||
if args.gui {
|
if args.gui {
|
||||||
create_ui(app_data, docker_sx, gui_state, is_running, input_sx)
|
Ui::create(app_data, docker_sx, gui_state, is_running, input_sx).await;
|
||||||
.await
|
|
||||||
.unwrap_or(());
|
|
||||||
} else {
|
} else {
|
||||||
// Debug mode for testing, mostly pointless, doesn't take terminal
|
// Debug mode for testing, mostly pointless, doesn't take terminal
|
||||||
info!("in debug mode");
|
info!("in debug mode");
|
||||||
|
|||||||
+234
-66
@@ -481,93 +481,253 @@ pub fn heading_bar<B: Backend>(
|
|||||||
|
|
||||||
/// From a given &str, return the maximum number of chars on a single line
|
/// From a given &str, return the maximum number of chars on a single line
|
||||||
fn max_line_width(text: &str) -> usize {
|
fn max_line_width(text: &str) -> usize {
|
||||||
let mut max_line_width = 0;
|
text.lines()
|
||||||
text.lines().into_iter().for_each(|line| {
|
.into_iter()
|
||||||
let width = line.chars().count();
|
.map(|i| i.chars().count())
|
||||||
if width > max_line_width {
|
.max()
|
||||||
max_line_width = width;
|
.unwrap_or_default()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Help popup box needs these three pieces of information
|
||||||
|
struct HelpInfo {
|
||||||
|
spans: Vec<Spans<'static>>,
|
||||||
|
width: usize,
|
||||||
|
height: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HelpInfo {
|
||||||
|
/// Find the max width of a Span in &[Spans], although it isn't calculating it correctly
|
||||||
|
fn calc_width(spans: &[Spans]) -> usize {
|
||||||
|
spans
|
||||||
|
.iter()
|
||||||
|
.flat_map(|x| x.0.iter())
|
||||||
|
.map(tui::text::Span::width)
|
||||||
|
.max()
|
||||||
|
.unwrap_or(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Just an empty span, i.e. a new line
|
||||||
|
fn empty_span<'a>() -> Spans<'a> {
|
||||||
|
Spans::from(String::new())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// generate a span, of given &str and given color
|
||||||
|
fn span<'a>(input: &str, color: Color) -> Span<'a> {
|
||||||
|
Span::styled(input.to_owned(), Style::default().fg(color))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Span to black text span
|
||||||
|
fn black_span<'a>(input: &str) -> Span<'a> {
|
||||||
|
Self::span(input, Color::Black)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Span to white text span
|
||||||
|
fn white_span<'a>(input: &str) -> Span<'a> {
|
||||||
|
Self::span(input, Color::White)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Generate the `oxker` name span + metadata
|
||||||
|
fn gen_name() -> Self {
|
||||||
|
let mut spans = NAME_TEXT
|
||||||
|
.lines()
|
||||||
|
.into_iter()
|
||||||
|
.map(|i| Spans::from(Self::white_span(i)))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
spans.insert(0, Self::empty_span());
|
||||||
|
let width = Self::calc_width(&spans);
|
||||||
|
let height = spans.len();
|
||||||
|
Self {
|
||||||
|
spans,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
max_line_width
|
|
||||||
|
/// Generate the description span + metadata
|
||||||
|
fn gen_description() -> Self {
|
||||||
|
let spans = [
|
||||||
|
Self::empty_span(),
|
||||||
|
Spans::from(Self::white_span(DESCRIPTION)),
|
||||||
|
Self::empty_span(),
|
||||||
|
];
|
||||||
|
let width = Self::calc_width(&spans);
|
||||||
|
let height = spans.len();
|
||||||
|
Self {
|
||||||
|
spans: spans.to_vec(),
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Generate the button information span + metadata
|
||||||
|
fn gen_button() -> Self {
|
||||||
|
let button_item = |x: &str| Self::white_span(&format!(" {x} "));
|
||||||
|
let button_desc = |x: &str| Self::black_span(x);
|
||||||
|
let or = || button_desc("or");
|
||||||
|
let space = || button_desc(" ");
|
||||||
|
|
||||||
|
let spans = [
|
||||||
|
Spans::from(vec![
|
||||||
|
space(),
|
||||||
|
button_item("( tab )"),
|
||||||
|
or(),
|
||||||
|
button_item("( shift+tab )"),
|
||||||
|
button_desc("to change panels"),
|
||||||
|
]),
|
||||||
|
Spans::from(vec![
|
||||||
|
space(),
|
||||||
|
button_item("( ↑ ↓ )"),
|
||||||
|
or(),
|
||||||
|
button_item("( j k )"),
|
||||||
|
or(),
|
||||||
|
button_item("( PgUp PgDown )"),
|
||||||
|
or(),
|
||||||
|
button_item("( Home End )"),
|
||||||
|
button_desc("to change selected line"),
|
||||||
|
]),
|
||||||
|
Spans::from(vec![
|
||||||
|
space(),
|
||||||
|
button_item("( enter )"),
|
||||||
|
button_desc("to send docker container command"),
|
||||||
|
]),
|
||||||
|
Spans::from(vec![
|
||||||
|
space(),
|
||||||
|
button_item("( h )"),
|
||||||
|
button_desc("to toggle this help information"),
|
||||||
|
]),
|
||||||
|
Spans::from(vec![
|
||||||
|
space(),
|
||||||
|
button_item("( 0 )"),
|
||||||
|
button_desc("to stop sort"),
|
||||||
|
]),
|
||||||
|
Spans::from(vec![
|
||||||
|
space(),
|
||||||
|
button_item("( 1 - 9 )"),
|
||||||
|
button_desc("sort by header - or click header"),
|
||||||
|
]),
|
||||||
|
Spans::from(vec![
|
||||||
|
space(),
|
||||||
|
button_item("( m )"),
|
||||||
|
button_desc(
|
||||||
|
"to toggle mouse capture - if disabled, text on screen can be selected & copied",
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
Spans::from(vec![
|
||||||
|
space(),
|
||||||
|
button_item("( q )"),
|
||||||
|
button_desc("to quit at any time"),
|
||||||
|
]),
|
||||||
|
];
|
||||||
|
|
||||||
|
let height = spans.len();
|
||||||
|
let width = Self::calc_width(&spans);
|
||||||
|
Self {
|
||||||
|
spans: spans.to_vec(),
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Generate the final lines, GitHub link etc, + metadata
|
||||||
|
fn gen_final() -> Self {
|
||||||
|
let spans = [
|
||||||
|
Self::empty_span(),
|
||||||
|
Spans::from(vec![Self::black_span(
|
||||||
|
"currently an early work in progress, all and any input appreciated",
|
||||||
|
)]),
|
||||||
|
Spans::from(vec![Span::styled(
|
||||||
|
REPO.to_owned(),
|
||||||
|
Style::default()
|
||||||
|
.bg(Color::Magenta)
|
||||||
|
.fg(Color::Black)
|
||||||
|
.add_modifier(Modifier::UNDERLINED),
|
||||||
|
)]),
|
||||||
|
];
|
||||||
|
let height = spans.len();
|
||||||
|
let width = Self::calc_width(&spans);
|
||||||
|
Self {
|
||||||
|
spans: spans.to_vec(),
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Draw the help box in the centre of the screen
|
/// Draw the help box in the centre of the screen
|
||||||
/// TODO should make every line it's own renderable span
|
|
||||||
pub fn help_box<B: Backend>(f: &mut Frame<'_, B>) {
|
pub fn help_box<B: Backend>(f: &mut Frame<'_, B>) {
|
||||||
let title = format!(" {VERSION} ");
|
let title = format!(" {VERSION} ");
|
||||||
|
|
||||||
let description_text = format!("\n{DESCRIPTION}");
|
let name_info = HelpInfo::gen_name();
|
||||||
|
let description_info = HelpInfo::gen_description();
|
||||||
|
let button_info = HelpInfo::gen_button();
|
||||||
|
let final_info = HelpInfo::gen_final();
|
||||||
|
|
||||||
let mut help_text = String::from("\n ( tab ) or ( shift+tab ) to change panels");
|
// have to add 10, but shouldn't need to, is an error somewhere
|
||||||
help_text
|
let max_line_width = [
|
||||||
.push_str("\n ( ↑ ↓ ) or ( j k ) or (PgUp PgDown) or (Home End) to change selected line");
|
name_info.width,
|
||||||
help_text.push_str("\n ( enter ) to send docker container commands");
|
description_info.width,
|
||||||
help_text.push_str("\n ( h ) to toggle this help information");
|
button_info.width,
|
||||||
help_text.push_str("\n ( 0 ) stop sort");
|
final_info.width,
|
||||||
help_text.push_str("\n ( 1 - 9 ) sort by header - or click header");
|
]
|
||||||
help_text.push_str(
|
.into_iter()
|
||||||
"\n ( m ) to toggle mouse capture - if disabled, text on screen can be selected & copied",
|
.max()
|
||||||
|
.unwrap_or_default()
|
||||||
|
+ 10;
|
||||||
|
let max_height =
|
||||||
|
name_info.height + description_info.height + button_info.height + final_info.height + 2;
|
||||||
|
|
||||||
|
let area = popup(
|
||||||
|
max_height,
|
||||||
|
max_line_width,
|
||||||
|
f.size(),
|
||||||
|
BoxLocation::MiddleCentre,
|
||||||
);
|
);
|
||||||
help_text.push_str("\n ( q ) to quit at any time");
|
|
||||||
help_text.push_str("\n mouse scrolling & clicking also available");
|
|
||||||
help_text.push_str("\n\n currently an early work in progress, all and any input appreciated");
|
|
||||||
help_text.push_str(format!("\n {}", REPO.trim()).as_str());
|
|
||||||
|
|
||||||
// Find the maximum line widths & height
|
let split_popup = Layout::default()
|
||||||
let all_text = format!("{NAME_TEXT}{description_text}{help_text}");
|
.direction(Direction::Vertical)
|
||||||
let mut max_line_width = max_line_width(&all_text);
|
.constraints(
|
||||||
let mut lines = all_text.lines().count();
|
[
|
||||||
|
Constraint::Max(name_info.height.try_into().unwrap_or_default()),
|
||||||
|
Constraint::Max(description_info.height.try_into().unwrap_or_default()),
|
||||||
|
Constraint::Max(button_info.height.try_into().unwrap_or_default()),
|
||||||
|
Constraint::Max(final_info.height.try_into().unwrap_or_default()),
|
||||||
|
]
|
||||||
|
.as_ref(),
|
||||||
|
)
|
||||||
|
.split(area);
|
||||||
|
|
||||||
// Add some vertical and horizontal padding to the info box
|
let name_paragraph = Paragraph::new(name_info.spans)
|
||||||
lines += 3;
|
|
||||||
max_line_width += 4;
|
|
||||||
|
|
||||||
let name_paragraph = Paragraph::new(NAME_TEXT)
|
|
||||||
.style(Style::default().bg(Color::Magenta).fg(Color::White))
|
.style(Style::default().bg(Color::Magenta).fg(Color::White))
|
||||||
.block(Block::default())
|
.block(Block::default())
|
||||||
.alignment(Alignment::Center);
|
.alignment(Alignment::Center);
|
||||||
|
|
||||||
let description_paragraph = Paragraph::new(description_text.as_str())
|
let description_paragraph = Paragraph::new(description_info.spans)
|
||||||
.style(Style::default().bg(Color::Magenta).fg(Color::Black))
|
.style(Style::default().bg(Color::Magenta).fg(Color::Black))
|
||||||
.block(Block::default())
|
.block(Block::default())
|
||||||
.alignment(Alignment::Center);
|
.alignment(Alignment::Center);
|
||||||
|
|
||||||
let help_paragraph = Paragraph::new(help_text.as_str())
|
let help_paragraph = Paragraph::new(button_info.spans)
|
||||||
.style(Style::default().bg(Color::Magenta).fg(Color::Black))
|
.style(Style::default().bg(Color::Magenta).fg(Color::Black))
|
||||||
.block(Block::default())
|
.block(Block::default())
|
||||||
.alignment(Alignment::Left);
|
.alignment(Alignment::Left);
|
||||||
|
|
||||||
|
let final_paragraph = Paragraph::new(final_info.spans)
|
||||||
|
.style(Style::default().bg(Color::Magenta).fg(Color::Black))
|
||||||
|
.block(Block::default())
|
||||||
|
.alignment(Alignment::Center);
|
||||||
|
|
||||||
let block = Block::default()
|
let block = Block::default()
|
||||||
.title(title)
|
.title(title)
|
||||||
.borders(Borders::ALL)
|
.borders(Borders::ALL)
|
||||||
.border_type(BorderType::Rounded)
|
.border_type(BorderType::Rounded)
|
||||||
.border_style(Style::default().fg(Color::Black));
|
.border_style(Style::default().fg(Color::Black));
|
||||||
|
|
||||||
let area = popup(lines, max_line_width, f.size(), BoxLocation::MiddleCentre);
|
|
||||||
|
|
||||||
let split_popup = Layout::default()
|
|
||||||
.direction(Direction::Vertical)
|
|
||||||
.constraints(
|
|
||||||
[
|
|
||||||
Constraint::Max(NAME_TEXT.lines().count().try_into().unwrap_or_default()),
|
|
||||||
Constraint::Max(
|
|
||||||
description_text
|
|
||||||
.lines()
|
|
||||||
.count()
|
|
||||||
.try_into()
|
|
||||||
.unwrap_or_default(),
|
|
||||||
),
|
|
||||||
Constraint::Max(help_text.lines().count().try_into().unwrap_or_default()),
|
|
||||||
]
|
|
||||||
.as_ref(),
|
|
||||||
)
|
|
||||||
.split(area);
|
|
||||||
|
|
||||||
// Order is important here
|
// Order is important here
|
||||||
f.render_widget(Clear, area);
|
f.render_widget(Clear, area);
|
||||||
f.render_widget(name_paragraph, split_popup[0]);
|
f.render_widget(name_paragraph, split_popup[0]);
|
||||||
f.render_widget(description_paragraph, split_popup[1]);
|
f.render_widget(description_paragraph, split_popup[1]);
|
||||||
f.render_widget(help_paragraph, split_popup[2]);
|
f.render_widget(help_paragraph, split_popup[2]);
|
||||||
|
f.render_widget(final_paragraph, split_popup[3]);
|
||||||
f.render_widget(block, area);
|
f.render_widget(block, area);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -640,23 +800,19 @@ pub fn info<B: Backend>(f: &mut Frame<'_, B>, text: String) {
|
|||||||
/// draw a box in the one of the BoxLocations, based on max line width + number of lines
|
/// draw a box in the one of the BoxLocations, based on max line width + number of lines
|
||||||
fn popup(text_lines: usize, text_width: usize, r: Rect, box_location: BoxLocation) -> Rect {
|
fn popup(text_lines: usize, text_width: usize, r: Rect, box_location: BoxLocation) -> Rect {
|
||||||
// Make sure blank_space can't be an negative, as will crash
|
// Make sure blank_space can't be an negative, as will crash
|
||||||
let blank_vertical = if usize::from(r.height) > text_lines {
|
let calc = |x: u16, y: usize| {
|
||||||
(usize::from(r.height) - text_lines) / 2
|
(usize::from(x).checked_sub(y).map_or(1usize, |f| f))
|
||||||
} else {
|
.checked_div(2)
|
||||||
1
|
.map_or(1usize, |f| f)
|
||||||
};
|
|
||||||
let blank_horizontal = if usize::from(r.width) > text_width {
|
|
||||||
(usize::from(r.width) - text_width) / 2
|
|
||||||
} else {
|
|
||||||
1
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let v_constraints = box_location.get_vertical_constraints(
|
let blank_vertical = calc(r.height, text_lines);
|
||||||
|
let blank_horizontal = calc(r.width, text_width);
|
||||||
|
|
||||||
|
let (h_constraints, v_constraints) = box_location.get_constraints(
|
||||||
|
blank_horizontal.try_into().unwrap_or_default(),
|
||||||
blank_vertical.try_into().unwrap_or_default(),
|
blank_vertical.try_into().unwrap_or_default(),
|
||||||
text_lines.try_into().unwrap_or_default(),
|
text_lines.try_into().unwrap_or_default(),
|
||||||
);
|
|
||||||
let h_constraints = box_location.get_horizontal_constraints(
|
|
||||||
blank_horizontal.try_into().unwrap_or_default(),
|
|
||||||
text_width.try_into().unwrap_or_default(),
|
text_width.try_into().unwrap_or_default(),
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -672,3 +828,15 @@ fn popup(text_lines: usize, text_width: usize, r: Rect, box_location: BoxLocatio
|
|||||||
.constraints(h_constraints)
|
.constraints(h_constraints)
|
||||||
.split(popup_layout[indexes.0])[indexes.1]
|
.split(popup_layout[indexes.0])[indexes.1]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Draw nothing, as in a blank screen
|
||||||
|
// pub fn nothing<B: Backend>(f: &mut Frame<'_, B>) {
|
||||||
|
// let whole_layout = Layout::default()
|
||||||
|
// .direction(Direction::Vertical)
|
||||||
|
// .constraints([Constraint::Min(100)].as_ref())
|
||||||
|
// .split(f.size());
|
||||||
|
|
||||||
|
// let block = Block::default()
|
||||||
|
// .borders(Borders::NONE);
|
||||||
|
// f.render_widget(block, whole_layout[0]);
|
||||||
|
// }
|
||||||
|
|||||||
+27
-13
@@ -75,31 +75,45 @@ impl BoxLocation {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Should combine with get_vertical_constraints and just return a tuple of (vc, hc)?
|
/// Get both the vertical and hoziztonal constrains
|
||||||
pub const fn get_horizontal_constraints(
|
pub const fn get_constraints(
|
||||||
self,
|
self,
|
||||||
|
blank_horizontal: u16,
|
||||||
blank_vertical: u16,
|
blank_vertical: u16,
|
||||||
|
text_lines: u16,
|
||||||
|
text_width: u16,
|
||||||
|
) -> ([Constraint; 3], [Constraint; 3]) {
|
||||||
|
(
|
||||||
|
Self::get_horizontal_constraints(self, blank_horizontal, text_width),
|
||||||
|
Self::get_vertical_constraints(self, blank_vertical, text_lines),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const fn get_horizontal_constraints(
|
||||||
|
self,
|
||||||
|
blank_horizontal: u16,
|
||||||
text_width: u16,
|
text_width: u16,
|
||||||
) -> [Constraint; 3] {
|
) -> [Constraint; 3] {
|
||||||
match self {
|
match self {
|
||||||
Self::TopLeft | Self::MiddleLeft | Self::BottomLeft => [
|
Self::TopLeft | Self::MiddleLeft | Self::BottomLeft => [
|
||||||
Constraint::Max(text_width),
|
Constraint::Max(text_width),
|
||||||
Constraint::Max(blank_vertical),
|
Constraint::Max(blank_horizontal),
|
||||||
Constraint::Max(blank_vertical),
|
Constraint::Max(blank_horizontal),
|
||||||
],
|
],
|
||||||
Self::TopCentre | Self::MiddleCentre | Self::BottomCentre => [
|
Self::TopCentre | Self::MiddleCentre | Self::BottomCentre => [
|
||||||
Constraint::Max(blank_vertical),
|
Constraint::Max(blank_horizontal),
|
||||||
Constraint::Max(text_width),
|
Constraint::Max(text_width),
|
||||||
Constraint::Max(blank_vertical),
|
Constraint::Max(blank_horizontal),
|
||||||
],
|
],
|
||||||
Self::TopRight | Self::MiddleRight | Self::BottomRight => [
|
Self::TopRight | Self::MiddleRight | Self::BottomRight => [
|
||||||
Constraint::Max(blank_vertical),
|
Constraint::Max(blank_horizontal),
|
||||||
Constraint::Max(blank_vertical),
|
Constraint::Max(blank_horizontal),
|
||||||
Constraint::Max(text_width),
|
Constraint::Max(text_width),
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub const fn get_vertical_constraints(
|
|
||||||
|
const fn get_vertical_constraints(
|
||||||
self,
|
self,
|
||||||
blank_vertical: u16,
|
blank_vertical: u16,
|
||||||
number_lines: u16,
|
number_lines: u16,
|
||||||
@@ -188,13 +202,13 @@ pub enum Status {
|
|||||||
/// Global gui_state, stored in an Arc<Mutex>
|
/// Global gui_state, stored in an Arc<Mutex>
|
||||||
#[derive(Debug, Default, Clone)]
|
#[derive(Debug, Default, Clone)]
|
||||||
pub struct GuiState {
|
pub struct GuiState {
|
||||||
panel_map: HashMap<SelectablePanel, Rect>,
|
|
||||||
heading_map: HashMap<Header, Rect>,
|
heading_map: HashMap<Header, Rect>,
|
||||||
loading_icon: Loading,
|
|
||||||
is_loading: HashSet<Uuid>,
|
is_loading: HashSet<Uuid>,
|
||||||
|
loading_icon: Loading,
|
||||||
|
panel_map: HashMap<SelectablePanel, Rect>,
|
||||||
status: HashSet<Status>,
|
status: HashSet<Status>,
|
||||||
pub selected_panel: SelectablePanel,
|
|
||||||
pub info_box_text: Option<String>,
|
pub info_box_text: Option<String>,
|
||||||
|
pub selected_panel: SelectablePanel,
|
||||||
}
|
}
|
||||||
impl GuiState {
|
impl GuiState {
|
||||||
/// Clear panels hash map, so on resize can fix the sizes for mouse clicks
|
/// Clear panels hash map, so on resize can fix the sizes for mouse clicks
|
||||||
@@ -273,7 +287,7 @@ impl GuiState {
|
|||||||
self.is_loading.insert(uuid);
|
self.is_loading.insert(uuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// If is_loading has any entries, return the current loading_icon, else an empty string
|
/// If is_loading has any entries, return the current loading_icon, else an empty string, which needs to take up the same space, hence ' '
|
||||||
pub fn get_loading(&mut self) -> String {
|
pub fn get_loading(&mut self) -> String {
|
||||||
if self.is_loading.is_empty() {
|
if self.is_loading.is_empty() {
|
||||||
String::from(" ")
|
String::from(" ")
|
||||||
|
|||||||
+142
-71
@@ -1,16 +1,18 @@
|
|||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use crossterm::{
|
use crossterm::{
|
||||||
event::{self, DisableMouseCapture, EnableMouseCapture, Event},
|
event::{self, DisableMouseCapture, Event},
|
||||||
execute,
|
execute,
|
||||||
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
|
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
|
||||||
};
|
};
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use std::{
|
use std::{
|
||||||
io::{self, Write},
|
io::{self, Stdout, Write},
|
||||||
sync::{atomic::Ordering, Arc},
|
sync::{atomic::Ordering, Arc},
|
||||||
|
time::Duration,
|
||||||
};
|
};
|
||||||
use std::{sync::atomic::AtomicBool, time::Instant};
|
use std::{sync::atomic::AtomicBool, time::Instant};
|
||||||
use tokio::sync::mpsc::Sender;
|
use tokio::sync::mpsc::Sender;
|
||||||
|
use tracing::error;
|
||||||
use tui::{
|
use tui::{
|
||||||
backend::{Backend, CrosstermBackend},
|
backend::{Backend, CrosstermBackend},
|
||||||
layout::{Constraint, Direction, Layout},
|
layout::{Constraint, Direction, Layout},
|
||||||
@@ -28,110 +30,179 @@ use crate::{
|
|||||||
input_handler::InputMessages,
|
input_handler::InputMessages,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Take control of the terminal in order to draw gui
|
pub struct Ui {
|
||||||
pub async fn create_ui(
|
|
||||||
app_data: Arc<Mutex<AppData>>,
|
app_data: Arc<Mutex<AppData>>,
|
||||||
docker_sx: Sender<DockerMessage>,
|
docker_sx: Sender<DockerMessage>,
|
||||||
gui_state: Arc<Mutex<GuiState>>,
|
gui_state: Arc<Mutex<GuiState>>,
|
||||||
|
input_poll_rate: Duration,
|
||||||
is_running: Arc<AtomicBool>,
|
is_running: Arc<AtomicBool>,
|
||||||
|
now: Instant,
|
||||||
sender: Sender<InputMessages>,
|
sender: Sender<InputMessages>,
|
||||||
) -> Result<()> {
|
terminal: Terminal<CrosstermBackend<Stdout>>,
|
||||||
enable_raw_mode()?;
|
|
||||||
let mut stdout = io::stdout();
|
|
||||||
execute!(stdout, EnterAlternateScreen, EnableMouseCapture)?;
|
|
||||||
let backend = CrosstermBackend::new(stdout);
|
|
||||||
let mut terminal = Terminal::new(backend)?;
|
|
||||||
|
|
||||||
let res = run_app(
|
|
||||||
app_data,
|
|
||||||
docker_sx,
|
|
||||||
gui_state,
|
|
||||||
is_running,
|
|
||||||
sender,
|
|
||||||
&mut terminal,
|
|
||||||
)
|
|
||||||
.await;
|
|
||||||
disable_raw_mode()?;
|
|
||||||
execute!(
|
|
||||||
terminal.backend_mut(),
|
|
||||||
LeaveAlternateScreen,
|
|
||||||
DisableMouseCapture
|
|
||||||
)?;
|
|
||||||
terminal.show_cursor()?;
|
|
||||||
|
|
||||||
if let Err(err) = res {
|
|
||||||
println!("error: {err}");
|
|
||||||
}
|
|
||||||
std::io::stdout().flush().unwrap_or(());
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Run a loop to draw the gui
|
impl Ui {
|
||||||
async fn run_app<B: Backend + Send>(
|
/// Enable mouse capture, but don't enable capture of all the mouse movements, doing so will improve performance, and is part of the fix for the weird mouse event output bug
|
||||||
app_data: Arc<Mutex<AppData>>,
|
pub fn enable_mouse_capture() -> Result<()> {
|
||||||
docker_sx: Sender<DockerMessage>,
|
io::stdout().write_all(
|
||||||
gui_state: Arc<Mutex<GuiState>>,
|
concat!(
|
||||||
is_running: Arc<AtomicBool>,
|
crossterm::csi!("?1000h"),
|
||||||
sender: Sender<InputMessages>,
|
crossterm::csi!("?1015h"),
|
||||||
terminal: &mut Terminal<B>,
|
crossterm::csi!("?1006h"),
|
||||||
) -> Result<(), AppError> {
|
)
|
||||||
let update_duration =
|
.as_bytes(),
|
||||||
std::time::Duration::from_millis(u64::from(app_data.lock().args.docker_interval));
|
)?;
|
||||||
let input_poll_rate = std::time::Duration::from_millis(75);
|
Ok(())
|
||||||
let status_dockerconnect = gui_state.lock().status_contains(&[Status::DockerConnect]);
|
}
|
||||||
let mut now = Instant::now();
|
|
||||||
if status_dockerconnect {
|
/// Create a new Ui struct, and execute the drawing loop
|
||||||
|
pub async fn create(
|
||||||
|
app_data: Arc<Mutex<AppData>>,
|
||||||
|
docker_sx: Sender<DockerMessage>,
|
||||||
|
gui_state: Arc<Mutex<GuiState>>,
|
||||||
|
is_running: Arc<AtomicBool>,
|
||||||
|
sender: Sender<InputMessages>,
|
||||||
|
) {
|
||||||
|
if let Ok(terminal) = Self::setup_terminal() {
|
||||||
|
let mut ui = Self {
|
||||||
|
app_data,
|
||||||
|
docker_sx,
|
||||||
|
gui_state,
|
||||||
|
input_poll_rate: std::time::Duration::from_millis(100),
|
||||||
|
is_running,
|
||||||
|
now: Instant::now(),
|
||||||
|
sender,
|
||||||
|
terminal,
|
||||||
|
};
|
||||||
|
if let Err(e) = ui.draw_ui().await {
|
||||||
|
error!("{e}");
|
||||||
|
}
|
||||||
|
if let Err(e) = ui.reset_terminal() {
|
||||||
|
error!("{e}");
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
error!("Terminal Error");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Setup the terminal for full-screen drawing mode, with mouse capture
|
||||||
|
fn setup_terminal() -> Result<Terminal<CrosstermBackend<Stdout>>> {
|
||||||
|
enable_raw_mode()?;
|
||||||
|
let mut stdout = io::stdout();
|
||||||
|
execute!(stdout, EnterAlternateScreen)?;
|
||||||
|
Self::enable_mouse_capture()?;
|
||||||
|
let backend = CrosstermBackend::new(stdout);
|
||||||
|
Ok(Terminal::new(backend)?)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This is a fix for mouse-events being printed to screen, read an event and do nothing with it
|
||||||
|
fn nullify_event_read(&self) {
|
||||||
|
if crossterm::event::poll(self.input_poll_rate).unwrap_or(true) {
|
||||||
|
event::read().ok();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// reset the terminal back to default settings
|
||||||
|
pub fn reset_terminal(&mut self) -> Result<()> {
|
||||||
|
self.terminal.clear()?;
|
||||||
|
|
||||||
|
execute!(
|
||||||
|
self.terminal.backend_mut(),
|
||||||
|
LeaveAlternateScreen,
|
||||||
|
DisableMouseCapture
|
||||||
|
)?;
|
||||||
|
disable_raw_mode()?;
|
||||||
|
self.terminal.show_cursor()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Draw the the error message ui, for 5 seconds, with a countdown
|
||||||
|
fn err_loop(&mut self) -> Result<(), AppError> {
|
||||||
let mut seconds = 5;
|
let mut seconds = 5;
|
||||||
loop {
|
loop {
|
||||||
if seconds < 1 {
|
if self.now.elapsed() >= std::time::Duration::from_secs(1) {
|
||||||
break;
|
|
||||||
}
|
|
||||||
if now.elapsed() >= std::time::Duration::from_secs(1) {
|
|
||||||
seconds -= 1;
|
seconds -= 1;
|
||||||
now = Instant::now();
|
self.now = Instant::now();
|
||||||
|
if seconds < 1 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if terminal
|
|
||||||
|
// This is a fix for mouse-events being printed to screen
|
||||||
|
self.nullify_event_read();
|
||||||
|
|
||||||
|
if self
|
||||||
|
.terminal
|
||||||
.draw(|f| draw_blocks::error(f, AppError::DockerConnect, Some(seconds)))
|
.draw(|f| draw_blocks::error(f, AppError::DockerConnect, Some(seconds)))
|
||||||
.is_err()
|
.is_err()
|
||||||
{
|
{
|
||||||
return Err(AppError::Terminal);
|
return Err(AppError::Terminal);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
Ok(())
|
||||||
while is_running.load(Ordering::SeqCst) {
|
}
|
||||||
if crossterm::event::poll(input_poll_rate).unwrap_or(false) {
|
|
||||||
|
/// The loop for drawing the main UI to the terminal
|
||||||
|
async fn gui_loop(&mut self) -> Result<(), AppError> {
|
||||||
|
let update_duration =
|
||||||
|
std::time::Duration::from_millis(u64::from(self.app_data.lock().args.docker_interval));
|
||||||
|
|
||||||
|
while self.is_running.load(Ordering::SeqCst) {
|
||||||
|
if self
|
||||||
|
.terminal
|
||||||
|
.draw(|frame| draw_frame(frame, &self.app_data, &self.gui_state))
|
||||||
|
.is_err()
|
||||||
|
{
|
||||||
|
return Err(AppError::Terminal);
|
||||||
|
}
|
||||||
|
if crossterm::event::poll(self.input_poll_rate).unwrap_or(false) {
|
||||||
if let Ok(event) = event::read() {
|
if let Ok(event) = event::read() {
|
||||||
if let Event::Key(key) = event {
|
if let Event::Key(key) = event {
|
||||||
sender
|
self.sender
|
||||||
.send(InputMessages::ButtonPress(key.code))
|
.send(InputMessages::ButtonPress(key.code))
|
||||||
.await
|
.await
|
||||||
.unwrap_or(());
|
.unwrap_or(());
|
||||||
} else if let Event::Mouse(m) = event {
|
} else if let Event::Mouse(m) = event {
|
||||||
sender
|
self.sender
|
||||||
.send(InputMessages::MouseEvent(m))
|
.send(InputMessages::MouseEvent(m))
|
||||||
.await
|
.await
|
||||||
.unwrap_or(());
|
.unwrap_or(());
|
||||||
} else if let Event::Resize(_, _) = event {
|
} else if let Event::Resize(_, _) = event {
|
||||||
gui_state.lock().clear_area_map();
|
self.gui_state.lock().clear_area_map();
|
||||||
terminal.autoresize().unwrap_or(());
|
self.terminal.autoresize().unwrap_or(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if now.elapsed() >= update_duration {
|
if self.now.elapsed() >= update_duration {
|
||||||
docker_sx.send(DockerMessage::Update).await.unwrap_or(());
|
self.docker_sx
|
||||||
now = Instant::now();
|
.send(DockerMessage::Update)
|
||||||
}
|
.await
|
||||||
if terminal.draw(|f| ui(f, &app_data, &gui_state)).is_err() {
|
.unwrap_or(());
|
||||||
return Err(AppError::Terminal);
|
self.now = Instant::now();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Draw either the Error, or main oxker ui, to the terminal
|
||||||
|
async fn draw_ui(&mut self) -> Result<(), AppError> {
|
||||||
|
let status_dockerconnect = self
|
||||||
|
.gui_state
|
||||||
|
.lock()
|
||||||
|
.status_contains(&[Status::DockerConnect]);
|
||||||
|
if status_dockerconnect {
|
||||||
|
self.err_loop()?;
|
||||||
|
} else {
|
||||||
|
self.gui_loop().await?;
|
||||||
|
}
|
||||||
|
self.nullify_event_read();
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
terminal.clear().unwrap_or(());
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ui<B: Backend>(
|
/// Draw the main ui to a frame of the terminal
|
||||||
|
fn draw_frame<B: Backend>(
|
||||||
f: &mut Frame<'_, B>,
|
f: &mut Frame<'_, B>,
|
||||||
app_data: &Arc<Mutex<AppData>>,
|
app_data: &Arc<Mutex<AppData>>,
|
||||||
gui_state: &Arc<Mutex<GuiState>>,
|
gui_state: &Arc<Mutex<GuiState>>,
|
||||||
@@ -183,7 +254,7 @@ fn ui<B: Backend>(
|
|||||||
vec![Constraint::Percentage(100)]
|
vec![Constraint::Percentage(100)]
|
||||||
};
|
};
|
||||||
|
|
||||||
// Split into 3, containers+controls, logs, then graphs
|
// Split into 2, logs, and optional charts
|
||||||
let lower_main = Layout::default()
|
let lower_main = Layout::default()
|
||||||
.direction(Direction::Vertical)
|
.direction(Direction::Vertical)
|
||||||
.constraints(lower_split.as_ref())
|
.constraints(lower_split.as_ref())
|
||||||
|
|||||||
Reference in New Issue
Block a user