diff --git a/.github/release-body.md b/.github/release-body.md index 6e8fc56..f7ab0af 100644 --- a/.github/release-body.md +++ b/.github/release-body.md @@ -1,23 +1,25 @@ -### 2024-01-18 +### 2024-02-14 ### Chores -+ dependencies updated, [53b4bafbe53312fe41608ddf33e865d474222aaa], [58ef151600e362048a607c8ae61a5edfe80ab1dd], [b6fd35022a99ec0e982ddb154b0450d49c4840e9], [0438c108bdd9815d7eae1b89c47c4e6438f358d6] -+ files formatted, [1806165c3e266876b2d1806f7b662d09705f3aad] -+ create_release.sh check for unused lint, [d0b27211928f93f8455e1ee5a6a6485c6a21d382] ++ create_release v0.5.5, [616338b7107036e968f51c3ff80739f9ffb40fbd] ++ update dependencies, [10180d2e0817c00a198e27f7d71080c502639a6b] ++ update to ratatui v0.26.0, [d33dce3eec4c19cc3c3668dab77f7d25d6970c3c] ++ GitHub workflow dependency bump, [0314eac9df6cf9fea1943dcd06bd6a0b27131c16] ### Docs -= Readme updated, screenshot added, [7561a93415c1e1f596b15edba95e7b32a939cd90], [4069e5572f81cb689dbb9f735db919e4636cdccc] - -### Features -+ Ports section added, closes #21, [65a1afcb0605604ede350a5630c775f94ebb74ee], [7a096a65c40924021fe643fe0aa1067095832df9] ++ screenshot updated, [fe5ec4f5dd25f11817be37f3f1867a6a2b0afc42] ### Fixes -+ sort arrow now on left of header, [40ddcb727d2c1758d6dd26a58507b85b219f51e2] ++ ports all listed in white, [d3b23585b38045eb3bc827367eca90eb7f7a7dd5] ++ use long container name in delete popup, [6202b7bbfdfb04a94959b5143dac3f1aa59cd336] ++ memory display, closes #33, [a182d40a7463164ef5dcac379d1a1768d77209d2] ### Refactors -+ rename string_wrapper > unit_struct, [27cf53e41f8b379f606c1c27620ee08e79bac57e] ++ use &[T] instead of &Vec, [76cd08ab2f98687a866a6bbb4fa93bbdedaa7699], [1f62bb50210f2d66bb7215e42e8b21a3c1a6ec06] ++ draw_block constraints into consts, [0436ff1b7356c80532048c7d497c66d331092b01] ### 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] ++ update port test with new colour, [f74ae3f5c34d74b78822078291fed401427c4cba] ++ color match tests updated, [5b287416315942b19c62f8c66348ce28462d894c] see CHANGELOG.md for more details diff --git a/.github/screenshot_01.png b/.github/screenshot_01.png index 383a567..8355605 100644 Binary files a/.github/screenshot_01.png and b/.github/screenshot_01.png differ diff --git a/.github/workflows/create_release_and_build.yml b/.github/workflows/create_release_and_build.yml index fedb00a..7540321 100644 --- a/.github/workflows/create_release_and_build.yml +++ b/.github/workflows/create_release_and_build.yml @@ -56,7 +56,7 @@ jobs: # Upload output for release page - name: Upload Artifacts - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: if-no-files-found: error name: ${{ matrix.target }} @@ -75,7 +75,7 @@ jobs: uses: actions/checkout@v4 - name: Setup | Artifacts - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 - name: Update Release uses: ncipollo/release-action@v1 diff --git a/CHANGELOG.md b/CHANGELOG.md index 94a81a2..a4d42e1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,28 @@ +# v0.6.1 +### 2024-02-14 + +### Chores ++ create_release v0.5.5, [616338b7](https://github.com/mrjackwills/oxker/commit/616338b7107036e968f51c3ff80739f9ffb40fbd) ++ update dependencies, [10180d2e](https://github.com/mrjackwills/oxker/commit/10180d2e0817c00a198e27f7d71080c502639a6b) ++ update to ratatui v0.26.0, [d33dce3e](https://github.com/mrjackwills/oxker/commit/d33dce3eec4c19cc3c3668dab77f7d25d6970c3c) ++ GitHub workflow dependency bump, [0314eac9](https://github.com/mrjackwills/oxker/commit/0314eac9df6cf9fea1943dcd06bd6a0b27131c16) + +### Docs ++ screenshot updated, [fe5ec4f5](https://github.com/mrjackwills/oxker/commit/fe5ec4f5dd25f11817be37f3f1867a6a2b0afc42) + +### Fixes ++ ports all listed in white, [d3b23585](https://github.com/mrjackwills/oxker/commit/d3b23585b38045eb3bc827367eca90eb7f7a7dd5) ++ use long container name in delete popup, [6202b7bb](https://github.com/mrjackwills/oxker/commit/6202b7bbfdfb04a94959b5143dac3f1aa59cd336) ++ memory display, closes [#33](https://github.com/mrjackwills/oxker/issues/33), [a182d40a](https://github.com/mrjackwills/oxker/commit/a182d40a7463164ef5dcac379d1a1768d77209d2) + +### Refactors ++ use &[T] instead of &Vec, [76cd08ab](https://github.com/mrjackwills/oxker/commit/76cd08ab2f98687a866a6bbb4fa93bbdedaa7699), [1f62bb50](https://github.com/mrjackwills/oxker/commit/1f62bb50210f2d66bb7215e42e8b21a3c1a6ec06) ++ draw_block constraints into consts, [0436ff1b](https://github.com/mrjackwills/oxker/commit/0436ff1b7356c80532048c7d497c66d331092b01) + +### Tests ++ update port test with new colour, [f74ae3f5](https://github.com/mrjackwills/oxker/commit/f74ae3f5c34d74b78822078291fed401427c4cba) ++ color match tests updated, [5b287416](https://github.com/mrjackwills/oxker/commit/5b287416315942b19c62f8c66348ce28462d894c) + # v0.6.0 ### 2024-01-18 diff --git a/Cargo.lock b/Cargo.lock index c67ea51..75cbe5b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -19,9 +19,9 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "ahash" -version = "0.8.7" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77c3a9648d43b9cd48db467b3f87fdd6e146bcc88ab0180006cef2179fe11d01" +checksum = "42cd52102d3df161c77a887b608d7a4897d7cc112886a9537b738a887a03aaff" dependencies = [ "cfg-if", "once_cell", @@ -66,9 +66,9 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.4" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87" +checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc" [[package]] name = "anstyle-parse" @@ -207,6 +207,15 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53" +[[package]] +name = "castaway" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a17ed5635fc8536268e5d4de1e22e81ac34419e5f052d4d51f4e01dcc263fcc" +dependencies = [ + "rustversion", +] + [[package]] name = "cc" version = "1.0.83" @@ -224,22 +233,22 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.31" +version = "0.4.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38" +checksum = "5bc015644b92d5890fab7489e49d21f879d5c990186827d42ec511919404f38b" dependencies = [ "android-tzdata", "iana-time-zone", "num-traits", "serde", - "windows-targets 0.48.5", + "windows-targets 0.52.0", ] [[package]] name = "clap" -version = "4.4.18" +version = "4.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e578d6ec4194633722ccf9544794b71b1385c3c027efe0c55db226fc880865c" +checksum = "80c21025abd42669a92efc996ef13cfb2c5c627858421ea58d5c3b331a6c134f" dependencies = [ "clap_builder", "clap_derive", @@ -247,9 +256,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.4.18" +version = "4.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4df4df40ec50c46000231c914968278b1eb05098cf8f1b3a518a95030e71d1c7" +checksum = "458bf1f341769dfcf849846f65dffdf9146daa56bcd2a47cb4e1de9915567c99" dependencies = [ "anstream", "anstyle", @@ -261,9 +270,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.4.7" +version = "4.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442" +checksum = "307bc0538d5f0f83b8248db3087aa92fe504e4691294d0c96c0eabc33f47ba47" dependencies = [ "heck", "proc-macro2", @@ -273,9 +282,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.6.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" +checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" [[package]] name = "colorchoice" @@ -283,6 +292,19 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" +[[package]] +name = "compact_str" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f86b9c4c00838774a6d902ef931eff7470720c51d90c2e32cfe15dc304737b3f" +dependencies = [ + "castaway", + "cfg-if", + "itoa", + "ryu", + "static_assertions", +] + [[package]] name = "core-foundation-sys" version = "0.8.6" @@ -347,9 +369,9 @@ dependencies = [ [[package]] name = "either" -version = "1.9.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" +checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" [[package]] name = "equivalent" @@ -453,7 +475,7 @@ dependencies = [ "futures-sink", "futures-util", "http", - "indexmap 2.1.0", + "indexmap 2.2.3", "slab", "tokio", "tokio-util", @@ -484,9 +506,9 @@ checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] name = "hermit-abi" -version = "0.3.4" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d3d0e0f38255e7fa3cf31335b3a56f05febd18025f4db5ef7a0cfb4f8da651f" +checksum = "bd5256b483761cd23699d0da46cc6fd2ee3be420bbe6d020ae4a091e70b7e9fd" [[package]] name = "hex" @@ -567,9 +589,9 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.59" +version = "0.1.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6a67363e2aa4443928ce15e57ebae94fd8949958fd1223c4cfc0cd473ad7539" +checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -611,9 +633,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.1.0" +version = "2.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" +checksum = "233cf39063f058ea2caae4091bf4a3ef70a653afbc026f5c4a4135d114e3c177" dependencies = [ "equivalent", "hashbrown 0.14.3", @@ -628,9 +650,9 @@ checksum = "1e186cfbae8084e513daff4240b4797e342f988cecda4fb6c939150f96315fd8" [[package]] name = "itertools" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25db6b064527c5d482d0423354fcd07a89a2dfe07b67892e62411946db7f07b0" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" dependencies = [ "either", ] @@ -643,9 +665,9 @@ checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" [[package]] name = "js-sys" -version = "0.3.67" +version = "0.3.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a1d36f1235bc969acba30b7f5990b864423a6068a10f7c90ae8f0112e3a59d1" +checksum = "406cda4b368d531c842222cf9d2600a9a4acce8d29423695379c6868a143a9ee" dependencies = [ "wasm-bindgen", ] @@ -658,9 +680,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.152" +version = "0.2.153" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" [[package]] name = "libredox" @@ -691,9 +713,9 @@ checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" [[package]] name = "lru" -version = "0.12.1" +version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2994eeba8ed550fd9b47a0b38f0242bc3344e496483c6180b69139cc2fa5d1d7" +checksum = "db2c024b41519440580066ba82aab04092b333e09066a5eb86c7c4890df31f22" dependencies = [ "hashbrown 0.14.3", ] @@ -706,9 +728,9 @@ checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" [[package]] name = "miniz_oxide" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" dependencies = [ "adler", ] @@ -735,11 +757,17 @@ dependencies = [ "winapi", ] +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + [[package]] name = "num-traits" -version = "0.2.17" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" +checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" dependencies = [ "autocfg", ] @@ -783,7 +811,7 @@ checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" [[package]] name = "oxker" -version = "0.6.0" +version = "0.6.1" dependencies = [ "anyhow", "bollard", @@ -837,18 +865,18 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pin-project" -version = "1.1.3" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422" +checksum = "0302c4a0442c456bd56f841aee5c3bfd17967563f6fadc9ceb9f9c23cf3807e0" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.3" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" +checksum = "266c042b60c9c76b8d53061e52b2e0d1116abc57cefc8c5cd671619a56ac3690" dependencies = [ "proc-macro2", "quote", @@ -881,9 +909,9 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "proc-macro2" -version = "1.0.76" +version = "1.0.78" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95fc56cda0b5c3325f5fbbd7ff9fda9e02bb00bb3dac51252d2f1bfa1cb8cc8c" +checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" dependencies = [ "unicode-ident", ] @@ -929,12 +957,13 @@ dependencies = [ [[package]] name = "ratatui" -version = "0.25.0" +version = "0.26.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5659e52e4ba6e07b2dad9f1158f578ef84a73762625ddb51536019f34d180eb" +checksum = "bcb12f8fbf6c62614b0d56eb352af54f6a22410c3b079eb53ee93c7b97dd31d8" dependencies = [ "bitflags 2.4.2", "cassowary", + "compact_str", "crossterm", "indoc", "itertools", @@ -992,18 +1021,18 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "serde" -version = "1.0.195" +version = "1.0.196" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63261df402c67811e9ac6def069e4786148c4563f4b50fd4bf30aa370d626b02" +checksum = "870026e60fa08c69f064aa766c10f10b1d62db9ccd4d0abb206472bee0ce3b32" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.195" +version = "1.0.196" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46fe8f8603d81ba86327b23a2e9cdf49e1255fb94a4c5f297f6ee0547178ea2c" +checksum = "33c85360c95e7d137454dc81d9a4ed2b8efd8fbe19cee57357b32b9771fccb67" dependencies = [ "proc-macro2", "quote", @@ -1012,9 +1041,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.111" +version = "1.0.113" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "176e46fa42316f18edd598015a5166857fc835ec732f5215eac6b7bdbf0a84f4" +checksum = "69801b70b1c3dac963ecb03a364ba0ceda9cf60c71cfe475e99864759c8b8a79" dependencies = [ "itoa", "ryu", @@ -1046,16 +1075,17 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.4.0" +version = "3.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64cd236ccc1b7a29e7e2739f27c0b2dd199804abc4290e32f59f3b68d6405c23" +checksum = "15d167997bd841ec232f5b2b8e0e26606df2e7caa4c31b95ea9ca52b200bd270" dependencies = [ "base64", "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.1.0", + "indexmap 2.2.3", "serde", + "serde_derive", "serde_json", "time", ] @@ -1110,9 +1140,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.13.0" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b187f0231d56fe41bfb12034819dd2bf336422a5866de41bc3fec4b2e3883e8" +checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" [[package]] name = "socket2" @@ -1134,26 +1164,32 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + [[package]] name = "strsim" -version = "0.10.0" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +checksum = "5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01" [[package]] name = "strum" -version = "0.25.0" +version = "0.26.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125" +checksum = "723b93e8addf9aa965ebe2d11da6d7540fa2283fcea14b3371ff055f7ba13f5f" dependencies = [ "strum_macros", ] [[package]] name = "strum_macros" -version = "0.25.3" +version = "0.26.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23dc1fa9ac9c169a78ba62f0b841814b7abae11bdd047b9c58f893439e309ea0" +checksum = "7a3417fc93d76740d974a01654a09777cb500428cc874ca9f45edfe0c4d4cd18" dependencies = [ "heck", "proc-macro2", @@ -1186,18 +1222,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.56" +version = "1.0.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad" +checksum = "1e45bcbe8ed29775f228095caf2cd67af7a4ccf756ebff23a306bf3e8b47b24b" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.56" +version = "1.0.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471" +checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81" dependencies = [ "proc-macro2", "quote", @@ -1216,12 +1252,13 @@ dependencies = [ [[package]] name = "time" -version = "0.3.31" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f657ba42c3f86e7680e53c8cd3af8abbe56b5491790b46e22e19c0d57463583e" +checksum = "c8248b6521bb14bc45b4067159b9b6ad792e2d6d754d6c41fb50e29fefe38749" dependencies = [ "deranged", "itoa", + "num-conv", "powerfmt", "serde", "time-core", @@ -1236,10 +1273,11 @@ checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "time-macros" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26197e33420244aeb70c3e8c78376ca46571bc4e701e4791c2cd9f57dcb3a43f" +checksum = "7ba3a3ef41e6672a2f0f001392bb5dcd3ff0a9992d618ca761a11c3121547774" dependencies = [ + "num-conv", "time-core", ] @@ -1260,9 +1298,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.35.1" +version = "1.36.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c89b4efa943be685f629b149f53829423f8f5531ea21249408e8e2f8671ec104" +checksum = "61285f6515fa018fb2d1e46eb21223fff441ee8db5d0f1435e8ab4f5cdb80931" dependencies = [ "backtrace", "bytes", @@ -1403,9 +1441,9 @@ dependencies = [ [[package]] name = "unicode-segmentation" -version = "1.10.1" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" +checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" [[package]] name = "unicode-width" @@ -1432,9 +1470,9 @@ checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" [[package]] name = "uuid" -version = "1.6.1" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e395fcf16a7a3d8127ec99782007af141946b4795001f876d54fb0d55978560" +checksum = "f00cc9702ca12d3c81455259621e676d0f7251cec66a21e98fe2e9a37db93b2a" dependencies = [ "getrandom", "rand", @@ -1469,9 +1507,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.90" +version = "0.2.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1223296a201415c7fad14792dbefaace9bd52b62d33453ade1c5b5f07555406" +checksum = "c1e124130aee3fb58c5bdd6b639a0509486b0338acaaae0c84a5124b0f588b7f" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -1479,9 +1517,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.90" +version = "0.2.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcdc935b63408d58a32f8cc9738a0bffd8f05cc7c002086c6ef20b7312ad9dcd" +checksum = "c9e7e1900c352b609c8488ad12639a311045f40a35491fb69ba8c12f758af70b" dependencies = [ "bumpalo", "log", @@ -1494,9 +1532,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.90" +version = "0.2.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e4c238561b2d428924c49815533a8b9121c664599558a5d9ec51f8a1740a999" +checksum = "b30af9e2d358182b5c7449424f017eba305ed32a7010509ede96cdc4696c46ed" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1504,9 +1542,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.90" +version = "0.2.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bae1abb6806dc1ad9e560ed242107c0f6c84335f1749dd4e8ddb012ebd5e25a7" +checksum = "642f325be6301eb8107a83d12a8ac6c1e1c54345a7ef1a9261962dfefda09e66" dependencies = [ "proc-macro2", "quote", @@ -1517,9 +1555,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.90" +version = "0.2.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d91413b1c31d7539ba5ef2451af3f0b833a005eb27a631cec32bc0635a8602b" +checksum = "4f186bd2dcf04330886ce82d6f33dd75a7bfcf69ecf5763b89fcde53b6ac9838" [[package]] name = "winapi" diff --git a/Cargo.toml b/Cargo.toml index 5bcbd65..2321090 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "oxker" -version = "0.6.0" +version = "0.6.1" edition = "2021" authors = ["Jack Wills "] description = "A simple tui to view & control docker containers" @@ -29,16 +29,16 @@ similar_names = "allow" anyhow = "1.0" bollard = "0.15" cansi = "2.2" -clap = { version = "4.4", features = ["color", "derive", "unicode"] } +clap = { version = "4.5", features = ["color", "derive", "unicode"] } crossterm = "0.27" +directories = "5.0" futures-util = "0.3" parking_lot = { version = "0.12" } -tokio = { version = "1.35", features = ["full"] } +ratatui = "0.26" +tokio = { version = "1.36", features = ["full"] } tracing = "0.1" tracing-subscriber = "0.3" -ratatui = "0.25" -uuid = { version = "1.6", features = ["fast-rng", "v4"] } -directories = "5.0" +uuid = { version = "1.7", features = ["fast-rng", "v4"] } [dev-dependencies] diff --git a/create_release.sh b/create_release.sh index 13e8a24..096d9e9 100755 --- a/create_release.sh +++ b/create_release.sh @@ -1,7 +1,6 @@ #!/bin/bash -# rust create_release -# v0.4.1 +# rust create_release v0.5.5 STAR_LINE='****************************************' CWD=$(pwd) @@ -18,6 +17,11 @@ error_close() { exit 1 } +# Check that dialog is installed +if ! [ -x "$(command -v dialog)" ]; then + error_close "dialog is not installed" +fi + # $1 string - question to ask ask_yn() { printf "%b%s? [y/N]:%b " "${GREEN}" "$1" "${RESET}" @@ -29,21 +33,34 @@ user_input() { echo "$data" } +# ask continue, or quit +ask_continue() { + ask_yn "continue" + if [[ ! "$(user_input)" =~ ^y$ ]]; then + exit + fi +} + +# semver major update update_major() { local bumped_major bumped_major=$((MAJOR + 1)) echo "${bumped_major}.0.0" } +# semver minor update update_minor() { local bumped_minor bumped_minor=$((MINOR + 1)) + MINOR=bumped_minor echo "${MAJOR}.${bumped_minor}.0" } +# semver patch update update_patch() { local bumped_patch bumped_patch=$((PATCH + 1)) + PATCH=bumped_patch echo "${MAJOR}.${MINOR}.${bumped_patch}" } @@ -153,14 +170,6 @@ check_tag() { done } -# ask continue, or quit -ask_continue() { - ask_yn "continue" - if [[ ! "$(user_input)" =~ ^y$ ]]; then - exit - fi -} - # run all tests cargo_test() { cargo test -- --test-threads=1 @@ -169,31 +178,55 @@ cargo_test() { # Simulate publishing to crates.io cargo_publish() { + echo -e "${PURPLE}cargo publish --dry-run${RESET}" cargo publish --dry-run ask_continue } -# Build all releases that GitHub workflow would -# This will download GB's of docker images -cargo_build() { - cargo install cross - cargo_clean +# Check to see if cross is installed - if not then install +check_cross() { + if ! [ -x "$(command -v cross)" ]; then + echo -e "${GREEN}cargo install cross${RESET}" + cargo install cross + fi +} + +cargo_build_x86_linux() { + check_cross echo -e "${YELLOW}cross build --target x86_64-unknown-linux-musl --release${RESET}" cross build --target x86_64-unknown-linux-musl --release - ask_continue - cargo_clean +} + +cargo_build_aarch64_linux() { + check_cross echo -e "${YELLOW}cross build --target aarch64-unknown-linux-musl --release${RESET}" cross build --target aarch64-unknown-linux-musl --release - ask_continue - cargo_clean +} + +cargo_build_armv6_linux() { + check_cross echo -e "${YELLOW}cross build --target arm-unknown-linux-musleabihf --release${RESET}" cross build --target arm-unknown-linux-musleabihf --release - ask_continue - cargo_clean +} + +cargo_build_x86_windows() { + check_cross echo -e "${YELLOW}cross build --target x86_64-pc-windows-gnu --release${RESET}" cross build --target x86_64-pc-windows-gnu --release +} + +# Build all releases that GitHub workflow would +# This will download GB's of docker images +cargo_build_all() { + cargo clean + cargo_build_armv6_linux + ask_continue + cargo_build_aarch64_linux + ask_continue + cargo_build_x86_linux + ask_continue + cargo_build_x86_windows ask_continue - cargo_clean } # $1 text to colourise @@ -202,11 +235,6 @@ release_continue() { ask_continue } -# Clean/remove builds, due to issue with cross-rs -cargo_clean() { - echo -e "${YELLOW}cargo clean${RESET}" - cargo clean -} # Check repository for typos check_typos() { echo -e "\n${PURPLE}check typos${RESET}" @@ -214,14 +242,16 @@ check_typos() { ask_continue } -# Make sure the unused lint isn't used +# 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}" + echo "\"#[allow(unused)]\" in ${matches_any}" + ask_continue elif [ -n "$matches_cargo" ]; then - error_close "\"unused = \"allow\"\" in Cargo.toml" + echo "\"unused = \"allow\"\" in Cargo.toml" + ask_continue fi } @@ -234,7 +264,7 @@ release_flow() { get_git_remote_url cargo_test - cargo_build + cargo_build_all cargo_publish cd "${CWD}" || error_close "Can't find ${CWD}" @@ -255,6 +285,7 @@ release_flow() { echo -e "\ncargo fmt" cargo fmt + echo -e "\n${PURPLE}cargo check${RESET}\n" cargo check @@ -267,8 +298,12 @@ release_flow() { release_continue "git checkout main" git checkout main + echo -e "${PURPLE}git pull origin main${RESET}" + git pull origin main + echo -e "${PURPLE}git merge --no-ff \"${RELEASE_BRANCH}\" -m \"chore: merge ${RELEASE_BRANCH} into main\"${RESET}" git merge --no-ff "$RELEASE_BRANCH" -m "chore: merge ${RELEASE_BRANCH} into main" + echo -e "\n${PURPLE}cargo check${RESET}\n" cargo check @@ -291,6 +326,51 @@ release_flow() { git branch -d "$RELEASE_BRANCH" } +build_choice() { + cmd=(dialog --backtitle "Choose option" --radiolist "choose" 14 80 16) + options=( + 1 "x86 musl linux" off + 2 "aarch64 musl linux" off + 3 "armv6 musl linux" off + 4 "x86 windows" off + 5 "all" off + ) + choices=$("${cmd[@]}" "${options[@]}" 2>&1 >/dev/tty) + exitStatus=$? + clear + if [ $exitStatus -ne 0 ]; then + exit + fi + for choice in $choices; do + case $choice in + 0) + exit + ;; + 1) + cargo_build_x86_linux + exit + ;; + 2) + cargo_build_aarch64_linux + exit + ;; + 3) + cargo_build_armv6_linux + exit + ;; + 4) + cargo_build_x86_windows + exit + ;; + 5) + cargo_build_all + exit + ;; + esac + done + +} + main() { cmd=(dialog --backtitle "Choose option" --radiolist "choose" 14 80 16) options=( @@ -319,7 +399,7 @@ main() { break ;; 3) - cargo_build + build_choice main break ;; diff --git a/docker-compose.yml b/docker-compose.yml index 442e95e..b2547f0 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,8 +11,6 @@ services: ipc: private restart: always shm_size: 256MB - ports: - - "127.0.0.1:4040:4040" networks: - oxker-example-net deploy: diff --git a/src/app_data/container_state.rs b/src/app_data/container_state.rs index 53976d6..0dcee3e 100644 --- a/src/app_data/container_state.rs +++ b/src/app_data/container_state.rs @@ -48,7 +48,6 @@ 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! unit_struct { ($name:ident) => { @@ -537,7 +536,6 @@ pub struct ContainerItem { pub mem_limit: ByteStats, pub mem_stats: VecDeque, pub name: ContainerName, - // todo remove option, can be empty vec pub ports: Vec, pub rx: ByteStats, pub state: State, @@ -691,7 +689,7 @@ mod tests { use super::{ByteStats, ContainerName, CpuStats, LogsTz}; #[test] - // Display CpuStats as a string + /// 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); @@ -704,7 +702,7 @@ mod tests { } #[test] - // Display bytestats as a string, convert into correct data unit (Kb, MB, GB) + /// 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); diff --git a/src/app_data/mod.rs b/src/app_data/mod.rs index 557de6b..d0acb9b 100644 --- a/src/app_data/mod.rs +++ b/src/app_data/mod.rs @@ -212,7 +212,7 @@ impl AppData { } /// Get all the ContainerItems - pub const fn get_container_items(&self) -> &Vec { + pub fn get_container_items(&self) -> &[ContainerItem] { &self.containers.items } @@ -383,6 +383,7 @@ impl AppData { } /// Get mutable Option of the currently selected container DockerControls items + /// TODO command or control, need a uniform name across the application pub fn get_control_items(&mut self) -> Option<&mut Vec> { self.get_mut_selected_container() .map(|i| &mut i.docker_controls.items) @@ -1229,7 +1230,7 @@ mod tests { } #[test] - // Get the currently selected container + /// Get the currently selected container fn test_app_data_get_selected_container() { let (_ids, mut containers) = gen_containers(); let mut app_data = gen_appdata(&containers); @@ -1249,7 +1250,7 @@ mod tests { } #[test] - // Get mut container by id + /// Get mut container by id fn test_app_data_get_container_by_id() { let (_ids, mut containers) = gen_containers(); let mut app_data = gen_appdata(&containers); @@ -1259,7 +1260,7 @@ mod tests { } #[test] - // Get just the containers name by id + /// Get just the containers name by id fn test_app_data_get_container_name_by_id() { let (_ids, containers) = gen_containers(); let mut app_data = gen_appdata(&containers); @@ -1269,7 +1270,7 @@ mod tests { } #[test] - // Get the id of the currently selected container + /// Get the id of the currently selected container fn test_app_data_get_selected_container_id() { let (_ids, containers) = gen_containers(); let mut app_data = gen_appdata(&containers); @@ -1383,7 +1384,7 @@ mod tests { "Up 1 hour".to_owned(), ) }; - let mut app_data = gen_appdata(&vec![gen_item_state(state)]); + let mut app_data = gen_appdata(&[gen_item_state(state)]); app_data.containers_start(); app_data.docker_controls_start(); @@ -1832,15 +1833,15 @@ mod tests { fn test_app_data_update_containers() { let (_ids, containers) = gen_containers(); let mut app_data = gen_appdata(&containers); - let result_pre = app_data.get_container_items().clone(); - let mut input = vec![ + let result_pre = app_data.get_container_items().to_owned(); + let mut input = [ gen_container_summary(1, "paused"), gen_container_summary(2, "dead"), ]; app_data.update_containers(&mut input); - let result_post = app_data.get_container_items(); - assert_ne!(&result_pre, result_post); + let result_post = app_data.get_container_items().to_owned(); + assert_ne!(result_pre, result_post); assert_eq!(result_post[0].state, State::Paused); assert_eq!(result_post[1].state, State::Dead); } diff --git a/src/docker_data/mod.rs b/src/docker_data/mod.rs index be8f1f2..302f0d5 100644 --- a/src/docker_data/mod.rs +++ b/src/docker_data/mod.rs @@ -1,7 +1,7 @@ use bollard::{ container::{ - ListContainersOptions, LogsOptions, RemoveContainerOptions, StartContainerOptions, Stats, - StatsOptions, + ListContainersOptions, LogsOptions, MemoryStatsStats, RemoveContainerOptions, + StartContainerOptions, Stats, StatsOptions, }, service::ContainerSummary, Docker, @@ -71,7 +71,7 @@ pub struct DockerData { impl DockerData { /// Use docker stats to calculate current cpu usage #[allow(clippy::cast_precision_loss)] - // FIX: this can overflow + // TODO 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; @@ -121,8 +121,19 @@ impl DockerData { .take(1); while let Some(Ok(stats)) = stream.next().await { + // Memory stats are only collected if the container is alive - is this the behaviour we want? let mem_stat = if state.is_alive() { - Some(stats.memory_stats.usage.unwrap_or_default()) + let mem_cache = stats.memory_stats.stats.map_or(0, |i| match i { + MemoryStatsStats::V1(x) => x.inactive_file, + MemoryStatsStats::V2(x) => x.inactive_file, + }); + Some( + stats + .memory_stats + .usage + .unwrap_or_default() + .saturating_sub(mem_cache), + ) } else { None }; diff --git a/src/main.rs b/src/main.rs index 7eb6851..f01e318 100644 --- a/src/main.rs +++ b/src/main.rs @@ -150,7 +150,6 @@ async fn main() { let containers = app_data .lock() .get_container_items() - .clone() .iter() .map(|i| format!("{i}")) .collect::>(); diff --git a/src/ui/color_match.rs b/src/ui/color_match.rs index a1171f2..4760db3 100644 --- a/src/ui/color_match.rs +++ b/src/ui/color_match.rs @@ -98,12 +98,13 @@ mod tests { }] .to_vec(), alignment: None, + style: Style::default(), }]; assert_eq!(result, expected); } #[test] - // Use the escape codes to colorize the text + /// Use the escape codes to colorize the text fn color_match_colorize() { let result = log_sanitizer::colorize_logs(INPUT); let expected = vec![Line { @@ -130,12 +131,13 @@ mod tests { }, ], alignment: None, + style: Style::default(), }]; assert_eq!(result, expected); } #[test] - // Remove all escape ansi codes from given input + /// Remove all escape ansi codes from given input fn color_match_remove_ansi() { let result = log_sanitizer::remove_ansi(INPUT); let expected = vec![Line { @@ -143,6 +145,7 @@ mod tests { content: std::borrow::Cow::Borrowed("oxker"), style: Style::default(), }], + style: Style::default(), alignment: None, }]; assert_eq!(result, expected); diff --git a/src/ui/draw_blocks.rs b/src/ui/draw_blocks.rs index 2dacdf4..a48312d 100644 --- a/src/ui/draw_blocks.rs +++ b/src/ui/draw_blocks.rs @@ -44,6 +44,24 @@ const MARGIN: &str = " "; const RIGHT_ARROW: &str = "▶ "; const CIRCLE: &str = "⚪ "; +const CONSTRAINT_50_50: [Constraint; 2] = [Constraint::Percentage(50), Constraint::Percentage(50)]; +const CONSTRAINT_100: [Constraint; 1] = [Constraint::Percentage(100)]; +const CONSTRAINT_POPUP: [Constraint; 5] = [ + Constraint::Min(2), + Constraint::Max(1), + Constraint::Max(1), + Constraint::Max(3), + Constraint::Min(1), +]; + +const CONSTRAINT_BUTTONS: [Constraint; 5] = [ + Constraint::Percentage(10), + Constraint::Percentage(35), + Constraint::Percentage(10), + Constraint::Percentage(35), + Constraint::Percentage(10), +]; + /// From a given &str, return the maximum number of chars on a single line fn max_line_width(text: &str) -> usize { text.lines() @@ -94,8 +112,7 @@ pub fn commands( fd: &FrameData, gui_state: &Arc>, ) { - let block = || generate_block(app_data, area, fd, gui_state, SelectablePanel::Commands); - // let block = block(); + let block = generate_block(app_data, area, fd, gui_state, SelectablePanel::Commands); let items = app_data.lock().get_control_items().map_or(vec![], |i| { i.iter() .map(|c| { @@ -108,18 +125,14 @@ pub fn commands( .collect::>() }); - let items = List::new(items) - .block(block()) - .highlight_style(Style::default().add_modifier(Modifier::BOLD)) - .highlight_symbol(RIGHT_ARROW); - if let Some(i) = app_data.lock().get_control_state() { + let items = List::new(items) + .block(block) + .highlight_style(Style::default().add_modifier(Modifier::BOLD)) + .highlight_symbol(RIGHT_ARROW); f.render_stateful_widget(items, area, i); } else { - let block = || generate_block(app_data, area, fd, gui_state, SelectablePanel::Commands); - let paragraph = Paragraph::new("") - .block(block()) - .alignment(Alignment::Center); + let paragraph = Paragraph::new("").block(block).alignment(Alignment::Center); f.render_widget(paragraph, area); } } @@ -241,11 +254,11 @@ pub fn logs( fd: &FrameData, gui_state: &Arc>, ) { - let block = || generate_block(app_data, area, fd, gui_state, SelectablePanel::Logs); + let block = generate_block(app_data, area, fd, gui_state, SelectablePanel::Logs); if fd.init { let paragraph = Paragraph::new(format!("parsing logs {}", fd.loading_icon)) .style(Style::default()) - .block(block()) + .block(block) .alignment(Alignment::Center); f.render_widget(paragraph, area); } else { @@ -253,12 +266,12 @@ pub fn logs( if logs.is_empty() { let paragraph = Paragraph::new("no logs found") - .block(block()) + .block(block) .alignment(Alignment::Center); f.render_widget(paragraph, area); } else { let items = List::new(logs) - .block(block()) + .block(block) .highlight_symbol(RIGHT_ARROW) .highlight_style(Style::default().add_modifier(Modifier::BOLD)); // This should always return Some, as logs is not empty @@ -307,12 +320,8 @@ pub fn ports( )) .fg(Color::Yellow), )]; - for (index, item) in ports.0.iter().enumerate() { - let fg = if index % 2 == 0 { - Color::White - } else { - Color::Magenta - }; + for item in &ports.0 { + let fg = Color::White; let strings = item.print(); let line = vec![ @@ -333,7 +342,7 @@ pub fn chart(f: &mut Frame, area: Rect, app_data: &Arc>) { if let Some((cpu, mem)) = app_data.lock().get_chart_data() { let area = Layout::default() .direction(Direction::Horizontal) - .constraints([Constraint::Percentage(50), Constraint::Percentage(50)].as_ref()) + .constraints(CONSTRAINT_50_50) .split(area); let cpu_dataset = vec![Dataset::default() @@ -423,7 +432,7 @@ pub fn heading_bar( let mut color = Color::Black; let mut prefix = ""; let mut prefix_margin = 0; - if let Some((a, b)) = data.sorted_by.as_ref() { + if let Some((a, b)) = &data.sorted_by { if x == a { match b { SortedOrder::Asc => prefix = "▲ ", @@ -505,12 +514,12 @@ pub fn heading_bar( let column_width = if column_width > 0 { column_width } else { 1 }; let splits = if data.has_containers { vec![ - Constraint::Min(2), + Constraint::Max(2), Constraint::Min(column_width.try_into().unwrap_or_default()), - Constraint::Min(info_width.try_into().unwrap_or_default()), + Constraint::Max(info_width.try_into().unwrap_or_default()), ] } else { - vec![Constraint::Percentage(100)] + CONSTRAINT_100.to_vec() }; let split_bar = Layout::default() @@ -756,15 +765,12 @@ pub fn help_box(f: &mut Frame) { let split_popup = Layout::default() .direction(Direction::Vertical) - .constraints( - [ - 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(), - ) + .constraints([ + 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::Min(final_info.height.try_into().unwrap_or_default()), + ]) .split(area); let name_paragraph = Paragraph::new(name_info.lines) @@ -815,7 +821,7 @@ pub fn delete_confirm(f: &mut Frame, gui_state: &Arc>, name: &Co let confirm = Line::from(vec![ Span::from("Are you sure you want to delete container: "), Span::styled( - name.to_string(), + name.get(), Style::default() .fg(Color::Red) .bg(Color::White) @@ -843,16 +849,10 @@ pub fn delete_confirm(f: &mut Frame, gui_state: &Arc>, name: &Co .alignment(Alignment::Center) .block(button_block()); - // Need to add some padding for the borders - let _yes_chars = u16::try_from(yes_text.chars().count() + 2).unwrap_or(9); - let no_para = Paragraph::new(no_text) .alignment(Alignment::Center) .block(button_block()); - // Need to add some padding for the borders - // let no_chars = u16::try_from(no_text.chars().count() + 2).unwrap_or(8); - let area = popup( lines, max_line_width.into(), @@ -862,30 +862,12 @@ pub fn delete_confirm(f: &mut Frame, gui_state: &Arc>, name: &Co let split_popup = Layout::default() .direction(Direction::Vertical) - .constraints( - [ - Constraint::Min(2), - Constraint::Max(1), - Constraint::Max(1), - Constraint::Max(3), - Constraint::Min(1), - ] - .as_ref(), - ) + .constraints(CONSTRAINT_POPUP) .split(area); let split_buttons = Layout::default() .direction(Direction::Horizontal) - .constraints( - [ - Constraint::Percentage(10), - Constraint::Percentage(35), - Constraint::Percentage(10), - Constraint::Percentage(35), - Constraint::Percentage(10), - ] - .as_ref(), - ) + .constraints(CONSTRAINT_BUTTONS) .split(split_popup[3]); let no_area = split_buttons[1]; @@ -951,6 +933,7 @@ pub fn error(f: &mut Frame, error: AppError, seconds: Option) { } /// Draw info box in one of the 9 BoxLocations +// TODO is this broken? pub fn info(f: &mut Frame, text: &str, instant: Instant, gui_state: &Arc>) { let block = Block::default() .title("") @@ -1085,7 +1068,7 @@ mod tests { // ******************** // #[test] - // Test that when DockerCommands are available, they are drawn correctly, dependant on container state + /// Test that when DockerCommands are available, they are drawn correctly, dependant on container state fn test_draw_blocks_commands_none() { let (w, h) = (12, 6); let mut setup = test_setup(w, h, false, false); @@ -1236,7 +1219,7 @@ mod tests { } #[test] - // When control panel is selected, the border is blue, if not then white, selected text is highlighted + /// When control panel is selected, the border is blue, if not then white, selected text is highlighted fn test_draw_blocks_commands_panel_selected_color() { let (w, h) = (12, 6); let mut setup = test_setup(w, h, true, true); @@ -1326,7 +1309,7 @@ mod tests { } #[test] - // No containers, panel unselected, then selected, border color changes correctly + /// No containers, panel unselected, then selected, border color changes correctly fn test_draw_blocks_containers_none() { let (w, h) = (25, 6); let mut setup = test_setup(w, h, true, true); @@ -1387,7 +1370,7 @@ mod tests { } #[test] - // Containers panel drawn, selected line is bold, border is blue + /// Containers panel drawn, selected line is bold, border is blue fn test_draw_blocks_containers_some() { let (w, h) = (130, 6); let mut setup = test_setup(w, h, true, true); @@ -1746,7 +1729,7 @@ mod tests { // ********** // #[test] - // No logs, panel unselected, then selected, border color changes correctly + /// No logs, panel unselected, then selected, border color changes correctly fn test_draw_blocks_logs_none() { let (w, h) = (25, 6); let mut setup = test_setup(w, h, true, true); @@ -1808,7 +1791,7 @@ mod tests { } #[test] - // Parsing logs, spinner visible, and then animates by one frame + /// Parsing logs, spinner visible, and then animates by one frame fn test_draw_blocks_logs_parsing() { let (w, h) = (25, 6); let mut setup = test_setup(w, h, true, true); @@ -1874,7 +1857,7 @@ mod tests { } #[test] - // Logs correct displayed, changing log state also draws correctly + /// Logs correct displayed, changing log state also draws correctly fn test_draw_blocks_logs_some() { let (w, h) = (25, 6); let mut setup = test_setup(w, h, true, true); @@ -1943,7 +1926,7 @@ mod tests { } #[test] - // Full (long) name displayed in logs border + /// Full (long) name displayed in logs border fn test_draw_blocks_logs_long_name() { let (w, h) = (80, 6); let mut setup = test_setup(w, h, true, true); @@ -2032,7 +2015,7 @@ mod tests { } } #[test] - // When status is Running, but not data, charts drawn without dots etc + /// When status is Running, but not data, charts drawn without dots etc fn test_draw_blocks_charts_running_none() { let (w, h) = (80, 10); let mut setup = test_setup(w, h, true, true); @@ -2087,7 +2070,7 @@ mod tests { } #[test] - // When status is Running, charts correctly drawn + /// When status is Running, charts correctly drawn fn test_draw_blocks_charts_running_some() { let (w, h) = (80, 10); let mut setup = test_setup(w, h, true, true); @@ -2140,7 +2123,7 @@ mod tests { } #[test] - // Whens status paused, some text is now Yellow + /// Whens status paused, some text is now Yellow fn test_draw_blocks_charts_paused() { let (w, h) = (80, 10); let mut setup = test_setup(w, h, true, true); @@ -2188,7 +2171,7 @@ mod tests { } #[test] - // When dead, text is read + /// When dead, text is read fn test_draw_blocks_charts_dead() { let (w, h) = (80, 10); let mut setup = test_setup(w, h, true, true); @@ -2335,7 +2318,6 @@ mod tests { let result = &setup.terminal.backend().buffer().content; for (index, expected_char) in expected.chars().enumerate() { let result_cell = &result[index]; - assert_eq!(result_cell.symbol(), expected_char.to_string()); assert_eq!(result_cell.bg, Color::Magenta); assert_eq!( @@ -2383,8 +2365,8 @@ mod tests { test(" name state status cpu memory/limit id image ▼ ↓ rx ↑ tx ( h ) show help ", 99..=108, (Header::Rx, SortedOrder::Desc)); // tx - test(" name state status cpu memory/limit id image ↓ rx ▲ ↑ tx ( h ) show help ", 109..=122, (Header::Tx, SortedOrder::Asc)); - test(" name state status cpu memory/limit id image ↓ rx ▼ ↑ tx ( h ) show help ", 109..=122, (Header::Tx, SortedOrder::Desc)); + test(" name state status cpu memory/limit id image ↓ rx ▲ ↑ tx ( h ) show help ", 109..=118, (Header::Tx, SortedOrder::Asc)); + test(" name state status cpu memory/limit id image ↓ rx ▼ ↑ tx ( h ) show help ", 109..=118, (Header::Tx, SortedOrder::Desc)); } #[test] @@ -2425,7 +2407,7 @@ mod tests { // Help popup // // ********** // #[test] - // This will cause issues once the version has more than the current 5 chars (0.5.0) + /// This will cause issues once the version has more than the current 5 chars (0.5.0) // Help popup is drawn correctly fn test_draw_blocks_help() { let (w, h) = (87, 30); @@ -2525,7 +2507,7 @@ mod tests { // ************ // #[test] - // Delete container popup is drawn correctly + /// Delete container popup is drawn correctly fn test_draw_blocks_delete() { let (w, h) = (82, 10); let mut setup = test_setup(w, h, true, true); @@ -2587,6 +2569,70 @@ mod tests { } } + #[test] + /// Delete container popup is drawn correctly + fn test_draw_blocks_delete_long_name() { + let (w, h) = (106, 10); + let mut setup = test_setup(w, h, true, true); + let name = ContainerName::from("container_1_container_1_container_1"); + setup.app_data.lock().containers.items[0].name = name.clone(); + + let expected = [ + " ", + " ╭──────────────────────────────────── Confirm Delete ────────────────────────────────────╮ ", + " │ │ ", + " │ Are you sure you want to delete container: container_1_container_1_container_1 │ ", + " │ │ ", + " │ ╭──────────────────────────────╮ ╭─────────────────────────────╮ │ ", + " │ │ (N)o │ │ (Y)es │ │ ", + " │ ╰──────────────────────────────╯ ╰─────────────────────────────╯ │ ", + " ╰────────────────────────────────────────────────────────────────────────────────────────╯ ", + " ", + ]; + + setup + .terminal + .draw(|f| { + super::delete_confirm(f, &setup.gui_state, &name); + }) + .unwrap(); + + let result = &setup.terminal.backend().buffer().content; + for (row_index, row) in expected.iter().enumerate() { + for (char_index, expected_char) in row.chars().enumerate() { + let index = row_index * usize::from(w) + char_index; + let result_cell = &result[index]; + assert_eq!(result_cell.symbol(), expected_char.to_string()); + + if row_index == 0 + || row_index == usize::from(h - 1) + || char_index < 8 + || char_index > usize::from(w - 9) + { + assert_eq!(result_cell.fg, Color::Reset); + assert_eq!(result_cell.bg, Color::Reset); + } else { + assert_eq!(result_cell.bg, Color::White); + } + + // Borders are black + if BORDER_CHARS.contains(&result_cell.symbol()) { + assert_eq!(result_cell.fg, Color::Black); + // Container name is red + } else if row_index == 3 && (57..=82).contains(&char_index) { + assert_eq!(result_cell.fg, Color::Red); + // All other text is black + } else if !row_index == 0 + && !row_index == usize::from(h - 1) + && !char_index < 8 + && !char_index > usize::from(w - 9) + { + assert_eq!(result_cell.fg, Color::Black); + } + } + } + } + // ***** // // popup // // ***** // @@ -2617,13 +2663,13 @@ mod tests { .unwrap(); let result = &setup.terminal.backend().buffer().content; + for (row_index, row) in expected.iter().enumerate() { for (char_index, expected_char) in row.chars().enumerate() { let index = row_index * usize::from(w) + char_index; let result_cell = &result[index]; assert_eq!(expected_char.to_string(), result_cell.symbol()); - let (fg, bg) = if row_index >= 6 && char_index >= 32 { (Color::White, Color::Blue) } else { @@ -2641,7 +2687,7 @@ mod tests { // *********** // #[test] - // Test that the error popup is centered, red background, white border, white text, and displays the correct text + /// Test that the error popup is centered, red background, white border, white text, and displays the correct text fn test_draw_blocks_docker_connect_error() { let (w, h) = (46, 9); let mut setup = test_setup(w, h, true, true); @@ -2692,7 +2738,7 @@ mod tests { } #[test] - // Test that the clearable error popup is centered, red background, white border, white text, and displays the correct text + /// Test that the clearable error popup is centered, red background, white border, white text, and displays the correct text fn test_draw_blocks_clearable_error() { let (w, h) = (39, 10); let mut setup = test_setup(w, h, true, true); @@ -2744,7 +2790,7 @@ mod tests { } #[test] - // Port section when container has no ports + /// Port section when container has no ports fn test_draw_blocks_ports_no_ports() { let (w, h) = (30, 8); let mut setup = test_setup(w, h, true, true); @@ -2824,7 +2870,7 @@ mod tests { } #[test] - // Port section when container has multiple ports + /// Port section when container has multiple ports fn test_draw_blocks_ports_multiple_ports() { let (w, h) = (32, 8); let mut setup = test_setup(w, h, true, true); @@ -2883,12 +2929,9 @@ mod tests { if row_index == 1 && result_cell_as_char { assert_eq!(result_cell.fg, Color::Yellow); } - if row_index == 2 && result_cell_as_char { + if (2..=3).contains(&row_index) && result_cell_as_char { assert_eq!(result_cell.fg, Color::White); } - if row_index == 3 && result_cell_as_char { - assert_eq!(result_cell.fg, Color::Magenta); - } if row_index == 4 && result_cell_as_char { assert_eq!(result_cell.fg, Color::White); } @@ -2897,7 +2940,7 @@ mod tests { } #[test] - // Port section title color correct dependant on state + /// Port section title color correct dependant on state fn test_draw_blocks_ports_container_state() { let (w, h) = (32, 8); let mut setup = test_setup(w, h, true, true); @@ -2951,6 +2994,7 @@ mod tests { }) .unwrap(); + // This is wrong - why? let expected = [ "╭─────────── ports ────────────╮", "│ ip private public │", @@ -2988,7 +3032,7 @@ mod tests { // The whole layout // // **************** // #[test] - // Check that the whole layout is drawn correctly + /// Check that the whole layout is drawn correctly fn test_draw_blocks_whole_layout() { let (w, h) = (160, 30); let mut setup = test_setup(w, h, true, true); @@ -3028,7 +3072,7 @@ mod tests { "│ │", "│ │", "╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯", - "╭───────────────────────── cpu 03.00% ──────────────────────────╮╭─────────────────────── memory 30.00 kB ───────────────────────╮╭────────── ports ───────────╮", + "╭───────────────────────── cpu 03.00% ──────────────────────────╮╭─────────────────────── memory 30.00 kB ───────────────────────╮╭────────── ports ───────────╮", "│10.00%│ •••• ││100.00 kB│ ••• ││ ip private public│", "│ │ ••• • ││ │ ••• • ││ 8001 │", "│ │•• ••• ││ │•• ••• ││127.0.0.1 8003 8003│", @@ -3052,4 +3096,75 @@ mod tests { } } } + + #[test] + /// Check that the whole layout is drawn correctly when have long container name and long image name + fn test_draw_blocks_whole_layout_long_name() { + let (w, h) = (190, 30); + let mut setup = test_setup(w, h, true, true); + + insert_chart_data(&setup); + insert_logs(&setup); + setup.app_data.lock().containers.items[0] + .ports + .push(ContainerPorts { + ip: Some("127.0.0.1".to_owned()), + private: 8003, + public: Some(8003), + }); + + setup.app_data.lock().containers.items[0].name = + ContainerName::from("a_long_container_name_for_the_purposes_of_this_test"); + setup.app_data.lock().containers.items[0].image = + ContainerImage::from("a_long_image_name_for_the_purposes_of_this_test"); + + let expected = [ + " name state status cpu memory/limit id image ↓ rx ↑ tx ( h ) show help ", + "╭ Containers 1/3 ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮╭─────────────────╮", + "│⚪ a_long_container_name_for_the… ✓ running Up 1 hour 03.00% 30.00 kB / 30.00 kB 1 a_long_image_name_for_the_pur… 0.00 kB 0.00 kB ││▶ pause │", + "│ container_2 ✓ running Up 2 hour 00.00% 0.00 kB / 0.00 kB 2 image_2 0.00 kB 0.00 kB ││ restart │", + "│ container_3 ✓ running Up 3 hour 00.00% 0.00 kB / 0.00 kB 3 image_3 0.00 kB 0.00 kB ││ stop │", + "│ ││ delete │", + "│ ││ │", + "│ ││ │", + "╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯╰─────────────────╯", + "╭ Logs 3/3 - a_long_container_name_for_the_purposes_of_this_test ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮", + "│ line 1 │", + "│ line 2 │", + "│▶ line 3 │", + "│ │", + "│ │", + "│ │", + "│ │", + "│ │", + "│ │", + "│ │", + "│ │", + "│ │", + "│ │", + "╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯", + "╭───────────────────────────────── cpu 03.00% ─────────────────────────────────╮╭────────────────────────────── memory 30.00 kB ───────────────────────────────╮╭────────── ports ───────────╮", + "│10.00%│ •••• ││100.00 kB│ ••••• ││ ip private public│", + "│ │ •••• • ││ │ ••• • ││ 8001 │", + "│ │••• •••• ││ │••• ••• ││127.0.0.1 8003 8003│", + "│ │ ││ │ ││ │", + "╰──────────────────────────────────────────────────────────────────────────────╯╰──────────────────────────────────────────────────────────────────────────────╯╰────────────────────────────╯", + ]; + setup + .terminal + .draw(|f| { + draw_frame(f, &setup.app_data, &setup.gui_state); + }) + .unwrap(); + + let result = &setup.terminal.backend().buffer().content; + for (row_index, row) in expected.iter().enumerate() { + for (char_index, expected_char) in row.chars().enumerate() { + let index = row_index * usize::from(w) + char_index; + let result_cell = &result[index]; + + assert_eq!(result_cell.symbol(), expected_char.to_string(),); + } + } + } } diff --git a/src/ui/gui_state.rs b/src/ui/gui_state.rs index 039e463..d93b1dc 100644 --- a/src/ui/gui_state.rs +++ b/src/ui/gui_state.rs @@ -109,19 +109,19 @@ impl BoxLocation { ) -> [Constraint; 3] { match self { Self::TopLeft | Self::MiddleLeft | Self::BottomLeft => [ - Constraint::Max(text_width), + Constraint::Min(text_width), Constraint::Max(blank_horizontal), Constraint::Max(blank_horizontal), ], Self::TopCentre | Self::MiddleCentre | Self::BottomCentre => [ Constraint::Max(blank_horizontal), - Constraint::Max(text_width), + Constraint::Min(text_width), Constraint::Max(blank_horizontal), ], Self::TopRight | Self::MiddleRight | Self::BottomRight => [ Constraint::Max(blank_horizontal), Constraint::Max(blank_horizontal), - Constraint::Max(text_width), + Constraint::Min(text_width), ], } } @@ -133,19 +133,19 @@ impl BoxLocation { ) -> [Constraint; 3] { match self { Self::TopLeft | Self::TopCentre | Self::TopRight => [ - Constraint::Max(number_lines), + Constraint::Min(number_lines), Constraint::Max(blank_vertical), Constraint::Max(blank_vertical), ], Self::MiddleLeft | Self::MiddleCentre | Self::MiddleRight => [ Constraint::Max(blank_vertical), - Constraint::Max(number_lines), + Constraint::Min(number_lines), Constraint::Max(blank_vertical), ], Self::BottomLeft | Self::BottomCentre | Self::BottomRight => [ Constraint::Max(blank_vertical), Constraint::Max(blank_vertical), - Constraint::Max(number_lines), + Constraint::Min(number_lines), ], } } diff --git a/src/ui/mod.rs b/src/ui/mod.rs index 79c3cb9..e3ddf0e 100644 --- a/src/ui/mod.rs +++ b/src/ui/mod.rs @@ -265,13 +265,14 @@ fn draw_frame(f: &mut Frame, app_data: &Arc>, gui_state: &Arc>, gui_state: &Arc