chore: merge release-v0.6.0 into main

This commit is contained in:
Jack Wills
2024-01-18 22:56:23 +00:00
17 changed files with 4148 additions and 414 deletions
+11 -14
View File
@@ -1,26 +1,23 @@
### 2024-01-05
### 2024-01-18
### Chores
+ .devcontainer updated, [2313618eb1493ce41d70847b888c32b65fdc40ea], [5af6b8bcd31c3c38ff5a5799c76dc1cbe1167763], [9b0b6b10c3a0c1d5095490cfd3cda18d252f38f5]
+ alpine version bump, [061de032dad935c56c6caab419ecb5c9bbac4c7e]
+ dependencies updated, [0890991ff1a239fe2d556a0c4eac6ae05beb9b50], [0a7b266b2a358a4788ae877ca8a97f08eac4eef2], [333621f1a7321c1fdf73fd35dd7f3ab165a9dc64], [3e51889cd8a552b1da463ae6a40d5de6eec188f5], [a179bb6f6a7e076269fa830f56c0d4a31cf8488a]
+ file formatting, [eb5e74ae67d815bf49f241d2baf319e41cf9adf8]
+ Rust 1.75.0 linting, [81be75f27fd32a59ebff57e44c5022ff862df84b]
+ dependencies updated, [53b4bafbe53312fe41608ddf33e865d474222aaa], [58ef151600e362048a607c8ae61a5edfe80ab1dd], [b6fd35022a99ec0e982ddb154b0450d49c4840e9], [0438c108bdd9815d7eae1b89c47c4e6438f358d6]
+ files formatted, [1806165c3e266876b2d1806f7b662d09705f3aad]
+ create_release.sh check for unused lint, [d0b27211928f93f8455e1ee5a6a6485c6a21d382]
### Docs
+ screenshot updated, [0231d1bdcda304300d289243a95044ab3bdce85c]
+ comment typo, [0ad1ec9d85d6f0cac743b4421d0ad03432c9d717]
= Readme updated, screenshot added, [7561a93415c1e1f596b15edba95e7b32a939cd90], [4069e5572f81cb689dbb9f735db919e4636cdccc]
### Features
+ re-arrange columns, container name is now the first column, added a ContainerName & ContainerImage struct via `string_wrapper` macro, closes #32, [e936bb4b78980d0e34a1ef5e9f6f82a9ed0ddc7f]
+ Ports section added, closes #21, [65a1afcb0605604ede350a5630c775f94ebb74ee], [7a096a65c40924021fe643fe0aa1067095832df9]
### Fixes
+ Docker Commands hidden, [4301e4709f99fc23ee438bf345b0dc698a05dc4e]
+ .gitattributes, [1234ea53897b2ed6ada0eb18cd81b8783a5dc5f5]
+ sort arrow now on left of header, [40ddcb727d2c1758d6dd26a58507b85b219f51e2]
### Refactors
+ GitHub workflow action improved, [04b66af2b60c96cfbece0b13109e30b08ef35cc4]
+ sort_containers, [ccf8b55a7495982f72b4fb3af6e11a9bd7465216]
+ string_wrapper .get() return `&str`, [a722731c6a77e00d1fb13967b51400aa34e72213]
+ rename string_wrapper > unit_struct, [27cf53e41f8b379f606c1c27620ee08e79bac57e]
### Tests
+ Finally have tests, currently for layout and associated methods, at the moment running the tests will not interfere with any running Docker containers, [4bcf77db776a36e0a8151ecfbda722a66c4ba46c]
see <a href='https://github.com/mrjackwills/oxker/blob/main/CHANGELOG.md'>CHANGELOG.md</a> for more details
Binary file not shown.

Before

Width:  |  Height:  |  Size: 55 KiB

After

Width:  |  Height:  |  Size: 34 KiB

+23
View File
@@ -1,3 +1,26 @@
# <a href='https://github.com/mrjackwills/oxker/releases/tag/v0.6.0'>v0.6.0</a>
### 2024-01-18
### Chores
+ dependencies updated, [53b4bafb](https://github.com/mrjackwills/oxker/commit/53b4bafbe53312fe41608ddf33e865d474222aaa), [58ef1516](https://github.com/mrjackwills/oxker/commit/58ef151600e362048a607c8ae61a5edfe80ab1dd), [b6fd3502](https://github.com/mrjackwills/oxker/commit/b6fd35022a99ec0e982ddb154b0450d49c4840e9), [0438c108](https://github.com/mrjackwills/oxker/commit/0438c108bdd9815d7eae1b89c47c4e6438f358d6)
+ files formatted, [1806165c](https://github.com/mrjackwills/oxker/commit/1806165c3e266876b2d1806f7b662d09705f3aad)
+ create_release.sh check for unused lint, [d0b27211](https://github.com/mrjackwills/oxker/commit/d0b27211928f93f8455e1ee5a6a6485c6a21d382)
### Docs
= Readme updated, screenshot added, [7561a934](https://github.com/mrjackwills/oxker/commit/7561a93415c1e1f596b15edba95e7b32a939cd90), [4069e557](https://github.com/mrjackwills/oxker/commit/4069e5572f81cb689dbb9f735db919e4636cdccc)
### Features
+ Ports section added, closes [#21](https://github.com/mrjackwills/oxker/issues/21), [65a1afcb](https://github.com/mrjackwills/oxker/commit/65a1afcb0605604ede350a5630c775f94ebb74ee), [7a096a65](https://github.com/mrjackwills/oxker/commit/7a096a65c40924021fe643fe0aa1067095832df9)
### Fixes
+ sort arrow now on left of header, [40ddcb72](https://github.com/mrjackwills/oxker/commit/40ddcb727d2c1758d6dd26a58507b85b219f51e2)
### Refactors
+ rename string_wrapper > unit_struct, [27cf53e4](https://github.com/mrjackwills/oxker/commit/27cf53e41f8b379f606c1c27620ee08e79bac57e)
### Tests
+ Finally have tests, currently for layout and associated methods, at the moment running the tests will not interfere with any running Docker containers, [4bcf77db](https://github.com/mrjackwills/oxker/commit/4bcf77db776a36e0a8151ecfbda722a66c4ba46c)
# <a href='https://github.com/mrjackwills/oxker/releases/tag/v0.5.0'>v0.5.0</a>
### 2024-01-05
Generated
+44 -44
View File
@@ -52,9 +52,9 @@ dependencies = [
[[package]]
name = "anstream"
version = "0.6.5"
version = "0.6.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d664a92ecae85fd0a7392615844904654d1d5f5514837f471ddef4a057aba1b6"
checksum = "6e2e1ebcb11de5c03c67de28a7df593d32191b44939c482e97702baaaa6ab6a5"
dependencies = [
"anstyle",
"anstyle-parse",
@@ -127,9 +127,9 @@ dependencies = [
[[package]]
name = "base64"
version = "0.21.5"
version = "0.21.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9"
checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567"
[[package]]
name = "bitflags"
@@ -139,9 +139,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bitflags"
version = "2.4.1"
version = "2.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07"
checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf"
[[package]]
name = "bollard"
@@ -237,9 +237,9 @@ dependencies = [
[[package]]
name = "clap"
version = "4.4.13"
version = "4.4.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52bdc885e4cacc7f7c9eedc1ef6da641603180c783c41a15c264944deeaab642"
checksum = "1e578d6ec4194633722ccf9544794b71b1385c3c027efe0c55db226fc880865c"
dependencies = [
"clap_builder",
"clap_derive",
@@ -247,9 +247,9 @@ dependencies = [
[[package]]
name = "clap_builder"
version = "4.4.12"
version = "4.4.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fb7fb5e4e979aec3be7791562fcba452f94ad85e954da024396433e0e25a79e9"
checksum = "4df4df40ec50c46000231c914968278b1eb05098cf8f1b3a518a95030e71d1c7"
dependencies = [
"anstream",
"anstyle",
@@ -295,7 +295,7 @@ version = "0.27.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f476fe445d41c9e991fd07515a6f463074b782242ccf4a5b7b1d1012e70824df"
dependencies = [
"bitflags 2.4.1",
"bitflags 2.4.2",
"crossterm_winapi",
"libc",
"mio",
@@ -426,9 +426,9 @@ dependencies = [
[[package]]
name = "getrandom"
version = "0.2.11"
version = "0.2.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f"
checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5"
dependencies = [
"cfg-if",
"libc",
@@ -443,9 +443,9 @@ checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253"
[[package]]
name = "h2"
version = "0.3.22"
version = "0.3.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4d6250322ef6e60f93f9a2162799302cd6f68f79f6e5d85c8c16f14d1d958178"
checksum = "bb2c4422095b67ee78da96fbb51a4cc413b3b25883c7717ff7ca1ab31022c9c9"
dependencies = [
"bytes",
"fnv",
@@ -484,9 +484,9 @@ checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
[[package]]
name = "hermit-abi"
version = "0.3.3"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7"
checksum = "5d3d0e0f38255e7fa3cf31335b3a56f05febd18025f4db5ef7a0cfb4f8da651f"
[[package]]
name = "hex"
@@ -643,9 +643,9 @@ checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c"
[[package]]
name = "js-sys"
version = "0.3.66"
version = "0.3.67"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cee9c64da59eae3b50095c18d3e74f8b73c0b86d2792824ff01bbce68ba229ca"
checksum = "9a1d36f1235bc969acba30b7f5990b864423a6068a10f7c90ae8f0112e3a59d1"
dependencies = [
"wasm-bindgen",
]
@@ -658,9 +658,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.151"
version = "0.2.152"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4"
checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7"
[[package]]
name = "libredox"
@@ -668,7 +668,7 @@ version = "0.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8"
dependencies = [
"bitflags 2.4.1",
"bitflags 2.4.2",
"libc",
"redox_syscall",
]
@@ -783,7 +783,7 @@ checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
[[package]]
name = "oxker"
version = "0.5.0"
version = "0.6.0"
dependencies = [
"anyhow",
"bollard",
@@ -881,9 +881,9 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
[[package]]
name = "proc-macro2"
version = "1.0.75"
version = "1.0.76"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "907a61bd0f64c2f29cd1cf1dc34d05176426a3f504a78010f08416ddb7b13708"
checksum = "95fc56cda0b5c3325f5fbbd7ff9fda9e02bb00bb3dac51252d2f1bfa1cb8cc8c"
dependencies = [
"unicode-ident",
]
@@ -933,7 +933,7 @@ version = "0.25.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a5659e52e4ba6e07b2dad9f1158f578ef84a73762625ddb51536019f34d180eb"
dependencies = [
"bitflags 2.4.1",
"bitflags 2.4.2",
"cassowary",
"crossterm",
"indoc",
@@ -992,18 +992,18 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "serde"
version = "1.0.194"
version = "1.0.195"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b114498256798c94a0689e1a15fec6005dee8ac1f41de56404b67afc2a4b773"
checksum = "63261df402c67811e9ac6def069e4786148c4563f4b50fd4bf30aa370d626b02"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.194"
version = "1.0.195"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a3385e45322e8f9931410f01b3031ec534c3947d0e94c18049af4d9f9907d4e0"
checksum = "46fe8f8603d81ba86327b23a2e9cdf49e1255fb94a4c5f297f6ee0547178ea2c"
dependencies = [
"proc-macro2",
"quote",
@@ -1110,9 +1110,9 @@ dependencies = [
[[package]]
name = "smallvec"
version = "1.11.2"
version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970"
checksum = "3b187f0231d56fe41bfb12034819dd2bf336422a5866de41bc3fec4b2e3883e8"
[[package]]
name = "socket2"
@@ -1382,9 +1382,9 @@ dependencies = [
[[package]]
name = "unicode-bidi"
version = "0.3.14"
version = "0.3.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6f2528f27a9eb2b21e69c95319b30bd0efd85d09c379741b0f78ea1d86be2416"
checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75"
[[package]]
name = "unicode-ident"
@@ -1469,9 +1469,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "wasm-bindgen"
version = "0.2.89"
version = "0.2.90"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ed0d4f68a3015cc185aff4db9506a015f4b96f95303897bfa23f846db54064e"
checksum = "b1223296a201415c7fad14792dbefaace9bd52b62d33453ade1c5b5f07555406"
dependencies = [
"cfg-if",
"wasm-bindgen-macro",
@@ -1479,9 +1479,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-backend"
version = "0.2.89"
version = "0.2.90"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b56f625e64f3a1084ded111c4d5f477df9f8c92df113852fa5a374dbda78826"
checksum = "fcdc935b63408d58a32f8cc9738a0bffd8f05cc7c002086c6ef20b7312ad9dcd"
dependencies = [
"bumpalo",
"log",
@@ -1494,9 +1494,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.89"
version = "0.2.90"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0162dbf37223cd2afce98f3d0785506dcb8d266223983e4b5b525859e6e182b2"
checksum = "3e4c238561b2d428924c49815533a8b9121c664599558a5d9ec51f8a1740a999"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
@@ -1504,9 +1504,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.89"
version = "0.2.90"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283"
checksum = "bae1abb6806dc1ad9e560ed242107c0f6c84335f1749dd4e8ddb012ebd5e25a7"
dependencies = [
"proc-macro2",
"quote",
@@ -1517,9 +1517,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.89"
version = "0.2.90"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ab9b36309365056cd639da3134bf87fa8f3d86008abf99e612384a6eecd459f"
checksum = "4d91413b1c31d7539ba5ef2451af3f0b833a005eb27a631cec32bc0635a8602b"
[[package]]
name = "winapi"
+3 -4
View File
@@ -1,6 +1,6 @@
[package]
name = "oxker"
version = "0.5.0"
version = "0.6.0"
edition = "2021"
authors = ["Jack Wills <email@mrjackwills.com>"]
description = "A simple tui to view & control docker containers"
@@ -29,7 +29,7 @@ similar_names = "allow"
anyhow = "1.0"
bollard = "0.15"
cansi = "2.2"
clap = { version = "4.4", features = ["derive", "unicode", "color"] }
clap = { version = "4.4", features = ["color", "derive", "unicode"] }
crossterm = "0.27"
futures-util = "0.3"
parking_lot = { version = "0.12" }
@@ -37,7 +37,7 @@ tokio = { version = "1.35", features = ["full"] }
tracing = "0.1"
tracing-subscriber = "0.3"
ratatui = "0.25"
uuid = { version = "1.6", features = ["v4", "fast-rng"] }
uuid = { version = "1.6", features = ["fast-rng", "v4"] }
directories = "5.0"
[dev-dependencies]
@@ -48,4 +48,3 @@ codegen-units = 1
panic = 'abort'
strip = true
debug = false
+2 -1
View File
@@ -157,7 +157,8 @@ see <a href="https://forums.raspberrypi.com/viewtopic.php?t=203128" target='_bla
## Tests
As of yet untested, needs work
~~As of yet untested, needs work~~
The work has been done, sp far the tests don't effect any running containers, but this may change in the future.
```shell
cargo test -- --test-threads=1
+36 -26
View File
@@ -1,7 +1,7 @@
#!/bin/bash
# rust create_release
# v0.3.1
# v0.4.1
STAR_LINE='****************************************'
CWD=$(pwd)
@@ -12,10 +12,9 @@ YELLOW='\033[0;33m'
PURPLE='\033[0;35m'
RESET='\033[0m'
# $1 string - error message
error_close() {
echo -e "\n${RED}ERROR - EXITED: ${YELLOW}$1${RESET}\n";
echo -e "\n${RED}ERROR - EXITED: ${YELLOW}$1${RESET}\n"
exit 1
}
@@ -56,8 +55,7 @@ get_git_remote_url() {
# Check that git status is clean
check_git_clean() {
GIT_CLEAN=$(git status --porcelain)
if [[ -n $GIT_CLEAN ]]
then
if [[ -n $GIT_CLEAN ]]; then
error_close "git dirty"
fi
}
@@ -66,8 +64,7 @@ check_git_clean() {
check_git() {
CURRENT_GIT_BRANCH=$(git branch --show-current)
check_git_clean
if [[ ! "$CURRENT_GIT_BRANCH" =~ ^dev$ ]]
then
if [[ ! "$CURRENT_GIT_BRANCH" =~ ^dev$ ]]; then
error_close "not on dev branch"
fi
}
@@ -79,8 +76,7 @@ ask_changelog_update() {
printf "%s" "$RELEASE_BODY_TEXT"
printf "\n%s\n" "${STAR_LINE}"
ask_yn "accept release body"
if [[ "$(user_input)" =~ ^y$ ]]
then
if [[ "$(user_input)" =~ ^y$ ]]; then
update_release_body_and_changelog "$RELEASE_BODY_TEXT"
else
exit
@@ -122,8 +118,7 @@ check_tag () {
LATEST_TAG=$(git describe --tags "$(git rev-list --tags --max-count=1)")
echo -e "\nCurrent tag: ${PURPLE}${LATEST_TAG}${RESET}\n"
echo -e "${YELLOW}Choose new tag version:${RESET}\n"
if [[ $LATEST_TAG =~ ^v(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)(-((0|[1-9][0-9]*|[0-9]*[a-zA-Z-][0-9a-zA-Z-]*)(\.(0|[1-9][0-9]*|[0-9]*[a-zA-Z-][0-9a-zA-Z-]*))*))?(\+([0-9a-zA-Z-]+(\.[0-9a-zA-Z-]+)*))?$ ]]
then
if [[ $LATEST_TAG =~ ^v(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)(-((0|[1-9][0-9]*|[0-9]*[a-zA-Z-][0-9a-zA-Z-]*)(\.(0|[1-9][0-9]*|[0-9]*[a-zA-Z-][0-9a-zA-Z-]*))*))?(\+([0-9a-zA-Z-]+(\.[0-9a-zA-Z-]+)*))?$ ]]; then
IFS="." read -r MAJOR MINOR PATCH <<<"${LATEST_TAG:1}"
else
MAJOR="0"
@@ -134,23 +129,26 @@ check_tag () {
OP_MINOR="minor___v$(update_minor)"
OP_PATCH="patch___v$(update_patch)"
OPTIONS=("$OP_MAJOR" "$OP_MINOR" "$OP_PATCH")
select choice in "${OPTIONS[@]}"
do
select choice in "${OPTIONS[@]}"; do
case $choice in
"$OP_MAJOR")
MAJOR=$((MAJOR + 1))
MINOR=0
PATCH=0
break;;
break
;;
"$OP_MINOR")
MINOR=$((MINOR + 1))
PATCH=0
break;;
break
;;
"$OP_PATCH")
PATCH=$((PATCH + 1))
break;;
break
;;
*)
error_close "invalid option $REPLY"
;;
esac
done
}
@@ -158,8 +156,7 @@ check_tag () {
# ask continue, or quit
ask_continue() {
ask_yn "continue"
if [[ ! "$(user_input)" =~ ^y$ ]]
then
if [[ ! "$(user_input)" =~ ^y$ ]]; then
exit
fi
}
@@ -199,7 +196,6 @@ cargo_build () {
cargo_clean
}
# $1 text to colourise
release_continue() {
echo -e "\n${PURPLE}$1${RESET}"
@@ -218,8 +214,20 @@ check_typos () {
ask_continue
}
# Make sure the unused lint isn't used
check_allow_unused() {
matches_any=$(find . -type d \( -name .git -o -name target \) -prune -o -type f -exec grep -lE '^#!\[allow\(unused\)\]$' {} +)
matches_cargo=$(grep "^unused = \"allow\"" ./Cargo.toml)
if [ -n "$matches_any" ]; then
error_close "\"#[allow(unused)]\" in ${matches_any}"
elif [ -n "$matches_cargo" ]; then
error_close "\"unused = \"allow\"\" in Cargo.toml"
fi
}
# Full flow to create a new release
release_flow() {
check_allow_unused
check_typos
check_git
@@ -283,7 +291,6 @@ release_flow() {
git branch -d "$RELEASE_BRANCH"
}
main() {
cmd=(dialog --backtitle "Choose option" --radiolist "choose" 14 80 16)
options=(
@@ -297,22 +304,25 @@ main() {
if [ $exitStatus -ne 0 ]; then
exit
fi
for choice in $choices
do
for choice in $choices; do
case $choice in
0)
exit;;
exit
;;
1)
cargo_test
main
break;;
break
;;
2)
release_flow
break;;
break
;;
3)
cargo_build
main
break;;
break
;;
esac
done
}
+2
View File
@@ -11,6 +11,8 @@ services:
ipc: private
restart: always
shm_size: 256MB
ports:
- "127.0.0.1:4040:4040"
networks:
- oxker-example-net
deploy:
+165 -15
View File
@@ -4,6 +4,7 @@ use std::{
fmt,
};
use bollard::service::Port;
use ratatui::{
style::Color,
widgets::{ListItem, ListState},
@@ -49,7 +50,7 @@ impl PartialOrd for ContainerId {
/// TODO - use string_wrapper for ContainerId?
/// ContainerName and ContainerImage are simple structs, used so can implement custom fmt functions to them
macro_rules! string_wrapper {
macro_rules! unit_struct {
($name:ident) => {
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct $name(String);
@@ -60,6 +61,13 @@ macro_rules! string_wrapper {
}
}
#[cfg(test)]
impl From<&str> for $name {
fn from(value: &str) -> Self {
Self(value.to_owned())
}
}
impl$name {
pub fn get(&self) -> &str {
self.0.as_str()
@@ -90,10 +98,51 @@ macro_rules! string_wrapper {
};
}
string_wrapper!(ContainerName);
string_wrapper!(ContainerImage);
unit_struct!(ContainerName);
unit_struct!(ContainerImage);
#[derive(Debug, Clone)]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ContainerPorts {
pub ip: Option<String>,
pub private: u16,
pub public: Option<u16>,
}
impl From<&Port> for ContainerPorts {
fn from(value: &Port) -> Self {
Self {
ip: value.ip.clone(),
private: value.private_port,
public: value.public_port,
}
}
}
impl ContainerPorts {
pub fn len_ip(&self) -> usize {
self.ip.as_ref().unwrap_or(&String::new()).chars().count()
}
pub fn len_private(&self) -> usize {
format!("{}", self.private).chars().count()
}
pub fn len_public(&self) -> usize {
format!("{}", self.public.unwrap_or_default())
.chars()
.count()
}
pub fn print(&self) -> (String, String, String) {
(
self.ip
.as_ref()
.map_or(String::new(), std::borrow::ToOwned::to_owned),
format!("{}", self.private),
self.public.map_or(String::new(), |s| s.to_string()),
)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct StatefulList<T> {
pub state: ListState,
pub items: Vec<T>,
@@ -234,13 +283,13 @@ impl fmt::Display for State {
}
/// Items for the container control list
#[derive(Debug, Clone, Copy)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DockerControls {
Pause,
Restart,
Start,
Stop,
Unpause,
Resume,
Delete,
}
@@ -252,7 +301,7 @@ impl DockerControls {
Self::Start => Color::Green,
Self::Stop => Color::Red,
Self::Delete => Color::Gray,
Self::Unpause => Color::Blue,
Self::Resume => Color::Blue,
}
}
@@ -260,7 +309,7 @@ impl DockerControls {
pub fn gen_vec(state: State) -> Vec<Self> {
match state {
State::Dead | State::Exited => vec![Self::Start, Self::Restart, Self::Delete],
State::Paused => vec![Self::Unpause, Self::Stop, Self::Delete],
State::Paused => vec![Self::Resume, Self::Stop, Self::Delete],
State::Restarting => vec![Self::Stop, Self::Delete],
State::Running => vec![Self::Pause, Self::Restart, Self::Stop, Self::Delete],
_ => vec![Self::Delete],
@@ -276,7 +325,7 @@ impl fmt::Display for DockerControls {
Self::Restart => "restart",
Self::Start => "start",
Self::Stop => "stop",
Self::Unpause => "resume",
Self::Resume => "resume",
};
write!(f, "{disp}")
}
@@ -416,7 +465,7 @@ impl fmt::Display for LogsTz {
/// Store the logs alongside a HashSet, each log *should* generate a unique timestamp,
/// so if we store the timestamp separately in a HashSet, we can then check if we should insert a log line into the
/// stateful list dependent on whethere the timestamp is in the HashSet or not
#[derive(Debug, Clone)]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Logs {
logs: StatefulList<ListItem<'static>>,
tz: HashSet<LogsTz>,
@@ -475,23 +524,25 @@ impl Logs {
}
/// Info for each container
#[derive(Debug, Clone)]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ContainerItem {
pub created: u64,
pub cpu_stats: VecDeque<CpuStats>,
pub created: u64,
pub docker_controls: StatefulList<DockerControls>,
pub id: ContainerId,
pub image: ContainerImage,
pub is_oxker: bool,
pub last_updated: u64,
pub logs: Logs,
pub mem_limit: ByteStats,
pub mem_stats: VecDeque<ByteStats>,
pub name: ContainerName,
// todo remove option, can be empty vec
pub ports: Vec<ContainerPorts>,
pub rx: ByteStats,
pub state: State,
pub status: String,
pub tx: ByteStats,
pub is_oxker: bool,
}
/// Basic display information, for when running in debug mode
@@ -509,6 +560,7 @@ impl fmt::Display for ContainerItem {
}
impl ContainerItem {
#[allow(clippy::too_many_arguments)]
/// Create a new container item
pub fn new(
created: u64,
@@ -516,14 +568,16 @@ impl ContainerItem {
image: String,
is_oxker: bool,
name: String,
ports: Vec<ContainerPorts>,
state: State,
status: String,
) -> Self {
let mut docker_controls = StatefulList::new(DockerControls::gen_vec(state));
docker_controls.start();
Self {
created,
cpu_stats: VecDeque::with_capacity(60),
created,
docker_controls,
id,
image: image.into(),
@@ -533,6 +587,7 @@ impl ContainerItem {
mem_limit: ByteStats::default(),
mem_stats: VecDeque::with_capacity(60),
name: name.into(),
ports,
rx: ByteStats::default(),
state,
status,
@@ -594,7 +649,7 @@ impl ContainerItem {
}
/// Container information panel headings + widths, for nice pretty formatting
#[derive(Debug, Clone, Copy)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Columns {
pub name: (Header, u8),
pub state: (Header, u8),
@@ -623,3 +678,98 @@ impl Columns {
}
}
}
#[cfg(test)]
mod tests {
use ratatui::widgets::ListItem;
use crate::{
app_data::{ContainerImage, Logs},
ui::log_sanitizer,
};
use super::{ByteStats, ContainerName, CpuStats, LogsTz};
#[test]
// Display CpuStats as a string
fn test_container_state_cpustats_to_string() {
let test = |f: f64, s: &str| {
assert_eq!(CpuStats::new(f).to_string(), s);
};
test(0.0, "00.00%");
test(1.5, "01.50%");
test(15.15, "15.15%");
test(150.15, "150.15%");
}
#[test]
// Display bytestats as a string, convert into correct data unit (Kb, MB, GB)
fn test_container_state_bytestats_to_string() {
let test = |u: u64, s: &str| {
assert_eq!(ByteStats::new(u).to_string(), s);
};
test(0, "0.00 kB");
test(150, "0.15 kB");
test(1500, "1.50 kB");
test(150_000, "150.00 kB");
test(1_500_000, "1.50 MB");
test(15_000_000, "15.00 MB");
test(150_000_000, "150.00 MB");
test(1_500_000_000, "1.50 GB");
test(15_000_000_000, "15.00 GB");
test(150_000_000_000, "150.00 GB");
}
#[test]
/// ContainerName as string truncated correctly
fn test_container_state_container_name_to_string() {
let result = ContainerName::from("name_01");
assert_eq!(result.to_string(), "name_01");
let result = ContainerName::from("name_01_name_01_name_01_name_01_");
assert_eq!(result.to_string(), "name_01_name_01_name_01_name_…");
let result = result.get();
assert_eq!(result, "name_01_name_01_name_01_name_01_");
}
#[test]
/// ContainerImage as string truncated correctly
fn test_container_state_container_image() {
let result = ContainerImage::from("name_01");
assert_eq!(result.to_string(), "name_01");
let result = ContainerImage::from("name_01_name_01_name_01_name_01_");
assert_eq!(result.to_string(), "name_01_name_01_name_01_name_…");
let result = result.get();
assert_eq!(result, "name_01_name_01_name_01_name_01_");
}
#[test]
/// Logs can only contain 1 entry per LogzTz
fn test_container_state_logz() {
let input = "2023-01-14T19:13:30.783138328Z Lorem ipsum dolor sit amet";
let tz = LogsTz::from(input);
let mut logs = Logs::default();
let line = log_sanitizer::remove_ansi(input);
logs.insert(ListItem::new(line.clone()), tz.clone());
logs.insert(ListItem::new(line.clone()), tz.clone());
logs.insert(ListItem::new(line), tz);
assert_eq!(logs.logs.items.len(), 1);
let input = "2023-01-15T19:13:30.783138328Z Lorem ipsum dolor sit amet";
let tz = LogsTz::from(input);
let line = log_sanitizer::remove_ansi(input);
logs.insert(ListItem::new(line.clone()), tz.clone());
logs.insert(ListItem::new(line.clone()), tz.clone());
logs.insert(ListItem::new(line), tz);
assert_eq!(logs.logs.items.len(), 2);
}
}
+1325 -150
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -14,6 +14,6 @@ pub enum DockerMessage {
Restart(ContainerId),
Start(ContainerId),
Stop(ContainerId),
Unpause(ContainerId),
Resume(ContainerId),
Update,
}
+148 -6
View File
@@ -71,6 +71,7 @@ pub struct DockerData {
impl DockerData {
/// Use docker stats to calculate current cpu usage
#[allow(clippy::cast_precision_loss)]
// FIX: this can overflow
fn calculate_usage(stats: &Stats) -> f64 {
let mut cpu_percentage = 0.0;
let previous_cpu = stats.precpu_stats.cpu_usage.total_usage;
@@ -150,7 +151,7 @@ impl DockerData {
app_data
.lock()
.update_stats(&id, cpu_stats, mem_stat, mem_limit, rx, tx);
.update_stats_by_id(&id, cpu_stats, mem_stat, mem_limit, rx, tx);
}
}
spawns.lock().remove(&spawn_id);
@@ -162,7 +163,6 @@ impl DockerData {
/// Update all stats, spawn each container into own tokio::spawn thread
fn update_all_container_stats(&mut self, all_ids: &[(State, ContainerId)]) {
for (state, id) in all_ids {
// let init = self.init.as_ref().map_or_else(|| None, |x| Some((Arc::clone(x), all_ids.len())));
let docker = Arc::clone(&self.docker);
let app_data = Arc::clone(&self.app_data);
let spawns = Arc::clone(&self.spawns);
@@ -387,11 +387,11 @@ impl DockerData {
});
self.update_everything().await;
}
DockerMessage::Unpause(id) => {
DockerMessage::Resume(id) => {
tokio::spawn(async move {
let handle = GuiState::start_loading_animation(&gui_state, uuid);
if docker.unpause_container(id.get()).await.is_err() {
Self::set_error(&app_data, DockerControls::Unpause, &gui_state);
Self::set_error(&app_data, DockerControls::Resume, &gui_state);
}
gui_state.lock().stop_loading_animation(&handle, uuid);
});
@@ -436,7 +436,7 @@ impl DockerData {
}
/// Send an update message every x ms, where x is the args.docker_interval
fn croner(args: &CliArgs, docker_tx: Sender<DockerMessage>) {
fn scheduler(args: &CliArgs, docker_tx: Sender<DockerMessage>) {
let update_duration = std::time::Duration::from_millis(u64::from(args.docker_interval));
let mut now = std::time::Instant::now();
tokio::spawn(async move {
@@ -472,10 +472,152 @@ impl DockerData {
spawns: Arc::new(Mutex::new(HashMap::new())),
};
inner.initialise_container_data().await;
Self::croner(&args, docker_tx);
Self::scheduler(&args, docker_tx);
inner.message_handler().await;
}
}
}
// tests, use redis-test container, check logs exists, and selector of logs, and that it increases, and matches end, when you run restart on the docker containers
#[cfg(test)]
mod tests {
use bollard::container::{
BlkioStats, CPUStats, CPUUsage, MemoryStats, PidsStats, StorageStats, ThrottlingData,
};
use super::*;
#[allow(clippy::too_many_lines)]
fn gen_stats(x: u64, y: u64) -> Stats {
Stats {
read: String::new(),
preread: String::new(),
num_procs: 0,
pids_stats: PidsStats {
current: None,
limit: None,
},
network: None,
networks: None,
memory_stats: MemoryStats {
stats: None,
max_usage: None,
usage: None,
failcnt: None,
limit: None,
commit: None,
commit_peak: None,
commitbytes: None,
commitpeakbytes: None,
privateworkingset: None,
},
blkio_stats: BlkioStats {
io_service_bytes_recursive: None,
io_serviced_recursive: None,
io_queue_recursive: None,
io_service_time_recursive: None,
io_wait_time_recursive: None,
io_merged_recursive: None,
io_time_recursive: None,
sectors_recursive: None,
},
cpu_stats: CPUStats {
cpu_usage: CPUUsage {
percpu_usage: Some(vec![
291_593_800,
182_192_900,
195_048_700,
23_032_300,
132_928_700,
235_555_600,
120_225_700,
175_752_000,
213_060_300,
95_321_600,
226_821_000,
0,
109_151_300,
0,
86_240_200,
1_884_400,
59_077_300,
23_224_900,
95_386_300,
144_987_400,
]),
total_usage: 250_000_000,
usage_in_usermode: 1_020_000_000,
usage_in_kernelmode: 1_030_000_000,
},
system_cpu_usage: Some(x),
online_cpus: Some(1),
throttling_data: ThrottlingData {
periods: 0,
throttled_periods: 0,
throttled_time: 0,
},
},
precpu_stats: CPUStats {
cpu_usage: CPUUsage {
percpu_usage: Some(vec![
291_593_800,
182_192_900,
195_048_700,
23_032_300,
132_928_700,
235_555_600,
120_225_700,
175_752_000,
213_060_300,
95_321_600,
226_821_000,
0,
109_151_300,
0,
86_240_200,
1_884_400,
59_077_300,
23_224_900,
93_831_100,
144_987_400,
]),
total_usage: 200_000_000,
usage_in_usermode: 1_020_000_000,
usage_in_kernelmode: 1_020_000_000,
},
system_cpu_usage: Some(y),
online_cpus: Some(1),
throttling_data: ThrottlingData {
periods: 0,
throttled_periods: 0,
throttled_time: 0,
},
},
storage_stats: StorageStats {
read_count_normalized: None,
read_size_bytes: None,
write_count_normalized: None,
write_size_bytes: None,
},
name: "/container_1".to_owned(),
id: "1".to_owned(),
}
}
#[test]
#[allow(clippy::float_cmp)]
/// Test the stats calculator, had to cheat here to get round input/outputs
fn test_calculate_usage_no_previous_cpu() {
let stats = gen_stats(1_000_000_000, 900_000_000);
let result = DockerData::calculate_usage(&stats);
assert_eq!(result, 50.0);
let stats = gen_stats(1_000_000_000, 800_000_000);
let result = DockerData::calculate_usage(&stats);
assert_eq!(result, 25.0);
let stats = gen_stats(1_000_000_000, 750_000_000);
let result = DockerData::calculate_usage(&stats);
assert_eq!(result, 20.00);
}
}
+8 -8
View File
@@ -268,11 +268,11 @@ impl InputHandler {
// This isn't great, just means you can't send docker commands before full initialization of the program
let panel = self.gui_state.lock().get_selected_panel();
if panel == SelectablePanel::Commands {
let option_command = self.app_data.lock().selected_docker_command();
let option_command = self.app_data.lock().selected_docker_controls();
if let Some(command) = option_command {
// Poor way of disallowing commands to be sent to a containerised okxer
if self.app_data.lock().is_oxker() {
if self.app_data.lock().is_oxker_in_container() {
return;
};
let option_id = self.app_data.lock().get_selected_container_id();
@@ -286,8 +286,8 @@ impl InputHandler {
DockerControls::Pause => {
self.docker_tx.send(DockerMessage::Pause(id)).await.ok()
}
DockerControls::Unpause => {
self.docker_tx.send(DockerMessage::Unpause(id)).await.ok()
DockerControls::Resume => {
self.docker_tx.send(DockerMessage::Resume(id)).await.ok()
}
DockerControls::Start => {
self.docker_tx.send(DockerMessage::Start(id)).await.ok()
@@ -337,7 +337,7 @@ impl InputHandler {
match selected_panel {
SelectablePanel::Containers => locked_data.containers_start(),
SelectablePanel::Logs => locked_data.log_start(),
SelectablePanel::Commands => locked_data.docker_command_start(),
SelectablePanel::Commands => locked_data.docker_controls_start(),
}
}
@@ -348,7 +348,7 @@ impl InputHandler {
match selected_panel {
SelectablePanel::Containers => locked_data.containers_end(),
SelectablePanel::Logs => locked_data.log_end(),
SelectablePanel::Commands => locked_data.docker_command_end(),
SelectablePanel::Commands => locked_data.docker_controls_end(),
}
}
@@ -481,7 +481,7 @@ impl InputHandler {
match selected_panel {
SelectablePanel::Containers => locked_data.containers_next(),
SelectablePanel::Logs => locked_data.log_next(),
SelectablePanel::Commands => locked_data.docker_command_next(),
SelectablePanel::Commands => locked_data.docker_controls_next(),
};
}
@@ -492,7 +492,7 @@ impl InputHandler {
match selected_panel {
SelectablePanel::Containers => locked_data.containers_previous(),
SelectablePanel::Logs => locked_data.log_previous(),
SelectablePanel::Commands => locked_data.docker_command_previous(),
SelectablePanel::Commands => locked_data.docker_controls_previous(),
}
}
}
+89
View File
@@ -164,3 +164,92 @@ async fn main() {
}
}
}
#[cfg(test)]
#[allow(clippy::unwrap_used, clippy::many_single_char_names, unused)]
mod tests {
use bollard::service::{ContainerSummary, Port};
use crate::{
app_data::{AppData, ContainerId, ContainerItem, ContainerPorts, State, StatefulList},
parse_args::CliArgs,
};
pub const fn gen_args() -> CliArgs {
CliArgs {
color: false,
docker_interval: 1000,
gui: true,
host: None,
in_container: false,
save_dir: None,
raw: false,
show_self: false,
timestamp: false,
use_cli: false,
}
}
pub fn gen_item(id: &ContainerId, index: usize) -> ContainerItem {
ContainerItem::new(
u64::try_from(index).unwrap(),
id.clone(),
format!("image_{index}"),
false,
format!("container_{index}"),
vec![ContainerPorts {
ip: None,
private: u16::try_from(index).unwrap_or(1) + 8000,
public: None,
}],
State::Running,
format!("Up {index} hour"),
)
}
pub fn gen_appdata(containers: &[ContainerItem]) -> AppData {
AppData {
containers: StatefulList::new(containers.to_vec()),
error: None,
sorted_by: None,
args: gen_args(),
}
}
pub fn gen_containers() -> (Vec<ContainerId>, Vec<ContainerItem>) {
let ids = (1..=3)
.map(|i| ContainerId::from(format!("{i}").as_str()))
.collect::<Vec<_>>();
let containers = ids
.iter()
.enumerate()
.map(|(index, id)| gen_item(id, index + 1))
.collect::<Vec<_>>();
(ids, containers)
}
pub fn gen_container_summary(index: usize, state: &str) -> ContainerSummary {
ContainerSummary {
id: Some(format!("{index}")),
names: Some(vec![format!("container_{}", index)]),
image: Some(format!("image_{index}")),
image_id: Some(format!("{index}")),
command: None,
created: Some(i64::try_from(index).unwrap()),
ports: Some(vec![Port {
ip: None,
private_port: u16::try_from(index).unwrap_or(1) + 8000,
public_port: None,
typ: None,
}]),
size_rw: None,
size_root_fs: None,
labels: None,
state: Some(state.to_owned()),
status: Some(format!("Up {index} hour")),
host_config: None,
network_settings: None,
mounts: None,
}
}
}
+76
View File
@@ -72,3 +72,79 @@ pub mod log_sanitizer {
}
}
}
#[cfg(test)]
mod tests {
use ratatui::{
style::{Color, Style},
text::{Line, Span},
};
use super::log_sanitizer;
// This spells out "oxker", with each char having a foreground and background colour
const INPUT: &str = "\x1b[31;47mo\x1b[32;40mx\x1b[33;41mk\x1b[34;42me\x1b[35;43mr\x1b[0m";
#[test]
/// Return test raw, as in show escape codes
fn color_match_raw() {
let result = log_sanitizer::raw(INPUT);
let expected = vec![Line {
spans: [Span {
content: std::borrow::Cow::Borrowed(
"\x1b[31;47mo\x1b[32;40mx\x1b[33;41mk\x1b[34;42me\x1b[35;43mr\x1b[0m",
),
style: Style::default(),
}]
.to_vec(),
alignment: None,
}];
assert_eq!(result, expected);
}
#[test]
// Use the escape codes to colorize the text
fn color_match_colorize() {
let result = log_sanitizer::colorize_logs(INPUT);
let expected = vec![Line {
spans: vec![
Span {
content: std::borrow::Cow::Borrowed("o"),
style: Style::default().fg(Color::Red).bg(Color::White),
},
Span {
content: std::borrow::Cow::Borrowed("x"),
style: Style::default().fg(Color::Green).bg(Color::Black),
},
Span {
content: std::borrow::Cow::Borrowed("k"),
style: Style::default().fg(Color::Yellow).bg(Color::Red),
},
Span {
content: std::borrow::Cow::Borrowed("e"),
style: Style::default().fg(Color::Blue).bg(Color::Green),
},
Span {
content: std::borrow::Cow::Borrowed("r"),
style: Style::default().fg(Color::Magenta).bg(Color::Yellow),
},
],
alignment: None,
}];
assert_eq!(result, expected);
}
#[test]
// Remove all escape ansi codes from given input
fn color_match_remove_ansi() {
let result = log_sanitizer::remove_ansi(INPUT);
let expected = vec![Line {
spans: vec![Span {
content: std::borrow::Cow::Borrowed("oxker"),
style: Style::default(),
}],
alignment: None,
}];
assert_eq!(result, expected);
}
}
+2145 -65
View File
File diff suppressed because it is too large Load Diff
+20 -30
View File
@@ -217,22 +217,6 @@ impl Ui {
}
}
#[cfg(not(debug_assertions))]
fn get_wholelayout(f: &Frame) -> std::rc::Rc<[ratatui::layout::Rect]> {
Layout::default()
.direction(Direction::Vertical)
.constraints([Constraint::Min(1), Constraint::Min(100)].as_ref())
.split(f.size())
}
#[cfg(debug_assertions)]
fn get_wholelayout(f: &Frame) -> std::rc::Rc<[ratatui::layout::Rect]> {
Layout::default()
.direction(Direction::Vertical)
.constraints([Constraint::Min(1), Constraint::Min(1), Constraint::Min(100)].as_ref())
.split(f.size())
}
/// Frequent data required by multiple framde drawing functions, can reduce mutex reads by placing it all in here
#[derive(Debug)]
pub struct FrameData {
@@ -279,21 +263,16 @@ impl From<(MutexGuard<'_, AppData>, MutexGuard<'_, GuiState>)> for FrameData {
fn draw_frame(f: &mut Frame, app_data: &Arc<Mutex<AppData>>, gui_state: &Arc<Mutex<GuiState>>) {
let fd = FrameData::from((app_data.lock(), gui_state.lock()));
let whole_layout = get_wholelayout(f);
#[cfg(debug_assertions)]
draw_blocks::debug_bar(whole_layout[0], f, app_data.lock().get_debug_string());
#[cfg(debug_assertions)]
let whole_layout_split = (1, 2);
#[cfg(not(debug_assertions))]
let whole_layout_split = (0, 1);
let whole_layout = Layout::default()
.direction(Direction::Vertical)
.constraints([Constraint::Min(1), Constraint::Min(100)].as_ref())
.split(f.size());
// Split into 3, containers+controls, logs, then graphs
let upper_main = Layout::default()
.direction(Direction::Vertical)
.constraints([Constraint::Max(fd.height), Constraint::Percentage(50)].as_ref())
.split(whole_layout[whole_layout_split.1]);
.split(whole_layout[1]);
let top_split = if fd.has_containers {
vec![Constraint::Percentage(90), Constraint::Percentage(10)]
@@ -307,7 +286,7 @@ fn draw_frame(f: &mut Frame, app_data: &Arc<Mutex<AppData>>, gui_state: &Arc<Mut
.split(upper_main[0]);
let lower_split = if fd.has_containers {
vec![Constraint::Percentage(75), Constraint::Percentage(25)]
vec![Constraint::Percentage(70), Constraint::Percentage(20)]
} else {
vec![Constraint::Percentage(100)]
};
@@ -318,11 +297,11 @@ fn draw_frame(f: &mut Frame, app_data: &Arc<Mutex<AppData>>, gui_state: &Arc<Mut
.constraints(lower_split)
.split(upper_main[1]);
draw_blocks::containers(app_data, top_panel[0], f, &fd, gui_state, &fd.columns);
draw_blocks::containers(app_data, top_panel[0], f, &fd, gui_state);
draw_blocks::logs(app_data, lower_main[0], f, &fd, gui_state);
draw_blocks::heading_bar(whole_layout[whole_layout_split.0], f, &fd, gui_state);
draw_blocks::heading_bar(whole_layout[0], f, &fd, gui_state);
if let Some(id) = fd.delete_confirm.as_ref() {
app_data.lock().get_container_name_by_id(id).map_or_else(
@@ -340,7 +319,18 @@ fn draw_frame(f: &mut Frame, app_data: &Arc<Mutex<AppData>>, gui_state: &Arc<Mut
// only draw commands + charts if there are containers
if fd.has_containers {
draw_blocks::commands(app_data, top_panel[1], f, &fd, gui_state);
draw_blocks::chart(f, lower_main[1], app_data);
// Can calculate the max string length here, and then use that to keep the ports section as small as possible (+4 for some padding + border)
let max_lens = app_data.lock().get_longest_port();
let ports_len = u16::try_from(max_lens.0 + max_lens.1 + max_lens.2 + 2).unwrap_or(26);
let lower = Layout::default()
.direction(Direction::Horizontal)
.constraints([Constraint::Min(1), Constraint::Max(ports_len)])
.split(lower_main[1]);
draw_blocks::chart(f, lower[0], app_data);
draw_blocks::ports(f, lower[1], app_data, max_lens);
}
if let Some((text, instant)) = fd.info_text {