chore: merge release-v0.11.0 into main
This commit is contained in:
+13
-3
@@ -1,6 +1,16 @@
|
|||||||
### 2025-06-19
|
### 2025-08-21
|
||||||
|
|
||||||
### Reverts
|
### Chores
|
||||||
+ Bollard update rolled back, closes #66, [aac9c6b598ce6c23b14f5a8b0116e662b18074d2]
|
+ Dependencies updated, [ced885e0128b6d5d3a3c7cb97d7e53bc2da64893], [f9b40ea03d0e70e235c28646ff3f9ebb468a904d]
|
||||||
|
+ Rust 1.89 linting, [79d19ceeb81ae60bc5562683e405d6e74e6f2578]
|
||||||
|
+ GitHub workflow updated, [08384200558fa1b9d378ea62ea832708caebaa91], [6573af1ed7d382a81c1305397e904066bb8395a8]
|
||||||
|
|
||||||
|
### Features
|
||||||
|
+ Horizontally scroll across logs. By default use `←` & `→` keys to traverse horizontally across the lines when logs panel selected. Updated `config.toml` with `log_scroll_forward` and `log_scroll_back` [c190f0206cc55b8e45b8373f9be954e828c18b3b], [8939ac0345326633e794cc10a981a1f3c5c07549]
|
||||||
|
+ Force clear screen & redraw of UI. By default uses `f` key, `config.toml` updated with `force_redraw` [50edbc0cc09db864835fe81a03cba8eadafe548b]
|
||||||
|
+ Increase scroll speed using the `ctrl` key in conjuction with a scroll key, `config.toml` updated with `scroll_modifier`. The next release will remove `scroll_down_many` & `scroll_down_up` keys, [c5bbffdb5f9e800951e4060aa6aee8e00db589aa]
|
||||||
|
|
||||||
|
### Refactors
|
||||||
|
+ remove macos cfg none-const functions, Zigbuild now uses Rust 1.87.0, [eb686e2c952e04da74b3e12c0bfa015ec4615e1d]
|
||||||
|
|
||||||
see <a href='https://github.com/mrjackwills/oxker/blob/main/CHANGELOG.md'>CHANGELOG.md</a> for more details
|
see <a href='https://github.com/mrjackwills/oxker/blob/main/CHANGELOG.md'>CHANGELOG.md</a> for more details
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 44 KiB |
@@ -31,7 +31,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v5
|
||||||
|
|
||||||
# Install stable rust, and associated tools
|
# Install stable rust, and associated tools
|
||||||
- name: install rust
|
- name: install rust
|
||||||
@@ -82,10 +82,10 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v5
|
||||||
|
|
||||||
- name: Setup | Artifacts
|
- name: Setup | Artifacts
|
||||||
uses: actions/download-artifact@v4
|
uses: actions/download-artifact@v5
|
||||||
|
|
||||||
- name: Update Release
|
- name: Update Release
|
||||||
uses: ncipollo/release-action@v1
|
uses: ncipollo/release-action@v1
|
||||||
@@ -107,7 +107,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v5
|
||||||
|
|
||||||
- name: Login to GitHub Container Registry
|
- name: Login to GitHub Container Registry
|
||||||
uses: docker/login-action@v3
|
uses: docker/login-action@v3
|
||||||
@@ -122,25 +122,24 @@ jobs:
|
|||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Write release version to env
|
- name: Set up Docker Buildx
|
||||||
run: |
|
uses: docker/setup-buildx-action@v3
|
||||||
CURRENT_SEMVER=${GITHUB_REF_NAME#v}
|
|
||||||
echo "CURRENT_SEMVER=$CURRENT_SEMVER" >> $GITHUB_ENV
|
|
||||||
|
|
||||||
- uses: docker/setup-buildx-action@v3
|
- name: Build and push Docker image
|
||||||
id: buildx
|
uses: docker/build-push-action@v6
|
||||||
with:
|
with:
|
||||||
install: true
|
context: .
|
||||||
- name: Build for Dockerhub & ghcr.io
|
file: ./containerised/Dockerfile
|
||||||
run: |
|
push: true
|
||||||
docker build --platform linux/arm/v6,linux/arm64,linux/amd64 \
|
tags: |
|
||||||
-t ${{ secrets.DOCKERHUB_USERNAME }}/oxker:latest \
|
${{ secrets.DOCKERHUB_USERNAME }}/{{ github.event.repository.name }}:latest
|
||||||
-t ${{ secrets.DOCKERHUB_USERNAME }}/oxker:${{env.CURRENT_SEMVER}} \
|
${{ secrets.DOCKERHUB_USERNAME }}/{{ github.event.repository.name }}:${{env.CURRENT_SEMVER}}
|
||||||
-t ghcr.io/${{ github.repository_owner }}/${{ github.ref_name }}:latest \
|
ghcr.io/${{ github.repository_owner }}/${{ github.event.repository.name }}:latest
|
||||||
-t ghcr.io/${{ github.repository_owner }}/${{ github.ref_name }}:${{env.CURRENT_SEMVER}} \
|
ghcr.io/${{ github.repository_owner }}/${{ github.event.repository.name }}:${{ env.CURRENT_SEMVER }}
|
||||||
--provenance=false --sbom=false \
|
platforms: linux/arm/v6,linux/arm64,linux/amd64
|
||||||
--push \
|
provenance: false
|
||||||
-f containerised/Dockerfile .
|
sbom: false
|
||||||
|
|
||||||
########################
|
########################
|
||||||
# Publish to crates.io #
|
# Publish to crates.io #
|
||||||
########################
|
########################
|
||||||
@@ -152,7 +151,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: update rust stable
|
- name: update rust stable
|
||||||
run: rustup update stable
|
run: rustup update stable
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v5
|
||||||
- name: Publish Dry Run
|
- name: Publish Dry Run
|
||||||
run: cargo publish --dry-run
|
run: cargo publish --dry-run
|
||||||
|
|
||||||
@@ -165,7 +164,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: update rust stable
|
- name: update rust stable
|
||||||
run: rustup update stable
|
run: rustup update stable
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v5
|
||||||
- name: Publish
|
- name: Publish
|
||||||
run: cargo publish
|
run: cargo publish
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
/target
|
/target
|
||||||
/releases
|
/releases
|
||||||
|
/binaries
|
||||||
# Used in the zigbuild for aarch64-apple-darwin
|
# Used in the zigbuild for aarch64-apple-darwin
|
||||||
.intentionally-empty-file.o
|
.intentionally-empty-file.o
|
||||||
+17
-1
@@ -1,3 +1,19 @@
|
|||||||
|
# <a href='https://github.com/mrjackwills/oxker/releases/tag/v0.11.0'>v0.11.0</a>
|
||||||
|
### 2025-08-21
|
||||||
|
|
||||||
|
### Chores
|
||||||
|
+ Dependencies updated, [ced885e0](https://github.com/mrjackwills/oxker/commit/ced885e0128b6d5d3a3c7cb97d7e53bc2da64893), [f9b40ea0](https://github.com/mrjackwills/oxker/commit/f9b40ea03d0e70e235c28646ff3f9ebb468a904d)
|
||||||
|
+ Rust 1.89 linting, [79d19cee](https://github.com/mrjackwills/oxker/commit/79d19ceeb81ae60bc5562683e405d6e74e6f2578)
|
||||||
|
+ GitHub workflow updated, [08384200](https://github.com/mrjackwills/oxker/commit/08384200558fa1b9d378ea62ea832708caebaa91), [6573af1e](https://github.com/mrjackwills/oxker/commit/6573af1ed7d382a81c1305397e904066bb8395a8)
|
||||||
|
|
||||||
|
### Features
|
||||||
|
+ Horizontally scroll across logs. By default use `←` & `→` keys to traverse horizontally across the lines when logs panel selected. Updated `config.toml` with `log_scroll_forward` and `log_scroll_back` [c190f020](https://github.com/mrjackwills/oxker/commit/c190f0206cc55b8e45b8373f9be954e828c18b3b), [8939ac03](https://github.com/mrjackwills/oxker/commit/8939ac0345326633e794cc10a981a1f3c5c07549)
|
||||||
|
+ Force clear screen & redraw of UI. By default uses `f` key, `config.toml` updated with `force_redraw` [50edbc0c](https://github.com/mrjackwills/oxker/commit/50edbc0cc09db864835fe81a03cba8eadafe548b)
|
||||||
|
+ Increase scroll speed using the `ctrl` key in conjuction with a scroll key, `config.toml` updated with `scroll_modifier`. The next release will remove `scroll_down_many` & `scroll_down_up` keys, [c5bbffdb](https://github.com/mrjackwills/oxker/commit/c5bbffdb5f9e800951e4060aa6aee8e00db589aa)
|
||||||
|
|
||||||
|
### Refactors
|
||||||
|
+ remove macos cfg none-const functions, Zigbuild now uses Rust 1.87.0, [eb686e2c](https://github.com/mrjackwills/oxker/commit/eb686e2c952e04da74b3e12c0bfa015ec4615e1d)
|
||||||
|
|
||||||
# <a href='https://github.com/mrjackwills/oxker/releases/tag/v0.10.5'>v0.10.5</a>
|
# <a href='https://github.com/mrjackwills/oxker/releases/tag/v0.10.5'>v0.10.5</a>
|
||||||
### 2025-06-19
|
### 2025-06-19
|
||||||
|
|
||||||
@@ -11,7 +27,7 @@
|
|||||||
+ .devcontainer updated, [324f8268](https://github.com/mrjackwills/oxker/commit/324f8268278081504d5357f2ed89b78ca2c25d04)
|
+ .devcontainer updated, [324f8268](https://github.com/mrjackwills/oxker/commit/324f8268278081504d5357f2ed89b78ca2c25d04)
|
||||||
+ dependencies updated, [0ace9dd6](https://github.com/mrjackwills/oxker/commit/0ace9dd662144a589341779a64d7fcd8de7d9978), [a6360075](https://github.com/mrjackwills/oxker/commit/a636007547280b3b3db69374601dbece4bc21eef)
|
+ dependencies updated, [0ace9dd6](https://github.com/mrjackwills/oxker/commit/0ace9dd662144a589341779a64d7fcd8de7d9978), [a6360075](https://github.com/mrjackwills/oxker/commit/a636007547280b3b3db69374601dbece4bc21eef)
|
||||||
+ Rust 1.87.0 linting, [395b1aa7](https://github.com/mrjackwills/oxker/commit/395b1aa7e997a528e4f21e66f5f859001c1c3ec1), [67e5888e](https://github.com/mrjackwills/oxker/commit/67e5888e008cfd504c10e47f678f9351c838be99)
|
+ Rust 1.87.0 linting, [395b1aa7](https://github.com/mrjackwills/oxker/commit/395b1aa7e997a528e4f21e66f5f859001c1c3ec1), [67e5888e](https://github.com/mrjackwills/oxker/commit/67e5888e008cfd504c10e47f678f9351c838be99)
|
||||||
|
back
|
||||||
### Docs
|
### Docs
|
||||||
+ example config files updated, [63ab7de7](https://github.com/mrjackwills/oxker/commit/63ab7de72897de460f31181c5a42befbee2f91d3), [8fb5ac4a](https://github.com/mrjackwills/oxker/commit/8fb5ac4a945b75f3fcd118c53be1202ccbc43c59)
|
+ example config files updated, [63ab7de7](https://github.com/mrjackwills/oxker/commit/63ab7de72897de460f31181c5a42befbee2f91d3), [8fb5ac4a](https://github.com/mrjackwills/oxker/commit/8fb5ac4a945b75f3fcd118c53be1202ccbc43c59)
|
||||||
+ README.md updated, link to directories crate, closes [#65](https://github.com/mrjackwills/oxker/issues/65), [c2bfe329](https://github.com/mrjackwills/oxker/commit/c2bfe3296563daf4b7f077469f3eeff6895720b0)
|
+ README.md updated, link to directories crate, closes [#65](https://github.com/mrjackwills/oxker/issues/65), [c2bfe329](https://github.com/mrjackwills/oxker/commit/c2bfe3296563daf4b7f077469f3eeff6895720b0)
|
||||||
|
|||||||
Generated
+165
-144
@@ -40,9 +40,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anstream"
|
name = "anstream"
|
||||||
version = "0.6.19"
|
version = "0.6.20"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "301af1932e46185686725e0fad2f8f2aa7da69dd70bf6ecc44d6b703844a3933"
|
checksum = "3ae563653d1938f79b1ab1b5e668c87c76a9930414574a6583a7b7e11a8e6192"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anstyle",
|
"anstyle",
|
||||||
"anstyle-parse",
|
"anstyle-parse",
|
||||||
@@ -70,35 +70,41 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anstyle-query"
|
name = "anstyle-query"
|
||||||
version = "1.1.3"
|
version = "1.1.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6c8bdeb6047d8983be085bab0ba1472e6dc604e7041dbf6fcd5e71523014fae9"
|
checksum = "9e231f6134f61b71076a3eab506c379d4f36122f2af15a9ff04415ea4c3339e2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows-sys 0.59.0",
|
"windows-sys 0.60.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anstyle-wincon"
|
name = "anstyle-wincon"
|
||||||
version = "3.0.9"
|
version = "3.0.10"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "403f75924867bb1033c59fbf0797484329750cfbe3c4325cd33127941fabc882"
|
checksum = "3e0633414522a32ffaac8ac6cc8f748e090c5717661fddeea04219e2344f5f2a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anstyle",
|
"anstyle",
|
||||||
"once_cell_polyfill",
|
"once_cell_polyfill",
|
||||||
"windows-sys 0.59.0",
|
"windows-sys 0.60.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anyhow"
|
name = "anyhow"
|
||||||
version = "1.0.98"
|
version = "1.0.99"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487"
|
checksum = "b0674a1ddeecb70197781e945de4b3b8ffb61fa939a5597bcf48503737663100"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "atomic-waker"
|
||||||
|
version = "1.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "autocfg"
|
name = "autocfg"
|
||||||
version = "1.4.0"
|
version = "1.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
|
checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "backtrace"
|
name = "backtrace"
|
||||||
@@ -123,15 +129,15 @@ checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bitflags"
|
name = "bitflags"
|
||||||
version = "2.9.1"
|
version = "2.9.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967"
|
checksum = "6a65b545ab31d687cff52899d4890855fec459eb6afe0da6417b8a18da87aa29"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bollard"
|
name = "bollard"
|
||||||
version = "0.18.1"
|
version = "0.19.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "97ccca1260af6a459d75994ad5acc1651bcabcbdbc41467cc9786519ab854c30"
|
checksum = "8796b390a5b4c86f9f2e8173a68c2791f4fa6b038b84e96dbc01c016d1e6722c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64",
|
"base64",
|
||||||
"bollard-stubs",
|
"bollard-stubs",
|
||||||
@@ -162,20 +168,21 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bollard-stubs"
|
name = "bollard-stubs"
|
||||||
version = "1.47.1-rc.27.3.1"
|
version = "1.49.0-rc.28.3.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3f179cfbddb6e77a5472703d4b30436bff32929c0aa8a9008ecf23d1d3cdd0da"
|
checksum = "2e7814991259013d5a5bee4ae28657dae0747d843cf06c40f7fc0c2894d6fa38"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
|
"serde_json",
|
||||||
"serde_repr",
|
"serde_repr",
|
||||||
"serde_with",
|
"serde_with",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bumpalo"
|
name = "bumpalo"
|
||||||
version = "3.18.1"
|
version = "3.19.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "793db76d6187cd04dff33004d8e6c9cc4e05cd330500379d2394209271b4aeee"
|
checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bytes"
|
name = "bytes"
|
||||||
@@ -197,27 +204,27 @@ checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "castaway"
|
name = "castaway"
|
||||||
version = "0.2.3"
|
version = "0.2.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0abae9be0aaf9ea96a3b1b8b1b55c602ca751eba1b1500220cea4ecbafe7c0d5"
|
checksum = "dec551ab6e7578819132c713a93c022a05d60159dc86e7a7050223577484c55a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"rustversion",
|
"rustversion",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cc"
|
name = "cc"
|
||||||
version = "1.2.27"
|
version = "1.2.33"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d487aa071b5f64da6f19a3e848e3578944b726ee5a4854b82172f02aa876bfdc"
|
checksum = "3ee0f8803222ba5a7e2777dd72ca451868909b1ac410621b676adf07280e9b5f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"shlex",
|
"shlex",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cfg-if"
|
name = "cfg-if"
|
||||||
version = "1.0.1"
|
version = "1.0.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268"
|
checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "chrono"
|
name = "chrono"
|
||||||
@@ -234,9 +241,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap"
|
name = "clap"
|
||||||
version = "4.5.40"
|
version = "4.5.45"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "40b6887a1d8685cebccf115538db5c0efe625ccac9696ad45c409d96566e910f"
|
checksum = "1fc0e74a703892159f5ae7d3aac52c8e6c392f5ae5f359c70b5881d60aaac318"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap_builder",
|
"clap_builder",
|
||||||
"clap_derive",
|
"clap_derive",
|
||||||
@@ -244,9 +251,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap_builder"
|
name = "clap_builder"
|
||||||
version = "4.5.40"
|
version = "4.5.44"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e0c66c08ce9f0c698cbce5c0279d0bb6ac936d8674174fe48f736533b964f59e"
|
checksum = "b3e7f4214277f3c7aa526a59dd3fbe306a370daee1f8b7b8c987069cd8e888a8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anstream",
|
"anstream",
|
||||||
"anstyle",
|
"anstyle",
|
||||||
@@ -258,9 +265,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap_derive"
|
name = "clap_derive"
|
||||||
version = "4.5.40"
|
version = "4.5.45"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d2c7947ae4cc3d851207c1adb5b5e260ff0cca11446b1d6d1423788e442257ce"
|
checksum = "14cb31bb0a7d536caef2639baa7fad459e15c3144efefa6dbd1c84562c4739f6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"heck",
|
"heck",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
@@ -349,7 +356,7 @@ dependencies = [
|
|||||||
"document-features",
|
"document-features",
|
||||||
"mio",
|
"mio",
|
||||||
"parking_lot",
|
"parking_lot",
|
||||||
"rustix 1.0.7",
|
"rustix 1.0.8",
|
||||||
"signal-hook",
|
"signal-hook",
|
||||||
"signal-hook-mio",
|
"signal-hook-mio",
|
||||||
"winapi",
|
"winapi",
|
||||||
@@ -473,9 +480,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dyn-clone"
|
name = "dyn-clone"
|
||||||
version = "1.0.19"
|
version = "1.0.20"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1c7a8fb8a9fbf66c1f703fe16184d10ca0ee9d23be5b4436400408ba54a95005"
|
checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "either"
|
name = "either"
|
||||||
@@ -497,12 +504,12 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "errno"
|
name = "errno"
|
||||||
version = "0.3.12"
|
version = "0.3.13"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cea14ef9355e3beab063703aa9dab15afd25f0667c341310c1e5274bb1d0da18"
|
checksum = "778e2ac28f6c47af28e4907f13ffd1e1ddbd400980a9abd7c8df189bf578a5ad"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"windows-sys 0.59.0",
|
"windows-sys 0.60.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -519,9 +526,9 @@ checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "form_urlencoded"
|
name = "form_urlencoded"
|
||||||
version = "1.2.1"
|
version = "1.2.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456"
|
checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
]
|
]
|
||||||
@@ -615,9 +622,9 @@ checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hashbrown"
|
name = "hashbrown"
|
||||||
version = "0.15.4"
|
version = "0.15.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5"
|
checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"allocator-api2",
|
"allocator-api2",
|
||||||
"equivalent",
|
"equivalent",
|
||||||
@@ -684,19 +691,21 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hyper"
|
name = "hyper"
|
||||||
version = "1.6.0"
|
version = "1.7.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cc2b571658e38e0c01b1fdca3bbbe93c00d3d71693ff2770043f8c29bc7d6f80"
|
checksum = "eb3aa54a13a0dfe7fbe3a59e0c76093041720fdc77b110cc0fc260fafb4dc51e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"atomic-waker",
|
||||||
"bytes",
|
"bytes",
|
||||||
"futures-channel",
|
"futures-channel",
|
||||||
"futures-util",
|
"futures-core",
|
||||||
"http",
|
"http",
|
||||||
"http-body",
|
"http-body",
|
||||||
"httparse",
|
"httparse",
|
||||||
"httpdate",
|
"httpdate",
|
||||||
"itoa",
|
"itoa",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
|
"pin-utils",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
"tokio",
|
"tokio",
|
||||||
"want",
|
"want",
|
||||||
@@ -719,9 +728,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hyper-util"
|
name = "hyper-util"
|
||||||
version = "0.1.14"
|
version = "0.1.16"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "dc2fdfdbff08affe55bb779f33b053aa1fe5dd5b54c257343c17edfa55711bdb"
|
checksum = "8d9b05277c7e8da2c93a568989bb6207bef0112e8d17df7a6eda4a3cf143bc5e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"futures-channel",
|
"futures-channel",
|
||||||
@@ -871,9 +880,9 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "idna"
|
name = "idna"
|
||||||
version = "1.0.3"
|
version = "1.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e"
|
checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"idna_adapter",
|
"idna_adapter",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
@@ -903,12 +912,12 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "indexmap"
|
name = "indexmap"
|
||||||
version = "2.9.0"
|
version = "2.10.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e"
|
checksum = "fe4cd85333e22411419a0bcae1297d25e58c9443848b11dc6a86fefe8c78a661"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"equivalent",
|
"equivalent",
|
||||||
"hashbrown 0.15.4",
|
"hashbrown 0.15.5",
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -931,9 +940,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "instability"
|
name = "instability"
|
||||||
version = "0.3.7"
|
version = "0.3.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0bf9fed6d91cfb734e7476a06bde8300a1b94e217e1b523b6f0cd1a01998c71d"
|
checksum = "435d80800b936787d62688c927b6490e887c7ef5ff9ce922c6c6050fca75eb9a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"darling",
|
"darling",
|
||||||
"indoc",
|
"indoc",
|
||||||
@@ -942,6 +951,17 @@ dependencies = [
|
|||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "io-uring"
|
||||||
|
version = "0.7.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d93587f37623a1a17d94ef2bc9ada592f5465fe7732084ab7beefabe5c77c0c4"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
"cfg-if",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "is_terminal_polyfill"
|
name = "is_terminal_polyfill"
|
||||||
version = "1.70.1"
|
version = "1.70.1"
|
||||||
@@ -1023,15 +1043,15 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.174"
|
version = "0.2.175"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776"
|
checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libredox"
|
name = "libredox"
|
||||||
version = "0.1.3"
|
version = "0.1.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d"
|
checksum = "391290121bad3d37fbddad76d8f5d1c1c314cfc646d143d7e07a3086ddff0ce3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"libc",
|
"libc",
|
||||||
@@ -1057,9 +1077,9 @@ checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "litrs"
|
name = "litrs"
|
||||||
version = "0.4.1"
|
version = "0.4.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b4ce301924b7887e9d637144fdade93f9dfff9b60981d4ac161db09720d39aa5"
|
checksum = "f5e54036fe321fd421e10d732f155734c4e4afd610dd556d9a82833ab3ee0bed"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lock_api"
|
name = "lock_api"
|
||||||
@@ -1083,7 +1103,7 @@ version = "0.12.5"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38"
|
checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"hashbrown 0.15.4",
|
"hashbrown 0.15.5",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1173,7 +1193,7 @@ checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "oxker"
|
name = "oxker"
|
||||||
version = "0.10.5"
|
version = "0.11.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"bollard",
|
"bollard",
|
||||||
@@ -1228,9 +1248,9 @@ checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "percent-encoding"
|
name = "percent-encoding"
|
||||||
version = "2.3.1"
|
version = "2.3.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
|
checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pin-project-lite"
|
name = "pin-project-lite"
|
||||||
@@ -1285,9 +1305,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.95"
|
version = "1.0.101"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
|
checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
@@ -1309,9 +1329,9 @@ checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rand"
|
name = "rand"
|
||||||
version = "0.9.1"
|
version = "0.9.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97"
|
checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"rand_chacha",
|
"rand_chacha",
|
||||||
"rand_core",
|
"rand_core",
|
||||||
@@ -1359,18 +1379,18 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "redox_syscall"
|
name = "redox_syscall"
|
||||||
version = "0.5.13"
|
version = "0.5.17"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0d04b7d0ee6b4a0207a0a7adb104d23ecb0b47d6beae7152d0fa34b692b29fd6"
|
checksum = "5407465600fb0548f1442edf71dd20683c6ed326200ace4b1ef0763521bb3b77"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "redox_users"
|
name = "redox_users"
|
||||||
version = "0.5.0"
|
version = "0.5.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "dd6f9d3d47bdd2ad6945c5015a226ec6155d0bcdfd8f7cd29f86b71f8de99d2b"
|
checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"getrandom 0.2.16",
|
"getrandom 0.2.16",
|
||||||
"libredox",
|
"libredox",
|
||||||
@@ -1399,9 +1419,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustc-demangle"
|
name = "rustc-demangle"
|
||||||
version = "0.1.25"
|
version = "0.1.26"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "989e6739f80c4ad5b13e0fd7fe89531180375b18520cc8c82080e4dc4035b84f"
|
checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustix"
|
name = "rustix"
|
||||||
@@ -1418,22 +1438,22 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustix"
|
name = "rustix"
|
||||||
version = "1.0.7"
|
version = "1.0.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266"
|
checksum = "11181fbabf243db407ef8df94a6ce0b2f9a733bd8be4ad02b4eda9602296cac8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"errno",
|
"errno",
|
||||||
"libc",
|
"libc",
|
||||||
"linux-raw-sys 0.9.4",
|
"linux-raw-sys 0.9.4",
|
||||||
"windows-sys 0.59.0",
|
"windows-sys 0.60.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustversion"
|
name = "rustversion"
|
||||||
version = "1.0.21"
|
version = "1.0.22"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d"
|
checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ryu"
|
name = "ryu"
|
||||||
@@ -1453,6 +1473,18 @@ dependencies = [
|
|||||||
"serde_json",
|
"serde_json",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "schemars"
|
||||||
|
version = "1.0.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "82d20c4491bc164fa2f6c5d44565947a52ad80b9505d8e36f8d54c27c739fcd0"
|
||||||
|
dependencies = [
|
||||||
|
"dyn-clone",
|
||||||
|
"ref-cast",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "scopeguard"
|
name = "scopeguard"
|
||||||
version = "1.2.0"
|
version = "1.2.0"
|
||||||
@@ -1481,9 +1513,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_json"
|
name = "serde_json"
|
||||||
version = "1.0.140"
|
version = "1.0.143"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373"
|
checksum = "d401abef1d108fbd9cbaebc3e46611f4b1021f714a0597a71f41ee463f5f4a5a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"itoa",
|
"itoa",
|
||||||
"memchr",
|
"memchr",
|
||||||
@@ -1515,9 +1547,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_spanned"
|
name = "serde_spanned"
|
||||||
version = "0.6.9"
|
version = "1.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3"
|
checksum = "40734c41988f7306bb04f0ecf60ec0f3f1caa34290e4e8ea471dcd3346483b83"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
@@ -1536,16 +1568,17 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_with"
|
name = "serde_with"
|
||||||
version = "3.13.0"
|
version = "3.14.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bf65a400f8f66fb7b0552869ad70157166676db75ed8181f8104ea91cf9d0b42"
|
checksum = "f2c45cd61fefa9db6f254525d46e392b852e0e61d9a1fd36e5bd183450a556d5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64",
|
"base64",
|
||||||
"chrono",
|
"chrono",
|
||||||
"hex",
|
"hex",
|
||||||
"indexmap 1.9.3",
|
"indexmap 1.9.3",
|
||||||
"indexmap 2.9.0",
|
"indexmap 2.10.0",
|
||||||
"schemars",
|
"schemars 0.9.0",
|
||||||
|
"schemars 1.0.4",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
@@ -1590,9 +1623,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "signal-hook-registry"
|
name = "signal-hook-registry"
|
||||||
version = "1.4.5"
|
version = "1.4.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9203b8055f63a2a00e2f593bb0510367fe707d7ff1e5c872de2f537b339e5410"
|
checksum = "b2a4719bff48cee6b39d12c020eeb490953ad2443b7055bd0b21fca26bd8c28b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
@@ -1605,9 +1638,9 @@ checksum = "bbbb5d9659141646ae647b42fe094daf6c6192d1620870b449d9557f748b2daa"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "slab"
|
name = "slab"
|
||||||
version = "0.4.10"
|
version = "0.4.11"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "04dc19736151f35336d325007ac991178d504a119863a2fcb3758cdb5e52c50d"
|
checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "smallvec"
|
name = "smallvec"
|
||||||
@@ -1617,12 +1650,12 @@ checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "socket2"
|
name = "socket2"
|
||||||
version = "0.5.10"
|
version = "0.6.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678"
|
checksum = "233504af464074f9d066d7b5416c5f9b894a5862a6506e306f7b816cdd6f1807"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.59.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1667,9 +1700,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "2.0.103"
|
version = "2.0.106"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e4307e30089d6fd6aff212f2da3a1f9e32f3223b1f010fb09b7c95f90f3ca1e8"
|
checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -1689,18 +1722,18 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thiserror"
|
name = "thiserror"
|
||||||
version = "2.0.12"
|
version = "2.0.16"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708"
|
checksum = "3467d614147380f2e4e374161426ff399c91084acd2363eaf549172b3d5e60c0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"thiserror-impl",
|
"thiserror-impl",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thiserror-impl"
|
name = "thiserror-impl"
|
||||||
version = "2.0.12"
|
version = "2.0.16"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d"
|
checksum = "6c5e1be1c48b9172ee610da68fd9cd2770e7a4056cb3fc98710ee6906f0c7960"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -1759,20 +1792,22 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio"
|
name = "tokio"
|
||||||
version = "1.45.1"
|
version = "1.47.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "75ef51a33ef1da925cea3e4eb122833cb377c61439ca401b770f54902b806779"
|
checksum = "89e49afdadebb872d3145a5638b59eb0691ea23e46ca484037cfab3b76b95038"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"backtrace",
|
"backtrace",
|
||||||
"bytes",
|
"bytes",
|
||||||
|
"io-uring",
|
||||||
"libc",
|
"libc",
|
||||||
"mio",
|
"mio",
|
||||||
"parking_lot",
|
"parking_lot",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"signal-hook-registry",
|
"signal-hook-registry",
|
||||||
|
"slab",
|
||||||
"socket2",
|
"socket2",
|
||||||
"tokio-macros",
|
"tokio-macros",
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.59.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1788,9 +1823,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio-util"
|
name = "tokio-util"
|
||||||
version = "0.7.15"
|
version = "0.7.16"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "66a539a9ad6d5d281510d5bd368c973d636c02dbf8a67300bfb6b950696ad7df"
|
checksum = "14307c986784f72ef81c89db7d9e28d6ac26d16213b109ea501696195e6e3ce5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"futures-core",
|
"futures-core",
|
||||||
@@ -1801,35 +1836,32 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toml"
|
name = "toml"
|
||||||
version = "0.8.23"
|
version = "0.9.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362"
|
checksum = "75129e1dc5000bfbaa9fee9d1b21f974f9fbad9daec557a521ee6e080825f6e8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
"serde_spanned",
|
"serde_spanned",
|
||||||
"toml_datetime",
|
"toml_datetime",
|
||||||
"toml_edit",
|
"toml_parser",
|
||||||
|
"winnow",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toml_datetime"
|
name = "toml_datetime"
|
||||||
version = "0.6.11"
|
version = "0.7.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c"
|
checksum = "bade1c3e902f58d73d3f294cd7f20391c1cb2fbcb643b73566bc773971df91e3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toml_edit"
|
name = "toml_parser"
|
||||||
version = "0.22.27"
|
version = "1.0.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a"
|
checksum = "b551886f449aa90d4fe2bdaa9f4a2577ad2dde302c61ecf262d80b116db95c10"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"indexmap 2.9.0",
|
|
||||||
"serde",
|
|
||||||
"serde_spanned",
|
|
||||||
"toml_datetime",
|
|
||||||
"winnow",
|
"winnow",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -1945,9 +1977,9 @@ checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "url"
|
name = "url"
|
||||||
version = "2.5.4"
|
version = "2.5.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60"
|
checksum = "137a3c834eaf7139b73688502f3f1141a0337c5d8e4d9b536f9b8c796e26a7c4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"form_urlencoded",
|
"form_urlencoded",
|
||||||
"idna",
|
"idna",
|
||||||
@@ -1968,9 +2000,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uuid"
|
name = "uuid"
|
||||||
version = "1.17.0"
|
version = "1.18.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3cf4199d1e5d15ddd86a694e4d0dffa9c323ce759fea589f00fef9d81cc1931d"
|
checksum = "f33196643e165781c20a5ead5582283a7dacbb87855d867fbc2df3f81eddc1be"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"getrandom 0.3.3",
|
"getrandom 0.3.3",
|
||||||
"js-sys",
|
"js-sys",
|
||||||
@@ -2147,15 +2179,6 @@ dependencies = [
|
|||||||
"windows-link",
|
"windows-link",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows-sys"
|
|
||||||
version = "0.52.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
|
|
||||||
dependencies = [
|
|
||||||
"windows-targets 0.52.6",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-sys"
|
name = "windows-sys"
|
||||||
version = "0.59.0"
|
version = "0.59.0"
|
||||||
@@ -2171,7 +2194,7 @@ version = "0.60.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb"
|
checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows-targets 0.53.2",
|
"windows-targets 0.53.3",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2192,10 +2215,11 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-targets"
|
name = "windows-targets"
|
||||||
version = "0.53.2"
|
version = "0.53.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c66f69fcc9ce11da9966ddb31a40968cad001c5bedeb5c2b82ede4253ab48aef"
|
checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"windows-link",
|
||||||
"windows_aarch64_gnullvm 0.53.0",
|
"windows_aarch64_gnullvm 0.53.0",
|
||||||
"windows_aarch64_msvc 0.53.0",
|
"windows_aarch64_msvc 0.53.0",
|
||||||
"windows_i686_gnu 0.53.0",
|
"windows_i686_gnu 0.53.0",
|
||||||
@@ -2304,12 +2328,9 @@ checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winnow"
|
name = "winnow"
|
||||||
version = "0.7.11"
|
version = "0.7.12"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "74c7b26e3480b707944fc872477815d29a8e429d2f93a1ce000f5fa84a15cbcd"
|
checksum = "f3edebf492c8125044983378ecb5766203ad3b4c2f7a922bd7dd207f6d443e95"
|
||||||
dependencies = [
|
|
||||||
"memchr",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wit-bindgen-rt"
|
name = "wit-bindgen-rt"
|
||||||
@@ -2352,18 +2373,18 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zerocopy"
|
name = "zerocopy"
|
||||||
version = "0.8.25"
|
version = "0.8.26"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a1702d9583232ddb9174e01bb7c15a2ab8fb1bc6f227aa1233858c351a3ba0cb"
|
checksum = "1039dd0d3c310cf05de012d8a39ff557cb0d23087fd44cad61df08fc31907a2f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"zerocopy-derive",
|
"zerocopy-derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zerocopy-derive"
|
name = "zerocopy-derive"
|
||||||
version = "0.8.25"
|
version = "0.8.26"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "28a6e20d751156648aa063f3800b706ee209a32c0b4d9f24be3d980b01be55ef"
|
checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -2404,9 +2425,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zerovec"
|
name = "zerovec"
|
||||||
version = "0.11.2"
|
version = "0.11.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4a05eb080e015ba39cc9e23bbe5e7fb04d5fb040350f99f34e338d5fdd294428"
|
checksum = "e7aa2bd55086f1ab526693ecbe444205da57e25f4489879da80635a46d90e73b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"yoke",
|
"yoke",
|
||||||
"zerofrom",
|
"zerofrom",
|
||||||
|
|||||||
+5
-5
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "oxker"
|
name = "oxker"
|
||||||
version = "0.10.5"
|
version = "0.11.0"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
authors = ["Jack Wills <email@mrjackwills.com>"]
|
authors = ["Jack Wills <email@mrjackwills.com>"]
|
||||||
description = "A simple tui to view & control docker containers"
|
description = "A simple tui to view & control docker containers"
|
||||||
@@ -27,7 +27,7 @@ similar_names = "allow"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0"
|
anyhow = "1.0"
|
||||||
bollard = "0.18"
|
bollard = "0.19"
|
||||||
cansi = "2.2"
|
cansi = "2.2"
|
||||||
clap = { version = "4.5", features = ["color", "derive", "unicode"] }
|
clap = { version = "4.5", features = ["color", "derive", "unicode"] }
|
||||||
crossterm = "0.29"
|
crossterm = "0.29"
|
||||||
@@ -39,12 +39,12 @@ ratatui = "0.29"
|
|||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
serde_jsonc = "1.0"
|
serde_jsonc = "1.0"
|
||||||
tokio = { version = "1.45", features = ["full"] }
|
tokio = { version = "1.47", features = ["full"] }
|
||||||
tokio-util = "0.7"
|
tokio-util = "0.7"
|
||||||
toml = { version = "0.8", default-features = false, features = ["parse"] }
|
toml = { version = "0.9", default-features = false, features = ["parse", "serde"] }
|
||||||
tracing = "0.1"
|
tracing = "0.1"
|
||||||
tracing-subscriber = "0.3"
|
tracing-subscriber = "0.3"
|
||||||
uuid = { version = "1.17", features = ["fast-rng", "v4"] }
|
uuid = { version = "1.18", features = ["fast-rng", "v4"] }
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
lto = true
|
lto = true
|
||||||
|
|||||||
@@ -105,7 +105,9 @@ In application controls, these, amongst many other settings, can be customized w
|
|||||||
| button| result|
|
| button| result|
|
||||||
|--|--|
|
|--|--|
|
||||||
| ```( tab )``` or ```( shift+tab )``` | Change panel, clicking on a panel also changes the selected panel.|
|
| ```( tab )``` or ```( shift+tab )``` | Change panel, clicking on a panel also changes the selected panel.|
|
||||||
| ```( ↑ ↓ )``` or ```( j k )``` or ```( PgUp PgDown )``` or ```( Home End )```| Change selected line in selected panel, mouse scroll also changes selected line.|
|
| ```( ↑ ↓ )``` or ```( j k )``` or ```( PgUp PgDown )``` or ```( Home End )```| Scroll line in selected panel - mouse wheel will also scroll.|
|
||||||
|
| ```( ← → )``` | When logs panel selected, scroll horizontally across the text of the logs.|
|
||||||
|
| ```( ctrl )``` | Increase scroll speed, used in conjuction scroll keys.|
|
||||||
| ```( enter )```| Run selected docker command.|
|
| ```( enter )```| Run selected docker command.|
|
||||||
| ```( 1-9 )``` | Sort containers by heading, clicking on headings also sorts the selected column. |
|
| ```( 1-9 )``` | Sort containers by heading, clicking on headings also sorts the selected column. |
|
||||||
| ```( 0 )``` | Stop sorting.|
|
| ```( 0 )``` | Stop sorting.|
|
||||||
@@ -113,6 +115,7 @@ In application controls, these, amongst many other settings, can be customized w
|
|||||||
| ```( - ) ``` or ```(=)``` | Reduce or increase the height of the logs panel.|
|
| ```( - ) ``` or ```(=)``` | Reduce or increase the height of the logs panel.|
|
||||||
| ```( \ )``` | Toggle the visibility of the logs panel.|
|
| ```( \ )``` | Toggle the visibility of the logs panel.|
|
||||||
| ```( e )``` | Exec into the selected container - not available on Windows.|
|
| ```( e )``` | Exec into the selected container - not available on Windows.|
|
||||||
|
| ```( f )``` | Force clear the screen & redraw the gui.|
|
||||||
| ```( h )``` | Toggle help menu.|
|
| ```( h )``` | Toggle help menu.|
|
||||||
| ```( m )``` | Toggle mouse capture - if disabled, text on screen can be selected.|
|
| ```( m )``` | Toggle mouse capture - if disabled, text on screen can be selected.|
|
||||||
| ```( q )``` | Quit.|
|
| ```( q )``` | Quit.|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ networks:
|
|||||||
name: oxker-examaple-net
|
name: oxker-examaple-net
|
||||||
services:
|
services:
|
||||||
postgres:
|
postgres:
|
||||||
image: postgres:alpine3.21
|
image: postgres:17-alpine
|
||||||
container_name: postgres
|
container_name: postgres
|
||||||
environment:
|
environment:
|
||||||
- POSTGRES_PASSWORD=never_use_this_password_in_production
|
- POSTGRES_PASSWORD=never_use_this_password_in_production
|
||||||
@@ -18,7 +18,7 @@ services:
|
|||||||
limits:
|
limits:
|
||||||
memory: 1024M
|
memory: 1024M
|
||||||
redis:
|
redis:
|
||||||
image: redis:alpine3.21
|
image: redis:latest
|
||||||
container_name: redis
|
container_name: redis
|
||||||
ipc: private
|
ipc: private
|
||||||
restart: always
|
restart: always
|
||||||
|
|||||||
@@ -42,6 +42,7 @@
|
|||||||
// 3) F1-F12
|
// 3) F1-F12
|
||||||
// 4) backspace, tab, backtab, delete, end, esc, home, insert, pagedown, pageup, left, right, up, down
|
// 4) backspace, tab, backtab, delete, end, esc, home, insert, pagedown, pageup, left, right, up, down
|
||||||
// Each definition can have two keys associated with it
|
// Each definition can have two keys associated with it
|
||||||
|
// WARNING "scroll_many" only accepts control, alt, shift, with no secondary option
|
||||||
// If any key clashes are found, oxker will revert to it's default keymap
|
// If any key clashes are found, oxker will revert to it's default keymap
|
||||||
"keymap": {
|
"keymap": {
|
||||||
// Clear any popup boxes, filter panel, or help panel
|
// Clear any popup boxes, filter panel, or help panel
|
||||||
@@ -74,10 +75,12 @@
|
|||||||
"save_logs": [
|
"save_logs": [
|
||||||
"s"
|
"s"
|
||||||
],
|
],
|
||||||
|
// TODO "scroll_down_many" will be removed in the next release
|
||||||
// Scroll down a list by many
|
// Scroll down a list by many
|
||||||
"scroll_down_many": [
|
"scroll_down_many": [
|
||||||
"pagedown"
|
"pagedown"
|
||||||
],
|
],
|
||||||
|
// TODO rename in next release
|
||||||
// Scroll down a list by one item
|
// Scroll down a list by one item
|
||||||
"scroll_down_one": [
|
"scroll_down_one": [
|
||||||
"down",
|
"down",
|
||||||
@@ -87,19 +90,30 @@
|
|||||||
"scroll_end": [
|
"scroll_end": [
|
||||||
"end"
|
"end"
|
||||||
],
|
],
|
||||||
|
// Modifier to scroll by 10 lines isntead of one, used in conjunction with scroll_up_x/scroll_down_x
|
||||||
|
"scroll_many": ["control"],
|
||||||
// Scroll up to the start of a list
|
// Scroll up to the start of a list
|
||||||
"scroll_start": [
|
"scroll_start": [
|
||||||
"home"
|
"home"
|
||||||
],
|
],
|
||||||
|
// TODO "scroll_up_many" will be removed in the next release
|
||||||
// Scroll up a list by many
|
// Scroll up a list by many
|
||||||
"scroll_up_many": [
|
"scroll_up_many": [
|
||||||
"pageup"
|
"pageup"
|
||||||
],
|
],
|
||||||
|
// TODO rename in next release
|
||||||
// Scroll up a list by one item
|
// Scroll up a list by one item
|
||||||
"scroll_up_one": [
|
"scroll_up_one": [
|
||||||
"up",
|
"up",
|
||||||
"k"
|
"k"
|
||||||
],
|
],
|
||||||
|
// Horizontal scroll of the logs
|
||||||
|
"log_scroll_forward": [
|
||||||
|
"right"
|
||||||
|
],
|
||||||
|
"log_scroll_back": [
|
||||||
|
"left"
|
||||||
|
],
|
||||||
// Select next panel
|
// Select next panel
|
||||||
"select_next_panel": [
|
"select_next_panel": [
|
||||||
"tab"
|
"tab"
|
||||||
@@ -159,6 +173,10 @@
|
|||||||
// Toggle visibility of the log section
|
// Toggle visibility of the log section
|
||||||
"log_section_toggle": [
|
"log_section_toggle": [
|
||||||
"\\"
|
"\\"
|
||||||
|
],
|
||||||
|
// Force a complete clear & redraw of the screen
|
||||||
|
"force_redraw": [
|
||||||
|
"f"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
////////////////////
|
////////////////////
|
||||||
|
|||||||
@@ -55,8 +55,10 @@ show_logs = true
|
|||||||
# 3) F1-F12
|
# 3) F1-F12
|
||||||
# 4) backspace, tab, backtab, delete, end, esc, home, insert, pagedown, pageup, left, right, up, down
|
# 4) backspace, tab, backtab, delete, end, esc, home, insert, pagedown, pageup, left, right, up, down
|
||||||
|
|
||||||
|
|
||||||
# Each definition can have two keys associated with it
|
# Each definition can have two keys associated with it
|
||||||
|
|
||||||
|
# WARNING "scroll_many" only accepts control, alt, shift, with no secondary option
|
||||||
|
|
||||||
# If any key clashes are found, oxker will revert to it's default keymap
|
# If any key clashes are found, oxker will revert to it's default keymap
|
||||||
|
|
||||||
[keymap]
|
[keymap]
|
||||||
@@ -74,18 +76,28 @@ filter_mode = ["/", "F1"]
|
|||||||
quit = ["q"]
|
quit = ["q"]
|
||||||
# Save logs of selected container to file on disk
|
# Save logs of selected container to file on disk
|
||||||
save_logs = ["s"]
|
save_logs = ["s"]
|
||||||
|
# TODO "scroll_down_many" will be removed in the next release
|
||||||
# scroll down a list by many
|
# scroll down a list by many
|
||||||
scroll_down_many = ["pagedown"]
|
scroll_down_many = ["pagedown"]
|
||||||
|
# TODO rename in next release
|
||||||
# scroll down a list by one item
|
# scroll down a list by one item
|
||||||
scroll_down_one = ["down", "j"]
|
scroll_down_one = ["down", "j"]
|
||||||
|
|
||||||
# scroll down to the end of a list
|
# scroll down to the end of a list
|
||||||
scroll_end = ["end"]
|
scroll_end = ["end"]
|
||||||
|
# Modifier to scroll by 10 lines isntead of one, used in conjunction with scroll_up_x/scroll_down_x
|
||||||
|
scroll_many = ["control"]
|
||||||
# scroll up to the start of a list
|
# scroll up to the start of a list
|
||||||
scroll_start = ["home"]
|
scroll_start = ["home"]
|
||||||
|
# TODO "scroll_up_many" will be removed in the next release
|
||||||
# scroll up a list by many
|
# scroll up a list by many
|
||||||
scroll_up_many = ["pageup"]
|
scroll_up_many = ["pageup"]
|
||||||
|
# TODO rename in next release
|
||||||
# scroll up a list by one item
|
# scroll up a list by one item
|
||||||
scroll_up_one = ["up", "k"]
|
scroll_up_one = ["up", "k"]
|
||||||
|
# Horizontal scroll of the logs
|
||||||
|
log_scroll_forward = ["right"]
|
||||||
|
log_scroll_back = ["left"]
|
||||||
# Select next panel
|
# Select next panel
|
||||||
select_next_panel = ["tab"]
|
select_next_panel = ["tab"]
|
||||||
# Select previous panel
|
# Select previous panel
|
||||||
@@ -108,10 +120,11 @@ toggle_help = ["h"]
|
|||||||
toggle_mouse_capture = ["m"]
|
toggle_mouse_capture = ["m"]
|
||||||
# Reduce the height of the logs list section
|
# Reduce the height of the logs list section
|
||||||
log_section_height_decrease = ["-"]
|
log_section_height_decrease = ["-"]
|
||||||
# Increase the height of the logs list section
|
|
||||||
log_section_height_increase = ["+"]
|
log_section_height_increase = ["+"]
|
||||||
# Toggle visibility of the log section
|
# Toggle visibility of the log section
|
||||||
log_section_toggle = ["\\"]
|
log_section_toggle = ["\\"]
|
||||||
|
# Force a complete clear & redraw of the screen
|
||||||
|
force_redraw = ["f"]
|
||||||
|
|
||||||
#################
|
#################
|
||||||
# Custom Colors #
|
# Custom Colors #
|
||||||
@@ -186,6 +199,7 @@ selected_filter_text = "black"
|
|||||||
# Highlighted text color
|
# Highlighted text color
|
||||||
highlight = "magenta"
|
highlight = "magenta"
|
||||||
|
|
||||||
|
|
||||||
# The color the of Docker commands available for each container
|
# The color the of Docker commands available for each container
|
||||||
[colors.commands]
|
[colors.commands]
|
||||||
# Background color of panel
|
# Background color of panel
|
||||||
|
|||||||
+257
-54
@@ -8,8 +8,10 @@ use std::{
|
|||||||
use bollard::service::Port;
|
use bollard::service::Port;
|
||||||
use jiff::{Timestamp, tz::TimeZone};
|
use jiff::{Timestamp, tz::TimeZone};
|
||||||
use ratatui::{
|
use ratatui::{
|
||||||
|
layout::Size,
|
||||||
style::Color,
|
style::Color,
|
||||||
widgets::{ListItem, ListState},
|
text::{Line, Text},
|
||||||
|
widgets::ListState,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::config::AppColors;
|
use crate::config::AppColors;
|
||||||
@@ -30,14 +32,6 @@ impl From<&str> for ContainerId {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ContainerId {
|
impl ContainerId {
|
||||||
// TODO remove this once zigbuild uses Rust v1.87.0
|
|
||||||
#[cfg(target_os = "macos")]
|
|
||||||
#[allow(clippy::missing_const_for_fn)]
|
|
||||||
pub fn get(&self) -> &str {
|
|
||||||
self.0.as_str()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(target_os = "macos"))]
|
|
||||||
pub const fn get(&self) -> &str {
|
pub const fn get(&self) -> &str {
|
||||||
self.0.as_str()
|
self.0.as_str()
|
||||||
}
|
}
|
||||||
@@ -84,14 +78,6 @@ macro_rules! unit_struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl $name {
|
impl $name {
|
||||||
#[cfg(target_os = "macos")]
|
|
||||||
#[allow(clippy::missing_const_for_fn)]
|
|
||||||
// TODO remove this once zigbuild uses Rust v1.87.0
|
|
||||||
pub fn get(&self) -> &str {
|
|
||||||
self.0.as_str()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(target_os = "macos"))]
|
|
||||||
pub const fn get(&self) -> &str {
|
pub const fn get(&self) -> &str {
|
||||||
self.0.as_str()
|
self.0.as_str()
|
||||||
}
|
}
|
||||||
@@ -215,6 +201,7 @@ impl<T> StatefulList<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Return the current status of the select list, e.g. 2/5,
|
/// Return the current status of the select list, e.g. 2/5,
|
||||||
|
/// MAYBE add up down arrows, check if at start or end etc
|
||||||
pub fn get_state_title(&self) -> String {
|
pub fn get_state_title(&self) -> String {
|
||||||
if self.items.is_empty() {
|
if self.items.is_empty() {
|
||||||
String::new()
|
String::new()
|
||||||
@@ -342,6 +329,54 @@ impl From<(&str, &ContainerStatus)> for State {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Need status, to check if container is unhealthy or not
|
||||||
|
impl
|
||||||
|
From<(
|
||||||
|
&bollard::secret::ContainerSummaryStateEnum,
|
||||||
|
&ContainerStatus,
|
||||||
|
)> for State
|
||||||
|
{
|
||||||
|
fn from(
|
||||||
|
(input, status): (
|
||||||
|
&bollard::secret::ContainerSummaryStateEnum,
|
||||||
|
&ContainerStatus,
|
||||||
|
),
|
||||||
|
) -> Self {
|
||||||
|
match input {
|
||||||
|
bollard::secret::ContainerSummaryStateEnum::DEAD => Self::Dead,
|
||||||
|
bollard::secret::ContainerSummaryStateEnum::EXITED => Self::Exited,
|
||||||
|
bollard::secret::ContainerSummaryStateEnum::PAUSED => Self::Paused,
|
||||||
|
bollard::secret::ContainerSummaryStateEnum::REMOVING => Self::Removing,
|
||||||
|
bollard::secret::ContainerSummaryStateEnum::RESTARTING => Self::Restarting,
|
||||||
|
bollard::secret::ContainerSummaryStateEnum::RUNNING => {
|
||||||
|
if status.unhealthy() {
|
||||||
|
Self::Running(RunningState::Unhealthy)
|
||||||
|
} else {
|
||||||
|
Self::Running(RunningState::Healthy)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => Self::Unknown,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Again, need status, to check if container is unhealthy or not
|
||||||
|
impl
|
||||||
|
From<(
|
||||||
|
Option<&bollard::secret::ContainerSummaryStateEnum>,
|
||||||
|
&ContainerStatus,
|
||||||
|
)> for State
|
||||||
|
{
|
||||||
|
fn from(
|
||||||
|
(input, status): (
|
||||||
|
Option<&bollard::secret::ContainerSummaryStateEnum>,
|
||||||
|
&ContainerStatus,
|
||||||
|
),
|
||||||
|
) -> Self {
|
||||||
|
input.map_or(Self::Unknown, |input| Self::from((input, status)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Again, need status, to check if container is unhealthy or not
|
/// Again, need status, to check if container is unhealthy or not
|
||||||
impl From<(Option<String>, &ContainerStatus)> for State {
|
impl From<(Option<String>, &ContainerStatus)> for State {
|
||||||
fn from((input, status): (Option<String>, &ContainerStatus)) -> Self {
|
fn from((input, status): (Option<String>, &ContainerStatus)) -> Self {
|
||||||
@@ -563,81 +598,177 @@ impl LogsTz {
|
|||||||
/// stateful list dependent on whether the timestamp is in the HashSet or not
|
/// stateful list dependent on whether the timestamp is in the HashSet or not
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct Logs {
|
pub struct Logs {
|
||||||
logs: StatefulList<ListItem<'static>>,
|
lines: StatefulList<Text<'static>>,
|
||||||
tz: HashSet<LogsTz>,
|
tz: HashSet<LogsTz>,
|
||||||
|
offset: u16,
|
||||||
|
max_log_len: usize,
|
||||||
|
adjusted_max_width: usize,
|
||||||
|
adjust_max_width_text_len: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Logs {
|
impl Default for Logs {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
let mut logs = StatefulList::new(vec![]);
|
let mut lines = StatefulList::new(vec![]);
|
||||||
logs.end();
|
lines.end();
|
||||||
Self {
|
Self {
|
||||||
logs,
|
lines,
|
||||||
tz: HashSet::new(),
|
tz: HashSet::new(),
|
||||||
|
offset: 0,
|
||||||
|
adjusted_max_width: 0,
|
||||||
|
adjust_max_width_text_len: 0,
|
||||||
|
max_log_len: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Logs {
|
impl Logs {
|
||||||
/// Only allow a new log line to be inserted if the log timestamp isn't in the tz HashSet
|
/// Only allow a new log line to be inserted if the log timestamp isn't in the tz HashSet
|
||||||
pub fn insert(&mut self, line: ListItem<'static>, tz: LogsTz) {
|
pub fn insert(&mut self, line: Text<'static>, tz: LogsTz) {
|
||||||
if self.tz.insert(tz) {
|
if self.tz.insert(tz) {
|
||||||
self.logs.items.push(line);
|
self.max_log_len = self.max_log_len.max(line.width());
|
||||||
|
self.lines.items.push(line);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the logs vec, but instead of cloning to whole vec, only clone items with x of the currently selected index
|
/// If scrolling horiztonally along the logs, display a counter of the position in the in the scroll, `x/y`
|
||||||
|
pub fn get_scroll_title(&mut self, width: u16) -> Option<String> {
|
||||||
|
if self.horizontal_scroll_able(width) {
|
||||||
|
let text_width = self.adjust_max_width_text_len;
|
||||||
|
let arrow_left = if self.offset > 0 { " ←" } else { " " };
|
||||||
|
let arrow_right = if usize::from(self.offset) < self.adjusted_max_width {
|
||||||
|
"→ "
|
||||||
|
} else {
|
||||||
|
" "
|
||||||
|
};
|
||||||
|
Some(format!(
|
||||||
|
"{left} {offset:>text_width$}/{adjusted_max_width} {right}",
|
||||||
|
offset = self.offset,
|
||||||
|
adjusted_max_width = self.adjusted_max_width,
|
||||||
|
left = arrow_left,
|
||||||
|
right = arrow_right,
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Format a log lone. Only return screen width amount of chars
|
||||||
|
/// If offset set, remove `char_offset` number of chars from a Text
|
||||||
|
/// `text` *should* only be a single line, so just use the .first() method rather than trying to iterate
|
||||||
|
fn format_log_line(text: &Text<'static>, char_offset: usize, width: u16) -> Text<'static> {
|
||||||
|
let mut skipped = 0;
|
||||||
|
text.lines.first().map_or_else(Text::default, |line| {
|
||||||
|
Text::from(Line::from(
|
||||||
|
line.spans
|
||||||
|
.iter()
|
||||||
|
.filter_map(|span| {
|
||||||
|
if skipped >= char_offset {
|
||||||
|
Some(ratatui::text::Span::styled(
|
||||||
|
span.content.chars().take(width.into()).collect::<String>(),
|
||||||
|
span.style,
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
let span_len = span.content.chars().count();
|
||||||
|
if skipped + span_len <= char_offset {
|
||||||
|
skipped += span_len;
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
let start_index = char_offset - skipped;
|
||||||
|
skipped = char_offset;
|
||||||
|
Some(ratatui::text::Span::styled(
|
||||||
|
span.content
|
||||||
|
.chars()
|
||||||
|
.skip(start_index)
|
||||||
|
.take(width.into())
|
||||||
|
.collect::<String>(),
|
||||||
|
span.style,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>(),
|
||||||
|
))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the logs vec, but instead of cloning to whole vec, only clone items within x of the currently selected index, as well as only the current screen widths number of chars
|
||||||
/// Where x is the abs different of the index plus the panel height & a padding
|
/// Where x is the abs different of the index plus the panel height & a padding
|
||||||
|
/// Take into account the char offset, so that can scroll a line
|
||||||
/// The rest can be just empty list items
|
/// The rest can be just empty list items
|
||||||
pub fn to_vec(&self, height: usize, padding: usize) -> Vec<ListItem<'static>> {
|
pub fn get_visible_logs(&self, size: Size, padding: usize) -> Vec<Text<'static>> {
|
||||||
let current_index = self.logs.state.selected().unwrap_or_default();
|
let current_index = self.lines.state.selected().unwrap_or_default();
|
||||||
self.logs
|
let height_padding = usize::from(size.height) + padding;
|
||||||
|
let char_offset = if usize::from(self.offset) > self.max_log_len {
|
||||||
|
self.max_log_len
|
||||||
|
} else {
|
||||||
|
self.offset.into()
|
||||||
|
};
|
||||||
|
|
||||||
|
self.lines
|
||||||
.items
|
.items
|
||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(index, item)| {
|
.map(|(index, item)| {
|
||||||
if current_index.abs_diff(index) <= height + padding {
|
if current_index.abs_diff(index) <= height_padding {
|
||||||
item.clone()
|
Self::format_log_line(item, char_offset, size.width)
|
||||||
} else {
|
} else {
|
||||||
ListItem::from("")
|
Text::from("")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The rest of the methods are basically forwarding from the underlying StatefulList
|
/// The rest of the methods are basically forwarding from the underlying StatefulList
|
||||||
pub fn get_state_title(&self) -> String {
|
pub fn get_state_title(&self) -> String {
|
||||||
self.logs.get_state_title()
|
self.lines.get_state_title()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return true it currently selected cotnainer logs are wide enough to horizontally scroll
|
||||||
|
pub fn horizontal_scroll_able(&mut self, width: u16) -> bool {
|
||||||
|
if self.lines.items.is_empty() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
self.adjusted_max_width = self.max_log_len.saturating_sub(width.into()) + 4;
|
||||||
|
self.adjust_max_width_text_len = self.adjusted_max_width.to_string().chars().count();
|
||||||
|
self.max_log_len + 4 > usize::from(width)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Add a padding so one char will always be visilbe?
|
||||||
|
pub fn forward(&mut self, width: u16) {
|
||||||
|
let offset = usize::from(self.offset);
|
||||||
|
if self.horizontal_scroll_able(width) {
|
||||||
|
if self.adjusted_max_width > 0 && offset < self.adjusted_max_width {
|
||||||
|
self.offset = self.offset.saturating_add(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Reduce the char offset
|
||||||
|
pub const fn back(&mut self) {
|
||||||
|
self.offset = self.offset.saturating_sub(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn next(&mut self) {
|
pub fn next(&mut self) {
|
||||||
self.logs.next();
|
self.lines.next();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn previous(&mut self) {
|
pub fn previous(&mut self) {
|
||||||
self.logs.previous();
|
self.lines.previous();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn end(&mut self) {
|
pub fn end(&mut self) {
|
||||||
self.logs.end();
|
self.lines.end();
|
||||||
}
|
}
|
||||||
pub fn start(&mut self) {
|
pub fn start(&mut self) {
|
||||||
self.logs.start();
|
self.lines.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO remove this once zigbuild uses Rust v1.87.0
|
|
||||||
#[cfg(target_os = "macos")]
|
|
||||||
#[allow(clippy::missing_const_for_fn)]
|
|
||||||
pub fn len(&self) -> usize {
|
|
||||||
self.logs.items.len()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(target_os = "macos"))]
|
|
||||||
pub const fn len(&self) -> usize {
|
pub const fn len(&self) -> usize {
|
||||||
self.logs.items.len()
|
self.lines.items.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const fn state(&mut self) -> &mut ListState {
|
pub const fn state(&mut self) -> &mut ListState {
|
||||||
&mut self.logs.state
|
&mut self.lines.state
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -801,7 +932,10 @@ impl Columns {
|
|||||||
mod tests {
|
mod tests {
|
||||||
|
|
||||||
use jiff::tz::TimeZone;
|
use jiff::tz::TimeZone;
|
||||||
use ratatui::widgets::ListItem;
|
use ratatui::{
|
||||||
|
layout::Size,
|
||||||
|
text::{Line, Text},
|
||||||
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
app_data::{ContainerImage, Logs, LogsTz, RunningState},
|
app_data::{ContainerImage, Logs, LogsTz, RunningState},
|
||||||
@@ -941,21 +1075,21 @@ mod tests {
|
|||||||
let mut logs = Logs::default();
|
let mut logs = Logs::default();
|
||||||
let line = log_sanitizer::remove_ansi(input);
|
let line = log_sanitizer::remove_ansi(input);
|
||||||
|
|
||||||
logs.insert(ListItem::new(line.clone()), tz.clone());
|
logs.insert(Text::from(line.clone()), tz.clone());
|
||||||
logs.insert(ListItem::new(line.clone()), tz.clone());
|
logs.insert(Text::from(line.clone()), tz.clone());
|
||||||
logs.insert(ListItem::new(line), tz);
|
logs.insert(Text::from(line), tz);
|
||||||
|
|
||||||
assert_eq!(logs.logs.items.len(), 1);
|
assert_eq!(logs.lines.items.len(), 1);
|
||||||
|
|
||||||
let input = "2023-01-15T19:13:30.783138328Z Lorem ipsum dolor sit amet";
|
let input = "2023-01-15T19:13:30.783138328Z Lorem ipsum dolor sit amet";
|
||||||
let (tz, _) = LogsTz::splitter(input);
|
let (tz, _) = LogsTz::splitter(input);
|
||||||
let line = log_sanitizer::remove_ansi(input);
|
let line = log_sanitizer::remove_ansi(input);
|
||||||
|
|
||||||
logs.insert(ListItem::new(line.clone()), tz.clone());
|
logs.insert(Text::from(line.clone()), tz.clone());
|
||||||
logs.insert(ListItem::new(line.clone()), tz.clone());
|
logs.insert(Text::from(line.clone()), tz.clone());
|
||||||
logs.insert(ListItem::new(line), tz);
|
logs.insert(Text::from(line), tz);
|
||||||
|
|
||||||
assert_eq!(logs.logs.items.len(), 2);
|
assert_eq!(logs.lines.items.len(), 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -1008,4 +1142,73 @@ mod tests {
|
|||||||
let input = State::from(("oxker", &healthy));
|
let input = State::from(("oxker", &healthy));
|
||||||
assert_eq!(input, State::Unknown);
|
assert_eq!(input, State::Unknown);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
/// Test the format_log_line methods, should ideally check colours are being correct kept as well
|
||||||
|
fn test_to_vec() {
|
||||||
|
let mut logs = Logs::default();
|
||||||
|
|
||||||
|
let input = "2023-01-14T19:13:30.783138328Z Hello world some long line".to_owned();
|
||||||
|
let (tz, _) = LogsTz::splitter(&input);
|
||||||
|
logs.insert(Text::from(input), tz);
|
||||||
|
|
||||||
|
let input = "2023-01-14T19:13:31.783138328Z Hello world some line".to_owned();
|
||||||
|
let (tz, _) = LogsTz::splitter(&input);
|
||||||
|
logs.insert(Text::from(input), tz);
|
||||||
|
|
||||||
|
let input = "2023-01-14T19:13:32.783138328Z Hello world".to_owned();
|
||||||
|
let (tz, _) = LogsTz::splitter(&input);
|
||||||
|
logs.insert(Text::from(input), tz);
|
||||||
|
|
||||||
|
logs.offset = 43;
|
||||||
|
let result = logs.get_visible_logs(
|
||||||
|
Size {
|
||||||
|
width: 14,
|
||||||
|
height: 10,
|
||||||
|
},
|
||||||
|
10,
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
vec![
|
||||||
|
Text::from(Line::from("some long line")),
|
||||||
|
Text::from(Line::from("some line")),
|
||||||
|
Text::from(Line::default())
|
||||||
|
],
|
||||||
|
result
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
/// Test the get_scroll_title methods
|
||||||
|
fn test_scroll_title() {
|
||||||
|
let mut logs = Logs::default();
|
||||||
|
|
||||||
|
let result = logs.get_scroll_title(10);
|
||||||
|
assert!(result.is_none());
|
||||||
|
|
||||||
|
let input = "short".to_owned();
|
||||||
|
let (tz, _) = LogsTz::splitter(&input);
|
||||||
|
logs.insert(Text::from(input), tz);
|
||||||
|
|
||||||
|
let result = logs.get_scroll_title(10);
|
||||||
|
assert!(result.is_none());
|
||||||
|
|
||||||
|
let input = "2023-01-14T19:13:30.783138328Z Hello world some long line".to_owned();
|
||||||
|
let (tz, _) = LogsTz::splitter(&input);
|
||||||
|
logs.insert(Text::from(input), tz);
|
||||||
|
|
||||||
|
let result = logs.get_scroll_title(10);
|
||||||
|
assert_eq!(result, Some(" 0/51 → ".to_owned()));
|
||||||
|
|
||||||
|
logs.forward(10);
|
||||||
|
|
||||||
|
let result = logs.get_scroll_title(10);
|
||||||
|
assert_eq!(result, Some(" ← 1/51 → ".to_owned()));
|
||||||
|
|
||||||
|
for _ in 0..=49 {
|
||||||
|
logs.forward(10);
|
||||||
|
}
|
||||||
|
let result = logs.get_scroll_title(10);
|
||||||
|
assert_eq!(result, Some(" ← 51/51 ".to_owned()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+100
-51
@@ -1,7 +1,7 @@
|
|||||||
use bollard::models::ContainerSummary;
|
use bollard::models::ContainerSummary;
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use ratatui::widgets::{ListItem, ListState};
|
use ratatui::{layout::Size, text::Text, widgets::ListState};
|
||||||
use std::{
|
use std::{
|
||||||
hash::Hash,
|
hash::Hash,
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
@@ -122,7 +122,7 @@ pub struct AppData {
|
|||||||
error: Option<AppError>,
|
error: Option<AppError>,
|
||||||
filter: Filter,
|
filter: Filter,
|
||||||
hidden_containers: Vec<ContainerItem>,
|
hidden_containers: Vec<ContainerItem>,
|
||||||
redraw: Arc<Rerender>,
|
rerender: Arc<Rerender>,
|
||||||
sorted_by: Option<(Header, SortedOrder)>,
|
sorted_by: Option<(Header, SortedOrder)>,
|
||||||
current_sorted_id: Vec<ContainerId>,
|
current_sorted_id: Vec<ContainerId>,
|
||||||
pub config: Config,
|
pub config: Config,
|
||||||
@@ -137,7 +137,7 @@ pub struct AppData {
|
|||||||
pub filter: Filter,
|
pub filter: Filter,
|
||||||
pub hidden_containers: Vec<ContainerItem>,
|
pub hidden_containers: Vec<ContainerItem>,
|
||||||
pub current_sorted_id: Vec<ContainerId>,
|
pub current_sorted_id: Vec<ContainerId>,
|
||||||
pub redraw: Arc<Rerender>,
|
pub rerender: Arc<Rerender>,
|
||||||
pub sorted_by: Option<(Header, SortedOrder)>,
|
pub sorted_by: Option<(Header, SortedOrder)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -151,7 +151,7 @@ impl AppData {
|
|||||||
error: None,
|
error: None,
|
||||||
filter: Filter::new(),
|
filter: Filter::new(),
|
||||||
hidden_containers: vec![],
|
hidden_containers: vec![],
|
||||||
redraw: Arc::clone(redraw),
|
rerender: Arc::clone(redraw),
|
||||||
sorted_by: None,
|
sorted_by: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -192,7 +192,7 @@ impl AppData {
|
|||||||
/// sets the state to start if any filtering has occurred
|
/// sets the state to start if any filtering has occurred
|
||||||
/// Also search in the "hidden" vec for items and insert back into the main containers vec
|
/// Also search in the "hidden" vec for items and insert back into the main containers vec
|
||||||
fn filter_containers(&mut self) {
|
fn filter_containers(&mut self) {
|
||||||
self.redraw.update();
|
self.rerender.update_draw();
|
||||||
let pre_len = self.get_container_len();
|
let pre_len = self.get_container_len();
|
||||||
|
|
||||||
if !self.hidden_containers.is_empty() {
|
if !self.hidden_containers.is_empty() {
|
||||||
@@ -296,7 +296,7 @@ impl AppData {
|
|||||||
/// Remove the sorted header & order, and sort by default - created datetime
|
/// Remove the sorted header & order, and sort by default - created datetime
|
||||||
pub fn reset_sorted(&mut self) {
|
pub fn reset_sorted(&mut self) {
|
||||||
self.set_sorted(None);
|
self.set_sorted(None);
|
||||||
self.redraw.update();
|
self.rerender.update_draw();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sort containers based on a given header, if headings match, and already ascending, remove sorting
|
/// Sort containers based on a given header, if headings match, and already ascending, remove sorting
|
||||||
@@ -392,7 +392,7 @@ impl AppData {
|
|||||||
|
|
||||||
self.containers.items.sort_by(sort_closure);
|
self.containers.items.sort_by(sort_closure);
|
||||||
if pre_order != self.get_current_ids() {
|
if pre_order != self.get_current_ids() {
|
||||||
self.redraw.update();
|
self.rerender.update_draw();
|
||||||
}
|
}
|
||||||
} else if self.current_sorted_id != self.get_current_ids() {
|
} else if self.current_sorted_id != self.get_current_ids() {
|
||||||
self.containers.items.sort_by(|a, b| {
|
self.containers.items.sort_by(|a, b| {
|
||||||
@@ -400,20 +400,13 @@ impl AppData {
|
|||||||
.cmp(&b.created)
|
.cmp(&b.created)
|
||||||
.then_with(|| a.name.get().cmp(b.name.get()))
|
.then_with(|| a.name.get().cmp(b.name.get()))
|
||||||
});
|
});
|
||||||
self.redraw.update();
|
self.rerender.update_draw();
|
||||||
self.current_sorted_id = self.get_current_ids();
|
self.current_sorted_id = self.get_current_ids();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Container state methods
|
/// Container state methods
|
||||||
/// Get the total number of none "hidden" containers
|
/// Get the total number of none "hidden" containers
|
||||||
// TODO remove this once zigbuild uses Rust v1.87.0
|
|
||||||
#[cfg(target_os = "macos")]
|
|
||||||
pub fn get_container_len(&self) -> usize {
|
|
||||||
self.containers.items.len()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(target_os = "macos"))]
|
|
||||||
pub const fn get_container_len(&self) -> usize {
|
pub const fn get_container_len(&self) -> usize {
|
||||||
self.containers.items.len()
|
self.containers.items.len()
|
||||||
}
|
}
|
||||||
@@ -446,25 +439,25 @@ impl AppData {
|
|||||||
/// Select the first container
|
/// Select the first container
|
||||||
pub fn containers_start(&mut self) {
|
pub fn containers_start(&mut self) {
|
||||||
self.containers.start();
|
self.containers.start();
|
||||||
self.redraw.update();
|
self.rerender.update_draw();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// select the last container
|
/// select the last container
|
||||||
pub fn containers_end(&mut self) {
|
pub fn containers_end(&mut self) {
|
||||||
self.containers.end();
|
self.containers.end();
|
||||||
self.redraw.update();
|
self.rerender.update_draw();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Select the next container
|
/// Select the next container
|
||||||
pub fn containers_next(&mut self) {
|
pub fn containers_next(&mut self) {
|
||||||
self.containers.next();
|
self.containers.next();
|
||||||
self.redraw.update();
|
self.rerender.update_draw();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// select the previous container
|
/// select the previous container
|
||||||
pub fn containers_previous(&mut self) {
|
pub fn containers_previous(&mut self) {
|
||||||
self.containers.previous();
|
self.containers.previous();
|
||||||
self.redraw.update();
|
self.rerender.update_draw();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get ListState of containers
|
/// Get ListState of containers
|
||||||
@@ -586,7 +579,7 @@ impl AppData {
|
|||||||
pub fn docker_controls_next(&mut self) {
|
pub fn docker_controls_next(&mut self) {
|
||||||
if let Some(i) = self.get_mut_selected_container() {
|
if let Some(i) = self.get_mut_selected_container() {
|
||||||
i.docker_controls.next();
|
i.docker_controls.next();
|
||||||
self.redraw.update();
|
self.rerender.update_draw();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -594,7 +587,7 @@ impl AppData {
|
|||||||
pub fn docker_controls_previous(&mut self) {
|
pub fn docker_controls_previous(&mut self) {
|
||||||
if let Some(i) = self.get_mut_selected_container() {
|
if let Some(i) = self.get_mut_selected_container() {
|
||||||
i.docker_controls.previous();
|
i.docker_controls.previous();
|
||||||
self.redraw.update();
|
self.rerender.update_draw();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -602,7 +595,7 @@ impl AppData {
|
|||||||
pub fn docker_controls_start(&mut self) {
|
pub fn docker_controls_start(&mut self) {
|
||||||
if let Some(i) = self.get_mut_selected_container() {
|
if let Some(i) = self.get_mut_selected_container() {
|
||||||
i.docker_controls.start();
|
i.docker_controls.start();
|
||||||
self.redraw.update();
|
self.rerender.update_draw();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -610,7 +603,7 @@ impl AppData {
|
|||||||
pub fn docker_controls_end(&mut self) {
|
pub fn docker_controls_end(&mut self) {
|
||||||
if let Some(i) = self.get_mut_selected_container() {
|
if let Some(i) = self.get_mut_selected_container() {
|
||||||
i.docker_controls.end();
|
i.docker_controls.end();
|
||||||
self.redraw.update();
|
self.rerender.update_draw();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -644,11 +637,33 @@ impl AppData {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// If scrolling horiztonally along the logs, display a counter of the position in the in the scroll, `x/y`
|
||||||
|
pub fn get_scroll_title(&mut self, width: u16) -> Option<String> {
|
||||||
|
self.get_mut_selected_container()
|
||||||
|
.and_then(|i| i.logs.get_scroll_title(width))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Increase the logs offset, basically moving an invisible cursor back
|
||||||
|
pub fn log_back(&mut self) {
|
||||||
|
if let Some(i) = self.get_mut_selected_container() {
|
||||||
|
i.logs.back();
|
||||||
|
self.rerender.update_draw();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Increase the logs offset, basically moving an invisible cursor forward
|
||||||
|
pub fn log_forward(&mut self, width: u16) {
|
||||||
|
if let Some(i) = self.get_mut_selected_container() {
|
||||||
|
i.logs.forward(width);
|
||||||
|
self.rerender.update_draw();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// select next selected log line
|
/// select next selected log line
|
||||||
pub fn log_next(&mut self) {
|
pub fn log_next(&mut self) {
|
||||||
if let Some(i) = self.get_mut_selected_container() {
|
if let Some(i) = self.get_mut_selected_container() {
|
||||||
i.logs.next();
|
i.logs.next();
|
||||||
self.redraw.update();
|
self.rerender.update_draw();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -656,7 +671,7 @@ impl AppData {
|
|||||||
pub fn log_previous(&mut self) {
|
pub fn log_previous(&mut self) {
|
||||||
if let Some(i) = self.get_mut_selected_container() {
|
if let Some(i) = self.get_mut_selected_container() {
|
||||||
i.logs.previous();
|
i.logs.previous();
|
||||||
self.redraw.update();
|
self.rerender.update_draw();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -664,7 +679,7 @@ impl AppData {
|
|||||||
pub fn log_end(&mut self) {
|
pub fn log_end(&mut self) {
|
||||||
if let Some(i) = self.get_mut_selected_container() {
|
if let Some(i) = self.get_mut_selected_container() {
|
||||||
i.logs.end();
|
i.logs.end();
|
||||||
self.redraw.update();
|
self.rerender.update_draw();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -672,17 +687,17 @@ impl AppData {
|
|||||||
pub fn log_start(&mut self) {
|
pub fn log_start(&mut self) {
|
||||||
if let Some(i) = self.get_mut_selected_container() {
|
if let Some(i) = self.get_mut_selected_container() {
|
||||||
i.logs.start();
|
i.logs.start();
|
||||||
self.redraw.update();
|
self.rerender.update_draw();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get mutable Vec of current containers logs
|
/// Get mutable Vec of current containers logs
|
||||||
pub fn get_logs(&self, height: u16, padding: usize) -> Vec<ListItem<'static>> {
|
pub fn get_logs(&self, size: Size, padding: usize) -> Vec<Text<'static>> {
|
||||||
self.containers
|
self.containers
|
||||||
.state
|
.state
|
||||||
.selected()
|
.selected()
|
||||||
.and_then(|i| self.containers.items.get(i))
|
.and_then(|i| self.containers.items.get(i))
|
||||||
.map_or(vec![], |i| i.logs.to_vec(height.into(), padding))
|
.map_or(vec![], |i| i.logs.get_visible_logs(size, padding))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get mutable Option of the currently selected container Logs state
|
/// Get mutable Option of the currently selected container Logs state
|
||||||
@@ -713,14 +728,14 @@ impl AppData {
|
|||||||
/// Remove single app_state error
|
/// Remove single app_state error
|
||||||
pub fn remove_error(&mut self) {
|
pub fn remove_error(&mut self) {
|
||||||
self.error = None;
|
self.error = None;
|
||||||
self.redraw.update();
|
self.rerender.update_draw();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Insert single app_state error
|
/// Insert single app_state error
|
||||||
pub fn set_error(&mut self, error: AppError, gui_state: &Arc<Mutex<GuiState>>, status: Status) {
|
pub fn set_error(&mut self, error: AppError, gui_state: &Arc<Mutex<GuiState>>, status: Status) {
|
||||||
gui_state.lock().status_push(status);
|
gui_state.lock().status_push(status);
|
||||||
self.error = Some(error);
|
self.error = Some(error);
|
||||||
self.redraw.update();
|
self.rerender.update_draw();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check if the selected container is a dockerised version of oxker
|
/// Check if the selected container is a dockerised version of oxker
|
||||||
@@ -810,7 +825,7 @@ impl AppData {
|
|||||||
container.mem_limit.update(mem_limit);
|
container.mem_limit.update(mem_limit);
|
||||||
}
|
}
|
||||||
if self.is_selected_container(id) {
|
if self.is_selected_container(id) {
|
||||||
self.redraw.update();
|
self.rerender.update_draw();
|
||||||
}
|
}
|
||||||
self.sort_containers();
|
self.sort_containers();
|
||||||
}
|
}
|
||||||
@@ -848,7 +863,7 @@ impl AppData {
|
|||||||
if self.containers.items.get(index).is_some() {
|
if self.containers.items.get(index).is_some() {
|
||||||
self.containers.items.remove(index);
|
self.containers.items.remove(index);
|
||||||
if self.is_selected_container(id) {
|
if self.is_selected_container(id) {
|
||||||
self.redraw.update();
|
self.rerender.update_draw();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -881,7 +896,12 @@ impl AppData {
|
|||||||
.as_ref()
|
.as_ref()
|
||||||
.map_or(String::new(), std::clone::Clone::clone),
|
.map_or(String::new(), std::clone::Clone::clone),
|
||||||
);
|
);
|
||||||
let state = State::from((i.state.as_ref().map_or("dead", |z| z), &status));
|
let state = State::from((
|
||||||
|
i.state
|
||||||
|
.as_ref()
|
||||||
|
.map_or(&bollard::secret::ContainerSummaryStateEnum::DEAD, |z| z),
|
||||||
|
&status,
|
||||||
|
));
|
||||||
let image = i
|
let image = i
|
||||||
.image
|
.image
|
||||||
.as_ref()
|
.as_ref()
|
||||||
@@ -965,7 +985,7 @@ impl AppData {
|
|||||||
} else {
|
} else {
|
||||||
log_sanitizer::remove_ansi(&i)
|
log_sanitizer::remove_ansi(&i)
|
||||||
};
|
};
|
||||||
container.logs.insert(ListItem::new(lines), log_tz);
|
container.logs.insert(Text::from(lines), log_tz);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the logs selected row for each container
|
// Set the logs selected row for each container
|
||||||
@@ -977,7 +997,7 @@ impl AppData {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if self.is_selected_container(id) {
|
if self.is_selected_container(id) {
|
||||||
self.redraw.update();
|
self.rerender.update_draw();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1945,14 +1965,19 @@ mod tests {
|
|||||||
let logs = (1..=3).map(|i| format!("{i} {i}")).collect::<Vec<_>>();
|
let logs = (1..=3).map(|i| format!("{i} {i}")).collect::<Vec<_>>();
|
||||||
|
|
||||||
app_data.update_log_by_id(logs, &ids[0]);
|
app_data.update_log_by_id(logs, &ids[0]);
|
||||||
// app_data.log_start();
|
|
||||||
|
|
||||||
let result = app_data.get_log_state();
|
let result = app_data.get_log_state();
|
||||||
assert!(result.is_some());
|
assert!(result.is_some());
|
||||||
assert_eq!(result.as_ref().unwrap().selected(), Some(2));
|
assert_eq!(result.as_ref().unwrap().selected(), Some(2));
|
||||||
assert_eq!(result.unwrap().offset(), 0);
|
assert_eq!(result.unwrap().offset(), 0);
|
||||||
|
|
||||||
let result = app_data.get_logs(4, 1);
|
let result = app_data.get_logs(
|
||||||
|
Size {
|
||||||
|
width: 20,
|
||||||
|
height: 4,
|
||||||
|
},
|
||||||
|
1,
|
||||||
|
);
|
||||||
assert_eq!(result.len(), 3);
|
assert_eq!(result.len(), 3);
|
||||||
|
|
||||||
let result = app_data.get_log_title();
|
let result = app_data.get_log_title();
|
||||||
@@ -2340,44 +2365,68 @@ mod tests {
|
|||||||
|
|
||||||
app_data.update_log_by_id(logs, &ids[0]);
|
app_data.update_log_by_id(logs, &ids[0]);
|
||||||
|
|
||||||
let result = app_data.get_logs(10, 10);
|
let result = app_data.get_logs(
|
||||||
|
Size {
|
||||||
|
width: 20,
|
||||||
|
height: 10,
|
||||||
|
},
|
||||||
|
10,
|
||||||
|
);
|
||||||
for (index, item) in result.iter().enumerate() {
|
for (index, item) in result.iter().enumerate() {
|
||||||
if index < 979 {
|
if index < 979 {
|
||||||
assert_eq!(item, &ListItem::new(""));
|
assert_eq!(item, &Text::from(""));
|
||||||
} else {
|
} else {
|
||||||
assert_eq!(item, &ListItem::new(format!("{index}")));
|
assert_eq!(item, &Text::from(format!("{index}")));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let result = app_data.get_logs(100, 20);
|
let result = app_data.get_logs(
|
||||||
|
Size {
|
||||||
|
width: 20,
|
||||||
|
height: 100,
|
||||||
|
},
|
||||||
|
20,
|
||||||
|
);
|
||||||
for (index, item) in result.iter().enumerate() {
|
for (index, item) in result.iter().enumerate() {
|
||||||
if index < 879 {
|
if index < 879 {
|
||||||
assert_eq!(item, &ListItem::new(""));
|
assert_eq!(item, &Text::from(""));
|
||||||
} else {
|
} else {
|
||||||
assert_eq!(item, &ListItem::new(format!("{index}")));
|
assert_eq!(item, &Text::from(format!("{index}")));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
app_data.log_start();
|
app_data.log_start();
|
||||||
let result = app_data.get_logs(10, 10);
|
|
||||||
|
let result = app_data.get_logs(
|
||||||
|
Size {
|
||||||
|
width: 20,
|
||||||
|
height: 10,
|
||||||
|
},
|
||||||
|
10,
|
||||||
|
);
|
||||||
for (index, item) in result.iter().enumerate() {
|
for (index, item) in result.iter().enumerate() {
|
||||||
if index > 20 {
|
if index > 20 {
|
||||||
assert_eq!(item, &ListItem::new(""));
|
assert_eq!(item, &Text::from(""));
|
||||||
} else {
|
} else {
|
||||||
assert_eq!(item, &ListItem::new(format!("{index}")));
|
assert_eq!(item, &Text::from(format!("{index}")));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _ in 0..=500 {
|
for _ in 0..=500 {
|
||||||
app_data.log_next();
|
app_data.log_next();
|
||||||
}
|
}
|
||||||
|
let result = app_data.get_logs(
|
||||||
let result = app_data.get_logs(10, 10);
|
Size {
|
||||||
|
width: 20,
|
||||||
|
height: 10,
|
||||||
|
},
|
||||||
|
10,
|
||||||
|
);
|
||||||
for (index, item) in result.iter().enumerate() {
|
for (index, item) in result.iter().enumerate() {
|
||||||
if (481..=521).contains(&index) {
|
if (481..=521).contains(&index) {
|
||||||
assert_eq!(item, &ListItem::new(format!("{index}")));
|
assert_eq!(item, &Text::from(format!("{index}")));
|
||||||
} else {
|
} else {
|
||||||
assert_eq!(item, &ListItem::new(""));
|
assert_eq!(item, &Text::from(""));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,6 +56,9 @@ show_logs = true
|
|||||||
# 4) backspace, tab, backtab, delete, end, esc, home, insert, pagedown, pageup, left, right, up, down
|
# 4) backspace, tab, backtab, delete, end, esc, home, insert, pagedown, pageup, left, right, up, down
|
||||||
|
|
||||||
# Each definition can have two keys associated with it
|
# Each definition can have two keys associated with it
|
||||||
|
|
||||||
|
# WARNING "scroll_many" only accepts control, alt, shift, with no secondary option
|
||||||
|
|
||||||
# If any key clashes are found, oxker will revert to it's default keymap
|
# If any key clashes are found, oxker will revert to it's default keymap
|
||||||
|
|
||||||
[keymap]
|
[keymap]
|
||||||
@@ -73,18 +76,28 @@ filter_mode = ["/", "F1"]
|
|||||||
quit = ["q"]
|
quit = ["q"]
|
||||||
# Save logs of selected container to file on disk
|
# Save logs of selected container to file on disk
|
||||||
save_logs = ["s"]
|
save_logs = ["s"]
|
||||||
|
# TODO "scroll_down_many" will be removed in the next release
|
||||||
# scroll down a list by many
|
# scroll down a list by many
|
||||||
scroll_down_many = ["pagedown"]
|
scroll_down_many = ["pagedown"]
|
||||||
|
# TODO rename in next release
|
||||||
# scroll down a list by one item
|
# scroll down a list by one item
|
||||||
scroll_down_one = ["down", "j"]
|
scroll_down_one = ["down", "j"]
|
||||||
|
|
||||||
# scroll down to the end of a list
|
# scroll down to the end of a list
|
||||||
scroll_end = ["end"]
|
scroll_end = ["end"]
|
||||||
|
# Modifier to scroll by 10 lines isntead of one, used in conjunction with scroll_up_x/scroll_down_x
|
||||||
|
scroll_many = ["control"]
|
||||||
# scroll up to the start of a list
|
# scroll up to the start of a list
|
||||||
scroll_start = ["home"]
|
scroll_start = ["home"]
|
||||||
|
# TODO "scroll_up_many" will be removed in the next release
|
||||||
# scroll up a list by many
|
# scroll up a list by many
|
||||||
scroll_up_many = ["pageup"]
|
scroll_up_many = ["pageup"]
|
||||||
|
# TODO rename in next release
|
||||||
# scroll up a list by one item
|
# scroll up a list by one item
|
||||||
scroll_up_one = ["up", "k"]
|
scroll_up_one = ["up", "k"]
|
||||||
|
# Horizontal scroll of the logs
|
||||||
|
log_scroll_forward = ["right"]
|
||||||
|
log_scroll_back = ["left"]
|
||||||
# Select next panel
|
# Select next panel
|
||||||
select_next_panel = ["tab"]
|
select_next_panel = ["tab"]
|
||||||
# Select previous panel
|
# Select previous panel
|
||||||
@@ -110,6 +123,8 @@ log_section_height_decrease = ["-"]
|
|||||||
log_section_height_increase = ["+"]
|
log_section_height_increase = ["+"]
|
||||||
# Toggle visibility of the log section
|
# Toggle visibility of the log section
|
||||||
log_section_toggle = ["\\"]
|
log_section_toggle = ["\\"]
|
||||||
|
# Force a complete clear & redraw of the screen
|
||||||
|
force_redraw = ["f"]
|
||||||
|
|
||||||
#################
|
#################
|
||||||
# Custom Colors #
|
# Custom Colors #
|
||||||
|
|||||||
+124
-64
@@ -1,6 +1,6 @@
|
|||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
|
||||||
use crossterm::event::KeyCode;
|
use crossterm::event::{KeyCode, KeyModifiers};
|
||||||
|
|
||||||
/// The macro accepts a list of struct names with key names
|
/// The macro accepts a list of struct names with key names
|
||||||
/// Returns a struct where every key name is an Option<String>, with the correct derived attributes
|
/// Returns a struct where every key name is an Option<String>, with the correct derived attributes
|
||||||
@@ -12,6 +12,7 @@ macro_rules! optional_config_struct {
|
|||||||
$(
|
$(
|
||||||
$key_name: Option<Vec<String>>,
|
$key_name: Option<Vec<String>>,
|
||||||
)*
|
)*
|
||||||
|
pub scroll_many: Option<Vec<String>>,
|
||||||
}
|
}
|
||||||
)*
|
)*
|
||||||
};
|
};
|
||||||
@@ -24,9 +25,10 @@ macro_rules! config_struct {
|
|||||||
$(
|
$(
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct $struct_name {
|
pub struct $struct_name {
|
||||||
$(
|
$(
|
||||||
pub $key_name: (KeyCode, Option<KeyCode>),
|
pub $key_name: (KeyCode, Option<KeyCode>),
|
||||||
)*
|
)*
|
||||||
|
pub scroll_many: KeyModifiers,
|
||||||
}
|
}
|
||||||
)*
|
)*
|
||||||
};
|
};
|
||||||
@@ -35,6 +37,7 @@ macro_rules! config_struct {
|
|||||||
optional_config_struct!(
|
optional_config_struct!(
|
||||||
ConfigKeymap,
|
ConfigKeymap,
|
||||||
clear,
|
clear,
|
||||||
|
force_redraw,
|
||||||
delete_deny,
|
delete_deny,
|
||||||
delete_confirm,
|
delete_confirm,
|
||||||
exec,
|
exec,
|
||||||
@@ -42,13 +45,19 @@ optional_config_struct!(
|
|||||||
log_section_height_increase,
|
log_section_height_increase,
|
||||||
log_section_height_decrease,
|
log_section_height_decrease,
|
||||||
log_section_toggle,
|
log_section_toggle,
|
||||||
|
log_scroll_forward,
|
||||||
|
log_scroll_back,
|
||||||
quit,
|
quit,
|
||||||
save_logs,
|
save_logs,
|
||||||
|
// TODO remove in next release
|
||||||
scroll_down_many,
|
scroll_down_many,
|
||||||
|
// TODO rename in next release
|
||||||
scroll_down_one,
|
scroll_down_one,
|
||||||
scroll_end,
|
scroll_end,
|
||||||
scroll_start,
|
scroll_start,
|
||||||
|
// TODO remove in next release
|
||||||
scroll_up_many,
|
scroll_up_many,
|
||||||
|
// TODO rename in next release
|
||||||
scroll_up_one,
|
scroll_up_one,
|
||||||
select_next_panel,
|
select_next_panel,
|
||||||
select_previous_panel,
|
select_previous_panel,
|
||||||
@@ -73,16 +82,23 @@ config_struct!(
|
|||||||
delete_confirm,
|
delete_confirm,
|
||||||
exec,
|
exec,
|
||||||
filter_mode,
|
filter_mode,
|
||||||
|
force_redraw,
|
||||||
log_section_height_increase,
|
log_section_height_increase,
|
||||||
log_section_height_decrease,
|
log_section_height_decrease,
|
||||||
log_section_toggle,
|
log_section_toggle,
|
||||||
|
log_scroll_forward,
|
||||||
|
log_scroll_back,
|
||||||
quit,
|
quit,
|
||||||
save_logs,
|
save_logs,
|
||||||
|
// TODO remove in next release
|
||||||
scroll_down_many,
|
scroll_down_many,
|
||||||
|
// TODO rename in next release
|
||||||
scroll_down_one,
|
scroll_down_one,
|
||||||
scroll_end,
|
scroll_end,
|
||||||
scroll_start,
|
scroll_start,
|
||||||
|
// TODO remove in next release
|
||||||
scroll_up_many,
|
scroll_up_many,
|
||||||
|
// TODO rename in next release
|
||||||
scroll_up_one,
|
scroll_up_one,
|
||||||
select_next_panel,
|
select_next_panel,
|
||||||
select_previous_panel,
|
select_previous_panel,
|
||||||
@@ -108,16 +124,24 @@ impl Keymap {
|
|||||||
delete_deny: (KeyCode::Char('n'), None),
|
delete_deny: (KeyCode::Char('n'), None),
|
||||||
exec: (KeyCode::Char('e'), None),
|
exec: (KeyCode::Char('e'), None),
|
||||||
filter_mode: (KeyCode::Char('/'), Some(KeyCode::F(1))),
|
filter_mode: (KeyCode::Char('/'), Some(KeyCode::F(1))),
|
||||||
|
force_redraw: (KeyCode::Char('f'), None),
|
||||||
log_section_height_decrease: (KeyCode::Char('-'), None),
|
log_section_height_decrease: (KeyCode::Char('-'), None),
|
||||||
log_section_height_increase: (KeyCode::Char('='), None),
|
log_section_height_increase: (KeyCode::Char('='), None),
|
||||||
log_section_toggle: (KeyCode::Char('\\'), None),
|
log_section_toggle: (KeyCode::Char('\\'), None),
|
||||||
|
log_scroll_back: (KeyCode::Left, None),
|
||||||
|
log_scroll_forward: (KeyCode::Right, None),
|
||||||
quit: (KeyCode::Char('q'), None),
|
quit: (KeyCode::Char('q'), None),
|
||||||
save_logs: (KeyCode::Char('s'), None),
|
save_logs: (KeyCode::Char('s'), None),
|
||||||
|
// TODO remove in next release
|
||||||
scroll_down_many: (KeyCode::PageDown, None),
|
scroll_down_many: (KeyCode::PageDown, None),
|
||||||
|
// TODO rename in next release
|
||||||
scroll_down_one: (KeyCode::Down, Some(KeyCode::Char('j'))),
|
scroll_down_one: (KeyCode::Down, Some(KeyCode::Char('j'))),
|
||||||
scroll_end: (KeyCode::End, None),
|
scroll_end: (KeyCode::End, None),
|
||||||
scroll_start: (KeyCode::Home, None),
|
scroll_start: (KeyCode::Home, None),
|
||||||
|
scroll_many: KeyModifiers::CONTROL,
|
||||||
|
// TODO remove in next release
|
||||||
scroll_up_many: (KeyCode::PageUp, None),
|
scroll_up_many: (KeyCode::PageUp, None),
|
||||||
|
// TODO rename in next release
|
||||||
scroll_up_one: (KeyCode::Up, Some(KeyCode::Char('k'))),
|
scroll_up_one: (KeyCode::Up, Some(KeyCode::Char('k'))),
|
||||||
select_next_panel: (KeyCode::Tab, None),
|
select_next_panel: (KeyCode::Tab, None),
|
||||||
select_previous_panel: (KeyCode::BackTab, None),
|
select_previous_panel: (KeyCode::BackTab, None),
|
||||||
@@ -189,6 +213,7 @@ impl From<Option<ConfigKeymap>> for Keymap {
|
|||||||
|
|
||||||
update_keymap(ck.exec, &mut keymap.exec, &mut clash);
|
update_keymap(ck.exec, &mut keymap.exec, &mut clash);
|
||||||
update_keymap(ck.filter_mode, &mut keymap.filter_mode, &mut clash);
|
update_keymap(ck.filter_mode, &mut keymap.filter_mode, &mut clash);
|
||||||
|
update_keymap(ck.force_redraw, &mut keymap.force_redraw, &mut clash);
|
||||||
update_keymap(ck.quit, &mut keymap.quit, &mut clash);
|
update_keymap(ck.quit, &mut keymap.quit, &mut clash);
|
||||||
update_keymap(ck.save_logs, &mut keymap.save_logs, &mut clash);
|
update_keymap(ck.save_logs, &mut keymap.save_logs, &mut clash);
|
||||||
update_keymap(
|
update_keymap(
|
||||||
@@ -201,6 +226,12 @@ impl From<Option<ConfigKeymap>> for Keymap {
|
|||||||
update_keymap(ck.scroll_start, &mut keymap.scroll_start, &mut clash);
|
update_keymap(ck.scroll_start, &mut keymap.scroll_start, &mut clash);
|
||||||
update_keymap(ck.scroll_up_many, &mut keymap.scroll_up_many, &mut clash);
|
update_keymap(ck.scroll_up_many, &mut keymap.scroll_up_many, &mut clash);
|
||||||
update_keymap(ck.scroll_up_one, &mut keymap.scroll_up_one, &mut clash);
|
update_keymap(ck.scroll_up_one, &mut keymap.scroll_up_one, &mut clash);
|
||||||
|
update_keymap(
|
||||||
|
ck.log_scroll_forward,
|
||||||
|
&mut keymap.log_scroll_forward,
|
||||||
|
&mut clash,
|
||||||
|
);
|
||||||
|
update_keymap(ck.log_scroll_back, &mut keymap.log_scroll_back, &mut clash);
|
||||||
update_keymap(
|
update_keymap(
|
||||||
ck.select_next_panel,
|
ck.select_next_panel,
|
||||||
&mut keymap.select_next_panel,
|
&mut keymap.select_next_panel,
|
||||||
@@ -227,6 +258,10 @@ impl From<Option<ConfigKeymap>> for Keymap {
|
|||||||
&mut keymap.toggle_mouse_capture,
|
&mut keymap.toggle_mouse_capture,
|
||||||
&mut clash,
|
&mut clash,
|
||||||
);
|
);
|
||||||
|
// TODO need to check for clashes when using additional modifiers
|
||||||
|
if let Some(scroll_many) = Self::try_parse_modifier(ck.scroll_many) {
|
||||||
|
keymap.scroll_many = scroll_many;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// A very basic clash check, every key has been inserted into a hashset, and a counter has been increased
|
// A very basic clash check, every key has been inserted into a hashset, and a counter has been increased
|
||||||
// if the counter and hashet length don't match, then there's a clash, and we just return the default keymap
|
// if the counter and hashet length don't match, then there's a clash, and we just return the default keymap
|
||||||
@@ -239,6 +274,20 @@ impl From<Option<ConfigKeymap>> for Keymap {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Keymap {
|
impl Keymap {
|
||||||
|
// Allowable key modifiers are only `shift`, `control`, `alt`
|
||||||
|
fn try_parse_modifier(input: Option<Vec<String>>) -> Option<KeyModifiers> {
|
||||||
|
input.and_then(|input| {
|
||||||
|
input
|
||||||
|
.first()
|
||||||
|
.and_then(|input| match input.to_lowercase().trim() {
|
||||||
|
"control" => Some(KeyModifiers::CONTROL),
|
||||||
|
"alt" => Some(KeyModifiers::ALT),
|
||||||
|
"shift" => Some(KeyModifiers::SHIFT),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/// Try to parse a &[String] into a Vec of keycodes, at most the output will have 2 entries
|
/// Try to parse a &[String] into a Vec of keycodes, at most the output will have 2 entries
|
||||||
/// This might fail on MacOS due to Backspace and Delete working in a different manner as to how they work on Linux & Windows
|
/// This might fail on MacOS due to Backspace and Delete working in a different manner as to how they work on Linux & Windows
|
||||||
/// I think that on MacOS `Del` becomes `Fwd Del`, and `Backspace` becomes `Delete`
|
/// I think that on MacOS `Del` becomes `Fwd Del`, and `Backspace` becomes `Delete`
|
||||||
@@ -310,7 +359,7 @@ impl Keymap {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[allow(clippy::unwrap_used)]
|
#[allow(clippy::unwrap_used)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crossterm::event::KeyCode;
|
use crossterm::event::{KeyCode, KeyModifiers};
|
||||||
|
|
||||||
use crate::config::keymap_parser::ConfigKeymap;
|
use crate::config::keymap_parser::ConfigKeymap;
|
||||||
|
|
||||||
@@ -364,28 +413,32 @@ mod tests {
|
|||||||
delete_deny: Some(vec!["s".to_owned()]),
|
delete_deny: Some(vec!["s".to_owned()]),
|
||||||
delete_confirm: None,
|
delete_confirm: None,
|
||||||
exec: None,
|
exec: None,
|
||||||
|
filter_mode: None,
|
||||||
|
force_redraw: None,
|
||||||
|
log_scroll_back: None,
|
||||||
|
log_scroll_forward: None,
|
||||||
log_section_height_decrease: None,
|
log_section_height_decrease: None,
|
||||||
log_section_height_increase: None,
|
log_section_height_increase: None,
|
||||||
filter_mode: None,
|
log_section_toggle: None,
|
||||||
quit: None,
|
quit: None,
|
||||||
save_logs: None,
|
save_logs: None,
|
||||||
scroll_down_many: None,
|
scroll_down_many: None,
|
||||||
scroll_down_one: None,
|
scroll_down_one: None,
|
||||||
scroll_end: None,
|
scroll_end: None,
|
||||||
scroll_start: None,
|
scroll_start: None,
|
||||||
|
scroll_many: None,
|
||||||
scroll_up_many: None,
|
scroll_up_many: None,
|
||||||
scroll_up_one: None,
|
scroll_up_one: None,
|
||||||
select_next_panel: None,
|
select_next_panel: None,
|
||||||
log_section_toggle: None,
|
|
||||||
select_previous_panel: None,
|
select_previous_panel: None,
|
||||||
sort_by_name: None,
|
|
||||||
sort_by_state: None,
|
|
||||||
sort_by_status: None,
|
|
||||||
sort_by_cpu: None,
|
sort_by_cpu: None,
|
||||||
sort_by_memory: None,
|
|
||||||
sort_by_id: None,
|
sort_by_id: None,
|
||||||
sort_by_image: None,
|
sort_by_image: None,
|
||||||
|
sort_by_memory: None,
|
||||||
|
sort_by_name: None,
|
||||||
sort_by_rx: None,
|
sort_by_rx: None,
|
||||||
|
sort_by_state: None,
|
||||||
|
sort_by_status: None,
|
||||||
sort_by_tx: None,
|
sort_by_tx: None,
|
||||||
sort_reset: None,
|
sort_reset: None,
|
||||||
toggle_help: None,
|
toggle_help: None,
|
||||||
@@ -404,72 +457,79 @@ mod tests {
|
|||||||
|
|
||||||
let input = ConfigKeymap {
|
let input = ConfigKeymap {
|
||||||
clear: gen_v(("a", "b")),
|
clear: gen_v(("a", "b")),
|
||||||
delete_confirm: gen_v(("e", "f")),
|
delete_confirm: gen_v(("c", "d")),
|
||||||
delete_deny: gen_v(("c", "d")),
|
delete_deny: gen_v(("e", "fd")),
|
||||||
exec: gen_v(("g", "h")),
|
exec: gen_v(("g", "h")),
|
||||||
filter_mode: gen_v(("i", "j")),
|
filter_mode: gen_v(("i", "j")),
|
||||||
log_section_height_decrease: gen_v(("-", "Z")),
|
force_redraw: gen_v(("k", "l")),
|
||||||
log_section_height_increase: gen_v(("=", "X")),
|
log_section_height_decrease: gen_v(("m", "n")),
|
||||||
log_section_toggle: gen_v(("Y", "W")),
|
log_section_height_increase: gen_v(("o", "p")),
|
||||||
quit: gen_v(("k", "l")),
|
log_scroll_forward: gen_v(("q", "r")),
|
||||||
save_logs: gen_v(("m", "n")),
|
log_scroll_back: gen_v(("s", "t")),
|
||||||
scroll_down_many: gen_v(("o", "p")),
|
log_section_toggle: gen_v(("u", "v")),
|
||||||
scroll_down_one: gen_v(("q", "r")),
|
quit: gen_v(("w", "x")),
|
||||||
scroll_end: gen_v(("s", "t")),
|
save_logs: gen_v(("y", "z")),
|
||||||
scroll_start: gen_v(("u", "v")),
|
scroll_down_many: gen_v(("1", "2")),
|
||||||
scroll_up_many: gen_v(("w", "x")),
|
scroll_down_one: gen_v(("3", "4")),
|
||||||
scroll_up_one: gen_v(("y", "z")),
|
scroll_end: gen_v(("5", "6")),
|
||||||
select_next_panel: gen_v(("0", "1")),
|
scroll_many: Some(vec!["alt".to_owned()]),
|
||||||
select_previous_panel: gen_v(("2", "3")),
|
scroll_start: gen_v(("7", "8")),
|
||||||
sort_by_cpu: gen_v(("F1", "F12")),
|
scroll_up_many: gen_v(("9", "0")),
|
||||||
sort_by_id: gen_v(("[", "]")),
|
scroll_up_one: gen_v(("F1", "F2")),
|
||||||
sort_by_image: gen_v(("A", "B")),
|
select_next_panel: gen_v(("F3", "F4")),
|
||||||
sort_by_memory: gen_v(("/", "\\")),
|
select_previous_panel: gen_v(("F5", "F6")),
|
||||||
sort_by_name: gen_v(("4", "5")),
|
sort_by_cpu: gen_v(("F7", "F8")),
|
||||||
sort_by_rx: gen_v(("C", "D")),
|
sort_by_id: gen_v(("F9", "F10")),
|
||||||
sort_by_state: gen_v(("6", "7")),
|
sort_by_image: gen_v(("F11", "F12")),
|
||||||
sort_by_status: gen_v(("8", "9")),
|
sort_by_memory: gen_v(("HOME", "END")),
|
||||||
sort_by_tx: gen_v(("insert", "TAB")),
|
sort_by_name: gen_v(("UP", "DOWN")),
|
||||||
sort_reset: gen_v(("up", "down")),
|
sort_by_rx: gen_v(("LEFT", "RIGHT")),
|
||||||
toggle_help: gen_v(("home", "end")),
|
sort_by_state: gen_v(("[", "]")),
|
||||||
toggle_mouse_capture: gen_v(("pagedown", "PAGEUP")),
|
sort_by_status: gen_v(("INSERTt", "TAB")),
|
||||||
|
sort_by_tx: gen_v(("PAGEDOWN", "PAGEUP")),
|
||||||
|
sort_reset: gen_v((",", ".")),
|
||||||
|
toggle_help: gen_v(("-", "=")),
|
||||||
|
toggle_mouse_capture: gen_v(("\\", "/")),
|
||||||
};
|
};
|
||||||
|
|
||||||
let result = Keymap::from(Some(input));
|
let result = Keymap::from(Some(input));
|
||||||
|
|
||||||
let expected = Keymap {
|
let expected = Keymap {
|
||||||
clear: (KeyCode::Char('a'), Some(KeyCode::Char('b'))),
|
clear: (KeyCode::Char('a'), Some(KeyCode::Char('b'))),
|
||||||
delete_deny: (KeyCode::Char('c'), Some(KeyCode::Char('d'))),
|
delete_deny: (KeyCode::Char('e'), None),
|
||||||
delete_confirm: (KeyCode::Char('e'), Some(KeyCode::Char('f'))),
|
delete_confirm: (KeyCode::Char('c'), Some(KeyCode::Char('d'))),
|
||||||
log_section_height_decrease: (KeyCode::Char('-'), Some(KeyCode::Char('Z'))),
|
|
||||||
log_section_height_increase: (KeyCode::Char('='), Some(KeyCode::Char('X'))),
|
|
||||||
log_section_toggle: (KeyCode::Char('Y'), Some(KeyCode::Char('W'))),
|
|
||||||
exec: (KeyCode::Char('g'), Some(KeyCode::Char('h'))),
|
exec: (KeyCode::Char('g'), Some(KeyCode::Char('h'))),
|
||||||
filter_mode: (KeyCode::Char('i'), Some(KeyCode::Char('j'))),
|
filter_mode: (KeyCode::Char('i'), Some(KeyCode::Char('j'))),
|
||||||
quit: (KeyCode::Char('k'), Some(KeyCode::Char('l'))),
|
force_redraw: (KeyCode::Char('k'), Some(KeyCode::Char('l'))),
|
||||||
save_logs: (KeyCode::Char('m'), Some(KeyCode::Char('n'))),
|
log_section_height_increase: (KeyCode::Char('o'), Some(KeyCode::Char('p'))),
|
||||||
scroll_down_many: (KeyCode::Char('o'), Some(KeyCode::Char('p'))),
|
log_section_height_decrease: (KeyCode::Char('m'), Some(KeyCode::Char('n'))),
|
||||||
scroll_down_one: (KeyCode::Char('q'), Some(KeyCode::Char('r'))),
|
log_section_toggle: (KeyCode::Char('u'), Some(KeyCode::Char('v'))),
|
||||||
scroll_end: (KeyCode::Char('s'), Some(KeyCode::Char('t'))),
|
log_scroll_forward: (KeyCode::Char('q'), Some(KeyCode::Char('r'))),
|
||||||
scroll_start: (KeyCode::Char('u'), Some(KeyCode::Char('v'))),
|
log_scroll_back: (KeyCode::Char('s'), Some(KeyCode::Char('t'))),
|
||||||
scroll_up_many: (KeyCode::Char('w'), Some(KeyCode::Char('x'))),
|
quit: (KeyCode::Char('w'), Some(KeyCode::Char('x'))),
|
||||||
scroll_up_one: (KeyCode::Char('y'), Some(KeyCode::Char('z'))),
|
save_logs: (KeyCode::Char('y'), Some(KeyCode::Char('z'))),
|
||||||
select_next_panel: (KeyCode::Char('0'), Some(KeyCode::Char('1'))),
|
scroll_down_many: (KeyCode::Char('1'), Some(KeyCode::Char('2'))),
|
||||||
select_previous_panel: (KeyCode::Char('2'), Some(KeyCode::Char('3'))),
|
scroll_down_one: (KeyCode::Char('3'), Some(KeyCode::Char('4'))),
|
||||||
sort_by_name: (KeyCode::Char('4'), Some(KeyCode::Char('5'))),
|
scroll_end: (KeyCode::Char('5'), Some(KeyCode::Char('6'))),
|
||||||
sort_by_state: (KeyCode::Char('6'), Some(KeyCode::Char('7'))),
|
scroll_start: (KeyCode::Char('7'), Some(KeyCode::Char('8'))),
|
||||||
sort_by_status: (KeyCode::Char('8'), Some(KeyCode::Char('9'))),
|
scroll_up_many: (KeyCode::Char('9'), Some(KeyCode::Char('0'))),
|
||||||
sort_by_cpu: (KeyCode::F(1), Some(KeyCode::F(12))),
|
scroll_up_one: (KeyCode::F(1), Some(KeyCode::F(2))),
|
||||||
sort_by_memory: (KeyCode::Char('/'), Some(KeyCode::Char('\\'))),
|
select_next_panel: (KeyCode::F(3), Some(KeyCode::F(4))),
|
||||||
sort_by_id: (KeyCode::Char('['), Some(KeyCode::Char(']'))),
|
select_previous_panel: (KeyCode::F(5), Some(KeyCode::F(6))),
|
||||||
sort_by_image: (KeyCode::Char('A'), Some(KeyCode::Char('B'))),
|
sort_by_name: (KeyCode::Up, Some(KeyCode::Down)),
|
||||||
sort_by_rx: (KeyCode::Char('C'), Some(KeyCode::Char('D'))),
|
sort_by_state: (KeyCode::Char('['), Some(KeyCode::Char(']'))),
|
||||||
sort_by_tx: (KeyCode::Insert, Some(KeyCode::Tab)),
|
sort_by_status: (KeyCode::Tab, None),
|
||||||
sort_reset: (KeyCode::Up, Some(KeyCode::Down)),
|
sort_by_cpu: (KeyCode::F(7), Some(KeyCode::F(8))),
|
||||||
toggle_help: (KeyCode::Home, Some(KeyCode::End)),
|
sort_by_memory: (KeyCode::Home, Some(KeyCode::End)),
|
||||||
toggle_mouse_capture: (KeyCode::PageDown, Some(KeyCode::PageUp)),
|
sort_by_id: (KeyCode::F(9), Some(KeyCode::F(10))),
|
||||||
|
sort_by_image: (KeyCode::F(11), Some(KeyCode::F(12))),
|
||||||
|
sort_by_rx: (KeyCode::Left, Some(KeyCode::Right)),
|
||||||
|
sort_by_tx: (KeyCode::PageDown, Some(KeyCode::PageUp)),
|
||||||
|
sort_reset: (KeyCode::Char(','), Some(KeyCode::Char('.'))),
|
||||||
|
toggle_help: (KeyCode::Char('-'), Some(KeyCode::Char('='))),
|
||||||
|
toggle_mouse_capture: (KeyCode::Char('\\'), Some(KeyCode::Char('/'))),
|
||||||
|
scroll_many: KeyModifiers::ALT,
|
||||||
};
|
};
|
||||||
|
|
||||||
assert_eq!(expected, result);
|
assert_eq!(expected, result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+182
-243
@@ -1,9 +1,10 @@
|
|||||||
use bollard::{
|
use bollard::{
|
||||||
Docker,
|
Docker,
|
||||||
container::{
|
query_parameters::{
|
||||||
ListContainersOptions, LogsOptions, MemoryStatsStats, RemoveContainerOptions,
|
ListContainersOptions, LogsOptions, RemoveContainerOptions, RestartContainerOptions,
|
||||||
StartContainerOptions, Stats, StatsOptions,
|
StartContainerOptions, StatsOptions, StopContainerOptions,
|
||||||
},
|
},
|
||||||
|
secret::ContainerStatsResponse,
|
||||||
service::ContainerSummary,
|
service::ContainerSummary,
|
||||||
};
|
};
|
||||||
use futures_util::StreamExt;
|
use futures_util::StreamExt;
|
||||||
@@ -75,31 +76,44 @@ pub struct DockerData {
|
|||||||
impl DockerData {
|
impl DockerData {
|
||||||
/// Use docker stats to calculate current cpu usage
|
/// Use docker stats to calculate current cpu usage
|
||||||
#[allow(clippy::cast_precision_loss)]
|
#[allow(clippy::cast_precision_loss)]
|
||||||
fn calculate_usage(stats: &Stats) -> f64 {
|
fn calculate_usage(stats: &ContainerStatsResponse) -> f64 {
|
||||||
let mut cpu_percentage = 0.0;
|
let mut cpu_percentage = 0.0;
|
||||||
let cpu_delta = stats
|
|
||||||
.cpu_stats
|
|
||||||
.cpu_usage
|
|
||||||
.total_usage
|
|
||||||
.saturating_sub(stats.precpu_stats.cpu_usage.total_usage)
|
|
||||||
as f64;
|
|
||||||
|
|
||||||
if let (Some(cpu_stats_usage), Some(precpu_stats_usage)) = (
|
let total_usage = stats.precpu_stats.as_ref().map_or(0, |i| {
|
||||||
stats.cpu_stats.system_cpu_usage,
|
i.cpu_usage
|
||||||
stats.precpu_stats.system_cpu_usage,
|
.as_ref()
|
||||||
|
.map_or(0, |i| i.total_usage.unwrap_or_default())
|
||||||
|
});
|
||||||
|
|
||||||
|
let cpu_delta = stats.cpu_stats.as_ref().map_or(0, |i| {
|
||||||
|
i.cpu_usage.as_ref().map_or(0, |i| {
|
||||||
|
i.total_usage
|
||||||
|
.unwrap_or_default()
|
||||||
|
.saturating_sub(total_usage)
|
||||||
|
})
|
||||||
|
}) as f64;
|
||||||
|
|
||||||
|
if let (Some(Some(cpu_stats_usage)), Some(Some(precpu_stats_usage))) = (
|
||||||
|
stats.cpu_stats.as_ref().map(|i| i.system_cpu_usage),
|
||||||
|
stats.precpu_stats.as_ref().map(|i| i.system_cpu_usage),
|
||||||
) {
|
) {
|
||||||
let system_delta = cpu_stats_usage.saturating_sub(precpu_stats_usage) as f64;
|
let system_delta = cpu_stats_usage.saturating_sub(precpu_stats_usage) as f64;
|
||||||
let online_cpus = stats.cpu_stats.online_cpus.unwrap_or_else(|| {
|
let online_cpus = f64::from(stats.cpu_stats.as_ref().map_or(0, |i| {
|
||||||
u64::try_from(
|
i.online_cpus.unwrap_or_else(|| {
|
||||||
stats
|
u32::try_from(
|
||||||
.cpu_stats
|
stats
|
||||||
.cpu_usage
|
.cpu_stats
|
||||||
.percpu_usage
|
.clone()
|
||||||
.as_ref()
|
.unwrap_or_default()
|
||||||
.map_or(0, std::vec::Vec::len),
|
.cpu_usage
|
||||||
)
|
.unwrap_or_default()
|
||||||
.unwrap_or_default()
|
.percpu_usage
|
||||||
}) as f64;
|
.as_ref()
|
||||||
|
.map_or(0, std::vec::Vec::len),
|
||||||
|
)
|
||||||
|
.unwrap_or_default()
|
||||||
|
})
|
||||||
|
}));
|
||||||
if system_delta > 0.0 && cpu_delta > 0.0 {
|
if system_delta > 0.0 && cpu_delta > 0.0 {
|
||||||
cpu_percentage = (cpu_delta / system_delta) * online_cpus * 100.0;
|
cpu_percentage = (cpu_delta / system_delta) * online_cpus * 100.0;
|
||||||
}
|
}
|
||||||
@@ -133,18 +147,20 @@ impl DockerData {
|
|||||||
|
|
||||||
while let Some(Ok(stats)) = stream.next().await {
|
while let Some(Ok(stats)) = stream.next().await {
|
||||||
// Memory stats are only collected if the container is alive - is this the behaviour we want?
|
// Memory stats are only collected if the container is alive - is this the behaviour we want?
|
||||||
|
|
||||||
let (mem_stat, cpu_stats) = if state.is_alive() {
|
let (mem_stat, cpu_stats) = if state.is_alive() {
|
||||||
let mem_cache = stats.memory_stats.stats.map_or(0, |i| match i {
|
let mem_cache = stats.memory_stats.as_ref().map_or(&0, |i| {
|
||||||
MemoryStatsStats::V1(x) => x.inactive_file,
|
i.stats
|
||||||
MemoryStatsStats::V2(x) => x.inactive_file,
|
.as_ref()
|
||||||
|
.map_or(&0, |i| i.get("inactive_file").unwrap_or(&0))
|
||||||
});
|
});
|
||||||
(
|
(
|
||||||
Some(
|
Some(
|
||||||
stats
|
stats
|
||||||
.memory_stats
|
.memory_stats
|
||||||
.usage
|
.as_ref()
|
||||||
.unwrap_or_default()
|
.map_or(0, |i| i.usage.unwrap_or_default())
|
||||||
.saturating_sub(mem_cache),
|
.saturating_sub(*mem_cache),
|
||||||
),
|
),
|
||||||
Some(Self::calculate_usage(&stats)),
|
Some(Self::calculate_usage(&stats)),
|
||||||
)
|
)
|
||||||
@@ -152,26 +168,25 @@ impl DockerData {
|
|||||||
(None, None)
|
(None, None)
|
||||||
};
|
};
|
||||||
|
|
||||||
let op_key = stats
|
// TODO is hardcoded eth0 a good idea here?
|
||||||
.networks
|
let (rx, tx) = stats.networks.as_ref().map_or((0, 0), |i| {
|
||||||
.as_ref()
|
i.get("eth0").map_or((0, 0), |x| {
|
||||||
.and_then(|networks| networks.keys().next().cloned());
|
(
|
||||||
|
x.rx_bytes.unwrap_or_default(),
|
||||||
let (rx, tx) = if let Some(key) = op_key {
|
x.tx_bytes.unwrap_or_default(),
|
||||||
stats
|
)
|
||||||
.networks
|
})
|
||||||
.unwrap_or_default()
|
});
|
||||||
.get(&key)
|
|
||||||
.map_or((0, 0), |f| (f.rx_bytes, f.tx_bytes))
|
|
||||||
} else {
|
|
||||||
(0, 0)
|
|
||||||
};
|
|
||||||
|
|
||||||
app_data.lock().update_stats_by_id(
|
app_data.lock().update_stats_by_id(
|
||||||
id,
|
id,
|
||||||
cpu_stats,
|
cpu_stats,
|
||||||
mem_stat,
|
mem_stat,
|
||||||
stats.memory_stats.limit.unwrap_or_default(),
|
stats
|
||||||
|
.memory_stats
|
||||||
|
.unwrap_or_default()
|
||||||
|
.limit
|
||||||
|
.unwrap_or_default(),
|
||||||
rx,
|
rx,
|
||||||
tx,
|
tx,
|
||||||
);
|
);
|
||||||
@@ -206,7 +221,7 @@ impl DockerData {
|
|||||||
async fn update_all_containers(&self) {
|
async fn update_all_containers(&self) {
|
||||||
let containers = self
|
let containers = self
|
||||||
.docker
|
.docker
|
||||||
.list_containers(Some(ListContainersOptions::<String> {
|
.list_containers(Some(ListContainersOptions {
|
||||||
all: true,
|
all: true,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}))
|
}))
|
||||||
@@ -244,11 +259,11 @@ impl DockerData {
|
|||||||
spawns: Arc<Mutex<HashMap<SpawnId, JoinHandle<()>>>>,
|
spawns: Arc<Mutex<HashMap<SpawnId, JoinHandle<()>>>>,
|
||||||
stderr: bool,
|
stderr: bool,
|
||||||
) {
|
) {
|
||||||
let options = Some(LogsOptions::<String> {
|
let options = Some(LogsOptions {
|
||||||
stdout: true,
|
stdout: true,
|
||||||
stderr,
|
stderr,
|
||||||
timestamps: true,
|
timestamps: true,
|
||||||
since: i64::try_from(since).unwrap_or_default(),
|
since: i32::try_from(since).unwrap_or_default(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -365,14 +380,22 @@ impl DockerData {
|
|||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
DockerCommand::Pause => docker.pause_container(id.get()).await,
|
DockerCommand::Pause => docker.pause_container(id.get()).await,
|
||||||
DockerCommand::Restart => docker.restart_container(id.get(), None).await,
|
DockerCommand::Restart => {
|
||||||
|
docker
|
||||||
|
.restart_container(id.get(), None::<RestartContainerOptions>)
|
||||||
|
.await
|
||||||
|
}
|
||||||
DockerCommand::Resume => docker.unpause_container(id.get()).await,
|
DockerCommand::Resume => docker.unpause_container(id.get()).await,
|
||||||
DockerCommand::Start => {
|
DockerCommand::Start => {
|
||||||
docker
|
docker
|
||||||
.start_container(id.get(), None::<StartContainerOptions<String>>)
|
.start_container(id.get(), None::<StartContainerOptions>)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
DockerCommand::Stop => {
|
||||||
|
docker
|
||||||
|
.stop_container(id.get(), None::<StopContainerOptions>)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
DockerCommand::Stop => docker.stop_container(id.get(), None).await,
|
|
||||||
}
|
}
|
||||||
.is_err()
|
.is_err()
|
||||||
{
|
{
|
||||||
@@ -448,119 +471,72 @@ impl DockerData {
|
|||||||
#[allow(clippy::float_cmp)]
|
#[allow(clippy::float_cmp)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
|
||||||
use bollard::container::{
|
use bollard::secret::{ContainerCpuStats, ContainerCpuUsage};
|
||||||
BlkioStats, CPUStats, CPUUsage, MemoryStats, PidsStats, Stats, StorageStats, ThrottlingData,
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
fn gen_stats() -> Stats {
|
fn gen_stats() -> ContainerStatsResponse {
|
||||||
Stats {
|
ContainerStatsResponse {
|
||||||
read: String::new(),
|
read: None,
|
||||||
preread: String::new(),
|
preread: None,
|
||||||
num_procs: 1,
|
num_procs: Some(1),
|
||||||
pids_stats: PidsStats {
|
pids_stats: None,
|
||||||
current: None,
|
|
||||||
limit: None,
|
|
||||||
},
|
|
||||||
network: None,
|
|
||||||
networks: None,
|
networks: None,
|
||||||
memory_stats: MemoryStats {
|
memory_stats: None,
|
||||||
stats: None,
|
blkio_stats: None,
|
||||||
max_usage: None,
|
cpu_stats: Some(ContainerCpuStats {
|
||||||
usage: None,
|
cpu_usage: Some(ContainerCpuUsage {
|
||||||
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![50]),
|
percpu_usage: Some(vec![50]),
|
||||||
usage_in_usermode: 10,
|
usage_in_usermode: Some(10),
|
||||||
total_usage: 100,
|
total_usage: Some(100),
|
||||||
usage_in_kernelmode: 20,
|
usage_in_kernelmode: Some(20),
|
||||||
},
|
}),
|
||||||
system_cpu_usage: Some(400),
|
system_cpu_usage: Some(400),
|
||||||
online_cpus: Some(1),
|
online_cpus: Some(1),
|
||||||
throttling_data: ThrottlingData {
|
throttling_data: None,
|
||||||
periods: 0,
|
}),
|
||||||
throttled_periods: 0,
|
precpu_stats: Some(ContainerCpuStats {
|
||||||
throttled_time: 0,
|
cpu_usage: Some(ContainerCpuUsage {
|
||||||
},
|
|
||||||
},
|
|
||||||
precpu_stats: CPUStats {
|
|
||||||
cpu_usage: CPUUsage {
|
|
||||||
percpu_usage: Some(vec![50]),
|
percpu_usage: Some(vec![50]),
|
||||||
usage_in_usermode: 10,
|
usage_in_usermode: Some(10),
|
||||||
total_usage: 100,
|
total_usage: Some(100),
|
||||||
usage_in_kernelmode: 20,
|
usage_in_kernelmode: Some(20),
|
||||||
},
|
}),
|
||||||
system_cpu_usage: Some(400),
|
system_cpu_usage: Some(400),
|
||||||
online_cpus: Some(1),
|
online_cpus: Some(1),
|
||||||
throttling_data: ThrottlingData {
|
throttling_data: None,
|
||||||
periods: 0,
|
}),
|
||||||
throttled_periods: 0,
|
storage_stats: None,
|
||||||
throttled_time: 0,
|
name: None,
|
||||||
},
|
id: None,
|
||||||
},
|
|
||||||
storage_stats: StorageStats {
|
|
||||||
read_count_normalized: None,
|
|
||||||
read_size_bytes: None,
|
|
||||||
write_count_normalized: None,
|
|
||||||
write_size_bytes: None,
|
|
||||||
},
|
|
||||||
name: String::new(),
|
|
||||||
id: String::new(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_calculate_usage_50() {
|
fn test_calculate_usage_50() {
|
||||||
let mut stats = gen_stats();
|
let mut stats = gen_stats();
|
||||||
stats.precpu_stats = CPUStats {
|
stats.precpu_stats = Some(ContainerCpuStats {
|
||||||
cpu_usage: CPUUsage {
|
cpu_usage: Some(ContainerCpuUsage {
|
||||||
percpu_usage: Some(vec![50]),
|
percpu_usage: Some(vec![50]),
|
||||||
usage_in_usermode: 10,
|
usage_in_usermode: Some(10),
|
||||||
total_usage: 100,
|
total_usage: Some(100),
|
||||||
usage_in_kernelmode: 20,
|
usage_in_kernelmode: Some(20),
|
||||||
},
|
}),
|
||||||
system_cpu_usage: Some(400),
|
system_cpu_usage: Some(400),
|
||||||
online_cpus: Some(1),
|
online_cpus: Some(1),
|
||||||
throttling_data: ThrottlingData {
|
throttling_data: None,
|
||||||
periods: 0,
|
});
|
||||||
throttled_periods: 0,
|
stats.cpu_stats = Some(ContainerCpuStats {
|
||||||
throttled_time: 0,
|
cpu_usage: Some(ContainerCpuUsage {
|
||||||
},
|
|
||||||
};
|
|
||||||
stats.cpu_stats = CPUStats {
|
|
||||||
cpu_usage: CPUUsage {
|
|
||||||
percpu_usage: Some(vec![150]),
|
percpu_usage: Some(vec![150]),
|
||||||
usage_in_usermode: 20,
|
usage_in_usermode: Some(20),
|
||||||
total_usage: 150,
|
total_usage: Some(150),
|
||||||
usage_in_kernelmode: 30,
|
usage_in_kernelmode: Some(30),
|
||||||
},
|
}),
|
||||||
system_cpu_usage: Some(500),
|
system_cpu_usage: Some(500),
|
||||||
online_cpus: Some(1),
|
online_cpus: Some(1),
|
||||||
throttling_data: ThrottlingData {
|
throttling_data: None,
|
||||||
periods: 0,
|
});
|
||||||
throttled_periods: 0,
|
|
||||||
throttled_time: 0,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
let cpu_percentage = DockerData::calculate_usage(&stats);
|
let cpu_percentage = DockerData::calculate_usage(&stats);
|
||||||
assert_eq!(50.0, cpu_percentage);
|
assert_eq!(50.0, cpu_percentage);
|
||||||
}
|
}
|
||||||
@@ -568,37 +544,28 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_calculate_usage_25() {
|
fn test_calculate_usage_25() {
|
||||||
let mut stats = gen_stats();
|
let mut stats = gen_stats();
|
||||||
stats.precpu_stats = CPUStats {
|
stats.precpu_stats = Some(ContainerCpuStats {
|
||||||
cpu_usage: CPUUsage {
|
cpu_usage: Some(ContainerCpuUsage {
|
||||||
percpu_usage: Some(vec![50]),
|
percpu_usage: Some(vec![50]),
|
||||||
usage_in_usermode: 10,
|
usage_in_usermode: Some(10),
|
||||||
total_usage: 100,
|
total_usage: Some(100),
|
||||||
usage_in_kernelmode: 20,
|
usage_in_kernelmode: Some(20),
|
||||||
},
|
}),
|
||||||
system_cpu_usage: Some(400),
|
system_cpu_usage: Some(400),
|
||||||
online_cpus: Some(1),
|
online_cpus: Some(1),
|
||||||
throttling_data: ThrottlingData {
|
throttling_data: None,
|
||||||
periods: 0,
|
});
|
||||||
throttled_periods: 0,
|
stats.cpu_stats = Some(ContainerCpuStats {
|
||||||
throttled_time: 0,
|
cpu_usage: Some(ContainerCpuUsage {
|
||||||
},
|
|
||||||
};
|
|
||||||
stats.cpu_stats = CPUStats {
|
|
||||||
cpu_usage: CPUUsage {
|
|
||||||
percpu_usage: Some(vec![75]),
|
percpu_usage: Some(vec![75]),
|
||||||
usage_in_usermode: 20,
|
usage_in_usermode: Some(20),
|
||||||
total_usage: 125,
|
total_usage: Some(125),
|
||||||
usage_in_kernelmode: 30,
|
usage_in_kernelmode: Some(30),
|
||||||
},
|
}),
|
||||||
system_cpu_usage: Some(500),
|
system_cpu_usage: Some(500),
|
||||||
online_cpus: Some(1),
|
online_cpus: Some(1),
|
||||||
throttling_data: ThrottlingData {
|
throttling_data: None,
|
||||||
periods: 0,
|
});
|
||||||
throttled_periods: 0,
|
|
||||||
throttled_time: 0,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
let cpu_percentage = DockerData::calculate_usage(&stats);
|
let cpu_percentage = DockerData::calculate_usage(&stats);
|
||||||
assert_eq!(25.0, cpu_percentage);
|
assert_eq!(25.0, cpu_percentage);
|
||||||
}
|
}
|
||||||
@@ -606,38 +573,28 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_calculate_usage_75() {
|
fn test_calculate_usage_75() {
|
||||||
let mut stats = gen_stats();
|
let mut stats = gen_stats();
|
||||||
stats.precpu_stats = CPUStats {
|
stats.precpu_stats = Some(ContainerCpuStats {
|
||||||
cpu_usage: CPUUsage {
|
cpu_usage: Some(ContainerCpuUsage {
|
||||||
percpu_usage: Some(vec![50]),
|
percpu_usage: Some(vec![50]),
|
||||||
usage_in_usermode: 10,
|
usage_in_usermode: Some(10),
|
||||||
total_usage: 100,
|
total_usage: Some(100),
|
||||||
usage_in_kernelmode: 20,
|
usage_in_kernelmode: Some(20),
|
||||||
},
|
}),
|
||||||
system_cpu_usage: Some(400),
|
system_cpu_usage: Some(400),
|
||||||
online_cpus: Some(1),
|
online_cpus: Some(1),
|
||||||
throttling_data: ThrottlingData {
|
throttling_data: None,
|
||||||
periods: 0,
|
});
|
||||||
throttled_periods: 0,
|
stats.cpu_stats = Some(ContainerCpuStats {
|
||||||
throttled_time: 0,
|
cpu_usage: Some(ContainerCpuUsage {
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
stats.cpu_stats = CPUStats {
|
|
||||||
cpu_usage: CPUUsage {
|
|
||||||
percpu_usage: Some(vec![175]),
|
percpu_usage: Some(vec![175]),
|
||||||
usage_in_usermode: 20,
|
usage_in_usermode: Some(20),
|
||||||
total_usage: 175,
|
total_usage: Some(175),
|
||||||
usage_in_kernelmode: 30,
|
usage_in_kernelmode: Some(30),
|
||||||
},
|
}),
|
||||||
system_cpu_usage: Some(500),
|
system_cpu_usage: Some(500),
|
||||||
online_cpus: Some(1),
|
online_cpus: Some(1),
|
||||||
throttling_data: ThrottlingData {
|
throttling_data: None,
|
||||||
periods: 0,
|
});
|
||||||
throttled_periods: 0,
|
|
||||||
throttled_time: 0,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
let cpu_percentage = DockerData::calculate_usage(&stats);
|
let cpu_percentage = DockerData::calculate_usage(&stats);
|
||||||
assert_eq!(75.0, cpu_percentage);
|
assert_eq!(75.0, cpu_percentage);
|
||||||
}
|
}
|
||||||
@@ -645,36 +602,28 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_calculate_usage_100() {
|
fn test_calculate_usage_100() {
|
||||||
let mut stats = gen_stats();
|
let mut stats = gen_stats();
|
||||||
stats.precpu_stats = CPUStats {
|
stats.precpu_stats = Some(ContainerCpuStats {
|
||||||
cpu_usage: CPUUsage {
|
cpu_usage: Some(ContainerCpuUsage {
|
||||||
percpu_usage: Some(vec![50]),
|
percpu_usage: Some(vec![50]),
|
||||||
usage_in_usermode: 10,
|
usage_in_usermode: Some(10),
|
||||||
total_usage: 100,
|
total_usage: Some(100),
|
||||||
usage_in_kernelmode: 20,
|
usage_in_kernelmode: Some(20),
|
||||||
},
|
}),
|
||||||
system_cpu_usage: Some(400),
|
system_cpu_usage: Some(400),
|
||||||
online_cpus: Some(1),
|
online_cpus: Some(1),
|
||||||
throttling_data: ThrottlingData {
|
throttling_data: None,
|
||||||
periods: 0,
|
});
|
||||||
throttled_periods: 0,
|
stats.cpu_stats = Some(ContainerCpuStats {
|
||||||
throttled_time: 0,
|
cpu_usage: Some(ContainerCpuUsage {
|
||||||
},
|
|
||||||
};
|
|
||||||
stats.cpu_stats = CPUStats {
|
|
||||||
cpu_usage: CPUUsage {
|
|
||||||
percpu_usage: Some(vec![200]),
|
percpu_usage: Some(vec![200]),
|
||||||
usage_in_usermode: 20,
|
usage_in_usermode: Some(20),
|
||||||
total_usage: 200,
|
total_usage: Some(200),
|
||||||
usage_in_kernelmode: 30,
|
usage_in_kernelmode: Some(30),
|
||||||
},
|
}),
|
||||||
system_cpu_usage: Some(500),
|
system_cpu_usage: Some(500),
|
||||||
online_cpus: Some(1),
|
online_cpus: Some(1),
|
||||||
throttling_data: ThrottlingData {
|
throttling_data: None,
|
||||||
periods: 0,
|
});
|
||||||
throttled_periods: 0,
|
|
||||||
throttled_time: 0,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
let cpu_percentage = DockerData::calculate_usage(&stats);
|
let cpu_percentage = DockerData::calculate_usage(&stats);
|
||||||
assert_eq!(100.0, cpu_percentage);
|
assert_eq!(100.0, cpu_percentage);
|
||||||
}
|
}
|
||||||
@@ -682,38 +631,28 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_calculate_usage_175() {
|
fn test_calculate_usage_175() {
|
||||||
let mut stats = gen_stats();
|
let mut stats = gen_stats();
|
||||||
stats.precpu_stats = CPUStats {
|
stats.precpu_stats = Some(ContainerCpuStats {
|
||||||
cpu_usage: CPUUsage {
|
cpu_usage: Some(ContainerCpuUsage {
|
||||||
percpu_usage: Some(vec![50]),
|
percpu_usage: Some(vec![50]),
|
||||||
usage_in_usermode: 10,
|
usage_in_usermode: Some(10),
|
||||||
total_usage: 100,
|
total_usage: Some(100),
|
||||||
usage_in_kernelmode: 20,
|
usage_in_kernelmode: Some(20),
|
||||||
},
|
}),
|
||||||
system_cpu_usage: Some(400),
|
system_cpu_usage: Some(400),
|
||||||
online_cpus: Some(1),
|
online_cpus: Some(1),
|
||||||
throttling_data: ThrottlingData {
|
throttling_data: None,
|
||||||
periods: 0,
|
});
|
||||||
throttled_periods: 0,
|
stats.cpu_stats = Some(ContainerCpuStats {
|
||||||
throttled_time: 0,
|
cpu_usage: Some(ContainerCpuUsage {
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
stats.cpu_stats = CPUStats {
|
|
||||||
cpu_usage: CPUUsage {
|
|
||||||
percpu_usage: Some(vec![275]),
|
percpu_usage: Some(vec![275]),
|
||||||
usage_in_usermode: 20,
|
usage_in_usermode: Some(20),
|
||||||
total_usage: 275,
|
total_usage: Some(275),
|
||||||
usage_in_kernelmode: 30,
|
usage_in_kernelmode: Some(30),
|
||||||
},
|
}),
|
||||||
system_cpu_usage: Some(500),
|
system_cpu_usage: Some(500),
|
||||||
online_cpus: Some(1),
|
online_cpus: Some(1),
|
||||||
throttling_data: ThrottlingData {
|
throttling_data: None,
|
||||||
periods: 0,
|
});
|
||||||
throttled_periods: 0,
|
|
||||||
throttled_time: 0,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
let cpu_percentage = DockerData::calculate_usage(&stats);
|
let cpu_percentage = DockerData::calculate_usage(&stats);
|
||||||
assert_eq!(175.0, cpu_percentage);
|
assert_eq!(175.0, cpu_percentage);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,5 +3,5 @@ use crossterm::event::{KeyCode, KeyModifiers, MouseEvent};
|
|||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub enum InputMessages {
|
pub enum InputMessages {
|
||||||
ButtonPress((KeyCode, KeyModifiers)),
|
ButtonPress((KeyCode, KeyModifiers)),
|
||||||
MouseEvent(MouseEvent),
|
MouseEvent((MouseEvent, KeyModifiers)),
|
||||||
}
|
}
|
||||||
|
|||||||
+83
-20
@@ -5,8 +5,7 @@ use std::{
|
|||||||
time::SystemTime,
|
time::SystemTime,
|
||||||
};
|
};
|
||||||
|
|
||||||
use bollard::container::LogsOptions;
|
use bollard::query_parameters::LogsOptions;
|
||||||
// use bollard::container::LogsOptions;
|
|
||||||
use cansi::v3::categorise_text;
|
use cansi::v3::categorise_text;
|
||||||
use crossterm::{
|
use crossterm::{
|
||||||
event::{DisableMouseCapture, KeyCode, KeyModifiers, MouseButton, MouseEvent, MouseEventKind},
|
event::{DisableMouseCapture, KeyCode, KeyModifiers, MouseButton, MouseEvent, MouseEventKind},
|
||||||
@@ -68,7 +67,7 @@ impl InputHandler {
|
|||||||
while let Some(message) = self.rx.recv().await {
|
while let Some(message) = self.rx.recv().await {
|
||||||
match message {
|
match message {
|
||||||
InputMessages::ButtonPress(key) => self.button_press(key.0, key.1).await,
|
InputMessages::ButtonPress(key) => self.button_press(key.0, key.1).await,
|
||||||
InputMessages::MouseEvent(mouse_event) => {
|
InputMessages::MouseEvent((mouse_event, modifider)) => {
|
||||||
let status = self.gui_state.lock().get_status();
|
let status = self.gui_state.lock().get_status();
|
||||||
let contains = |s: Status| status.contains(&s);
|
let contains = |s: Status| status.contains(&s);
|
||||||
|
|
||||||
@@ -79,7 +78,7 @@ impl InputHandler {
|
|||||||
| !contains(Status::DeleteConfirm)
|
| !contains(Status::DeleteConfirm)
|
||||||
| !contains(Status::Filter)
|
| !contains(Status::Filter)
|
||||||
{
|
{
|
||||||
self.mouse_press(mouse_event);
|
self.mouse_press(mouse_event, modifider);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -188,7 +187,7 @@ impl InputHandler {
|
|||||||
|
|
||||||
let path = log_path.join(format!("{name}_{now}.log"));
|
let path = log_path.join(format!("{name}_{now}.log"));
|
||||||
|
|
||||||
let options = Some(LogsOptions::<String> {
|
let options = Some(LogsOptions {
|
||||||
stderr: true,
|
stderr: true,
|
||||||
stdout: true,
|
stdout: true,
|
||||||
timestamps: args.show_timestamp,
|
timestamps: args.show_timestamp,
|
||||||
@@ -286,6 +285,36 @@ impl InputHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// If keymap.scroll_modifier is pressed, return 10, else return 1, to speed up scrolling
|
||||||
|
fn get_modifier_total(&self, modifier: KeyModifiers) -> u8 {
|
||||||
|
if modifier == self.keymap.scroll_many {
|
||||||
|
10
|
||||||
|
} else {
|
||||||
|
1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Advance the "cursor" along the logs
|
||||||
|
fn logs_forward(&self, modifier: KeyModifiers) {
|
||||||
|
let panel = self.gui_state.lock().get_selected_panel();
|
||||||
|
if panel == SelectablePanel::Logs {
|
||||||
|
for _ in 0..self.get_modifier_total(modifier) {
|
||||||
|
let width = self.gui_state.lock().get_screen_width();
|
||||||
|
self.app_data.lock().log_forward(width);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Retreat the "cursor" along the logs
|
||||||
|
fn logs_back(&self, modifier: KeyModifiers) {
|
||||||
|
let panel = self.gui_state.lock().get_selected_panel();
|
||||||
|
if panel == SelectablePanel::Logs {
|
||||||
|
for _ in 0..self.get_modifier_total(modifier) {
|
||||||
|
self.app_data.lock().log_back();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Change the the "next" selectable panel
|
/// Change the the "next" selectable panel
|
||||||
/// If no containers, and on Commands panel, skip to next panel, as Commands panel isn't visible in this state
|
/// If no containers, and on Commands panel, skip to next panel, as Commands panel isn't visible in this state
|
||||||
fn next_panel_key(&self) {
|
fn next_panel_key(&self) {
|
||||||
@@ -391,6 +420,11 @@ impl InputHandler {
|
|||||||
/// Handle input that refers to the sorting of columns
|
/// Handle input that refers to the sorting of columns
|
||||||
fn handle_sort(&self, key_code: KeyCode) {
|
fn handle_sort(&self, key_code: KeyCode) {
|
||||||
match key_code {
|
match key_code {
|
||||||
|
_ if self.keymap.force_redraw.0 == key_code
|
||||||
|
|| self.keymap.force_redraw.1 == Some(key_code) =>
|
||||||
|
{
|
||||||
|
self.gui_state.lock().set_clear();
|
||||||
|
}
|
||||||
_ if self.keymap.sort_reset.0 == key_code
|
_ if self.keymap.sort_reset.0 == key_code
|
||||||
|| self.keymap.sort_reset.1 == Some(key_code) =>
|
|| self.keymap.sort_reset.1 == Some(key_code) =>
|
||||||
{
|
{
|
||||||
@@ -467,7 +501,8 @@ impl InputHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Handle button presses in all other scenarios
|
/// Handle button presses in all other scenarios
|
||||||
async fn handle_others(&mut self, key_code: KeyCode) {
|
#[allow(clippy::cognitive_complexity)]
|
||||||
|
async fn handle_others(&mut self, key_code: KeyCode, modifier: KeyModifiers) {
|
||||||
self.handle_sort(key_code);
|
self.handle_sort(key_code);
|
||||||
// shift key plus arrows
|
// shift key plus arrows
|
||||||
match key_code {
|
match key_code {
|
||||||
@@ -537,28 +572,28 @@ impl InputHandler {
|
|||||||
_ if self.keymap.scroll_up_one.0 == key_code
|
_ if self.keymap.scroll_up_one.0 == key_code
|
||||||
|| self.keymap.scroll_up_one.1 == Some(key_code) =>
|
|| self.keymap.scroll_up_one.1 == Some(key_code) =>
|
||||||
{
|
{
|
||||||
self.previous();
|
self.scroll_up(modifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
_ if self.keymap.scroll_up_many.0 == key_code
|
_ if self.keymap.scroll_up_many.0 == key_code
|
||||||
|| self.keymap.scroll_up_many.1 == Some(key_code) =>
|
|| self.keymap.scroll_up_many.1 == Some(key_code) =>
|
||||||
{
|
{
|
||||||
for _ in 0..=6 {
|
for _ in 0..=6 {
|
||||||
self.previous();
|
self.scroll_up(modifier);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_ if self.keymap.scroll_down_one.0 == key_code
|
_ if self.keymap.scroll_down_one.0 == key_code
|
||||||
|| self.keymap.scroll_down_one.1 == Some(key_code) =>
|
|| self.keymap.scroll_down_one.1 == Some(key_code) =>
|
||||||
{
|
{
|
||||||
self.next();
|
self.scroll_down(modifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
_ if self.keymap.scroll_down_many.0 == key_code
|
_ if self.keymap.scroll_down_many.0 == key_code
|
||||||
|| self.keymap.scroll_down_many.1 == Some(key_code) =>
|
|| self.keymap.scroll_down_many.1 == Some(key_code) =>
|
||||||
{
|
{
|
||||||
for _ in 0..=6 {
|
for _ in 0..=6 {
|
||||||
self.next();
|
self.scroll_down(modifier);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -569,6 +604,18 @@ impl InputHandler {
|
|||||||
self.docker_tx.send(DockerMessage::Update).await.ok();
|
self.docker_tx.send(DockerMessage::Update).await.ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_ if self.keymap.log_scroll_back.0 == key_code
|
||||||
|
|| self.keymap.log_scroll_back.1 == Some(key_code) =>
|
||||||
|
{
|
||||||
|
self.logs_back(modifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
_ if self.keymap.log_scroll_forward.0 == key_code
|
||||||
|
|| self.keymap.log_scroll_forward.1 == Some(key_code) =>
|
||||||
|
{
|
||||||
|
self.logs_forward(modifier);
|
||||||
|
}
|
||||||
|
|
||||||
KeyCode::Enter => self.enter_key().await,
|
KeyCode::Enter => self.enter_key().await,
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
@@ -603,7 +650,7 @@ impl InputHandler {
|
|||||||
} else if contains_delete {
|
} else if contains_delete {
|
||||||
self.handle_delete(key_code).await;
|
self.handle_delete(key_code).await;
|
||||||
} else {
|
} else {
|
||||||
self.handle_others(key_code).await;
|
self.handle_others(key_code, key_modifier).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -628,7 +675,7 @@ impl InputHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Handle mouse button events
|
/// Handle mouse button events
|
||||||
fn mouse_press(&self, mouse_event: MouseEvent) {
|
fn mouse_press(&self, mouse_event: MouseEvent, modifier: KeyModifiers) {
|
||||||
let status = self.gui_state.lock().get_status();
|
let status = self.gui_state.lock().get_status();
|
||||||
if status.contains(&Status::Help) {
|
if status.contains(&Status::Help) {
|
||||||
let mouse_point = Rect::new(mouse_event.column, mouse_event.row, 1, 1);
|
let mouse_point = Rect::new(mouse_event.column, mouse_event.row, 1, 1);
|
||||||
@@ -638,8 +685,8 @@ impl InputHandler {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
match mouse_event.kind {
|
match mouse_event.kind {
|
||||||
MouseEventKind::ScrollUp => self.previous(),
|
MouseEventKind::ScrollUp => self.scroll_up(modifier),
|
||||||
MouseEventKind::ScrollDown => self.next(),
|
MouseEventKind::ScrollDown => self.scroll_down(modifier),
|
||||||
MouseEventKind::Down(MouseButton::Left) => {
|
MouseEventKind::Down(MouseButton::Left) => {
|
||||||
let mouse_point = Rect::new(mouse_event.column, mouse_event.row, 1, 1);
|
let mouse_point = Rect::new(mouse_event.column, mouse_event.row, 1, 1);
|
||||||
let header = self.gui_state.lock().get_intersect_header(mouse_point);
|
let header = self.gui_state.lock().get_intersect_header(mouse_point);
|
||||||
@@ -659,21 +706,37 @@ impl InputHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Change state to next, depending which panel is currently in focus
|
/// Change state to next, depending which panel is currently in focus
|
||||||
fn next(&self) {
|
fn scroll_down(&self, modifier: KeyModifiers) {
|
||||||
let selected_panel = self.gui_state.lock().get_selected_panel();
|
let selected_panel = self.gui_state.lock().get_selected_panel();
|
||||||
match selected_panel {
|
match selected_panel {
|
||||||
SelectablePanel::Containers => self.app_data.lock().containers_next(),
|
SelectablePanel::Containers => {
|
||||||
SelectablePanel::Logs => self.app_data.lock().log_next(),
|
for _ in 0..self.get_modifier_total(modifier) {
|
||||||
|
self.app_data.lock().containers_next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SelectablePanel::Logs => {
|
||||||
|
for _ in 0..self.get_modifier_total(modifier) {
|
||||||
|
self.app_data.lock().log_next();
|
||||||
|
}
|
||||||
|
}
|
||||||
SelectablePanel::Commands => self.app_data.lock().docker_controls_next(),
|
SelectablePanel::Commands => self.app_data.lock().docker_controls_next(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Change state to previous, depending which panel is currently in focus
|
/// Change state to previous, depending which panel is currently in focus
|
||||||
fn previous(&self) {
|
fn scroll_up(&self, modifier: KeyModifiers) {
|
||||||
let selected_panel = self.gui_state.lock().get_selected_panel();
|
let selected_panel = self.gui_state.lock().get_selected_panel();
|
||||||
match selected_panel {
|
match selected_panel {
|
||||||
SelectablePanel::Containers => self.app_data.lock().containers_previous(),
|
SelectablePanel::Containers => {
|
||||||
SelectablePanel::Logs => self.app_data.lock().log_previous(),
|
for _ in 0..self.get_modifier_total(modifier) {
|
||||||
|
self.app_data.lock().containers_previous();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SelectablePanel::Logs => {
|
||||||
|
for _ in 0..self.get_modifier_total(modifier) {
|
||||||
|
self.app_data.lock().log_previous();
|
||||||
|
}
|
||||||
|
}
|
||||||
SelectablePanel::Commands => self.app_data.lock().docker_controls_previous(),
|
SelectablePanel::Commands => self.app_data.lock().docker_controls_previous(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+7
-3
@@ -1,3 +1,6 @@
|
|||||||
|
#![allow(clippy::collapsible_if)]
|
||||||
|
// Zigbuild is stuck on 1.87.0, which means Mac builds won't work when using collapsible ifs
|
||||||
|
|
||||||
use app_data::AppData;
|
use app_data::AppData;
|
||||||
use app_error::AppError;
|
use app_error::AppError;
|
||||||
use bollard::{API_DEFAULT_VERSION, Docker};
|
use bollard::{API_DEFAULT_VERSION, Docker};
|
||||||
@@ -149,7 +152,7 @@ async fn main() {
|
|||||||
#[allow(clippy::unwrap_used)]
|
#[allow(clippy::unwrap_used)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
|
||||||
use std::sync::Arc;
|
use std::{str::FromStr, sync::Arc};
|
||||||
|
|
||||||
use bollard::service::{ContainerSummary, Port};
|
use bollard::service::{ContainerSummary, Port};
|
||||||
|
|
||||||
@@ -208,7 +211,7 @@ mod tests {
|
|||||||
current_sorted_id: vec![],
|
current_sorted_id: vec![],
|
||||||
error: None,
|
error: None,
|
||||||
sorted_by: None,
|
sorted_by: None,
|
||||||
redraw: Arc::new(Rerender::new()),
|
rerender: Arc::new(Rerender::new()),
|
||||||
filter: Filter::new(),
|
filter: Filter::new(),
|
||||||
config: gen_config(),
|
config: gen_config(),
|
||||||
}
|
}
|
||||||
@@ -228,6 +231,7 @@ mod tests {
|
|||||||
|
|
||||||
pub fn gen_container_summary(index: usize, state: &str) -> ContainerSummary {
|
pub fn gen_container_summary(index: usize, state: &str) -> ContainerSummary {
|
||||||
ContainerSummary {
|
ContainerSummary {
|
||||||
|
image_manifest_descriptor: None,
|
||||||
id: Some(format!("{index}")),
|
id: Some(format!("{index}")),
|
||||||
names: Some(vec![format!("container_{}", index)]),
|
names: Some(vec![format!("container_{}", index)]),
|
||||||
image: Some(format!("image_{index}")),
|
image: Some(format!("image_{index}")),
|
||||||
@@ -243,7 +247,7 @@ mod tests {
|
|||||||
size_rw: None,
|
size_rw: None,
|
||||||
size_root_fs: None,
|
size_root_fs: None,
|
||||||
labels: None,
|
labels: None,
|
||||||
state: Some(state.to_owned()),
|
state: Some(bollard::secret::ContainerSummaryStateEnum::from_str(state).unwrap()),
|
||||||
status: Some(format!("Up {index} hour")),
|
status: Some(format!("Up {index} hour")),
|
||||||
host_config: None,
|
host_config: None,
|
||||||
network_settings: None,
|
network_settings: None,
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ use ratatui::{
|
|||||||
use crate::{app_data::FilterBy, config::AppColors, ui::FrameData};
|
use crate::{app_data::FilterBy, config::AppColors, ui::FrameData};
|
||||||
|
|
||||||
/// Create the filter_by by spans, coloured dependant on which one is selected
|
/// Create the filter_by by spans, coloured dependant on which one is selected
|
||||||
fn filter_by_spans(colors: AppColors, fd: &FrameData) -> [Span; 4] {
|
fn filter_by_spans(colors: AppColors, fd: &'_ FrameData) -> [Span<'_>; 4] {
|
||||||
let selected = Style::default()
|
let selected = Style::default()
|
||||||
.bg(colors.filter.selected_filter_background)
|
.bg(colors.filter.selected_filter_background)
|
||||||
.fg(colors.filter.selected_filter_text);
|
.fg(colors.filter.selected_filter_text);
|
||||||
|
|||||||
+164
-116
@@ -109,7 +109,17 @@ impl HelpInfo {
|
|||||||
button_item("PgUp PgDown"),
|
button_item("PgUp PgDown"),
|
||||||
or(),
|
or(),
|
||||||
button_item("Home End"),
|
button_item("Home End"),
|
||||||
button_desc("change selected line"),
|
button_desc("scroll vertically"),
|
||||||
|
]),
|
||||||
|
Line::from(vec![
|
||||||
|
space(),
|
||||||
|
button_item("← →"),
|
||||||
|
button_desc("horizontal scroll across logs"),
|
||||||
|
]),
|
||||||
|
Line::from(vec![
|
||||||
|
space(),
|
||||||
|
button_item("ctrl"),
|
||||||
|
button_desc("increase scroll speed, used in conjuction scroll keys"),
|
||||||
]),
|
]),
|
||||||
Line::from(vec![
|
Line::from(vec![
|
||||||
space(),
|
space(),
|
||||||
@@ -123,6 +133,11 @@ impl HelpInfo {
|
|||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
button_desc(" - not available on Windows"),
|
button_desc(" - not available on Windows"),
|
||||||
]),
|
]),
|
||||||
|
Line::from(vec![
|
||||||
|
space(),
|
||||||
|
button_item("f"),
|
||||||
|
button_desc("force clear the screen & redraw the gui"),
|
||||||
|
]),
|
||||||
Line::from(vec![
|
Line::from(vec![
|
||||||
space(),
|
space(),
|
||||||
button_item("h"),
|
button_item("h"),
|
||||||
@@ -268,6 +283,13 @@ impl HelpInfo {
|
|||||||
or_secondary(km.scroll_up_many, "scroll list by up many"),
|
or_secondary(km.scroll_up_many, "scroll list by up many"),
|
||||||
or_secondary(km.scroll_end, "scroll list to end"),
|
or_secondary(km.scroll_end, "scroll list to end"),
|
||||||
or_secondary(km.scroll_start, "scroll list to start"),
|
or_secondary(km.scroll_start, "scroll list to start"),
|
||||||
|
or_secondary(km.log_scroll_forward, "horizontal scroll logs right"),
|
||||||
|
or_secondary(km.log_scroll_back, "horizontal scroll logs left"),
|
||||||
|
Line::from(vec![
|
||||||
|
space(),
|
||||||
|
button_item(km.scroll_many.to_string().as_str()),
|
||||||
|
button_desc("increase scroll speed, used in conjuction scroll keys"),
|
||||||
|
]),
|
||||||
Line::from(vec![
|
Line::from(vec![
|
||||||
space(),
|
space(),
|
||||||
button_item("enter"),
|
button_item("enter"),
|
||||||
@@ -277,6 +299,7 @@ impl HelpInfo {
|
|||||||
or_secondary(km.exec, "exec into a container"),
|
or_secondary(km.exec, "exec into a container"),
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
or_secondary(km.exec, "exec into a container - not available on Windows"),
|
or_secondary(km.exec, "exec into a container - not available on Windows"),
|
||||||
|
or_secondary(km.force_redraw, "force clear the screen & redraw the gui"),
|
||||||
or_secondary(
|
or_secondary(
|
||||||
km.toggle_help,
|
km.toggle_help,
|
||||||
"toggle this help information - or click heading",
|
"toggle this help information - or click heading",
|
||||||
@@ -427,7 +450,7 @@ pub fn draw(
|
|||||||
#[allow(clippy::unwrap_used, clippy::too_many_lines)]
|
#[allow(clippy::unwrap_used, clippy::too_many_lines)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::config::{AppColors, Keymap};
|
use crate::config::{AppColors, Keymap};
|
||||||
use crossterm::event::KeyCode;
|
use crossterm::event::{KeyCode, KeyModifiers};
|
||||||
use insta::assert_snapshot;
|
use insta::assert_snapshot;
|
||||||
use jiff::tz::TimeZone;
|
use jiff::tz::TimeZone;
|
||||||
use ratatui::style::{Color, Modifier};
|
use ratatui::style::{Color, Modifier};
|
||||||
@@ -436,8 +459,10 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[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)
|
||||||
|
/// This test is incredibly annoying
|
||||||
|
/// println!("{} {} {} {} {}", row_index, result_cell_index, result_cell.symbol(), result_cell.bg, result_cell.fg);
|
||||||
fn test_draw_blocks_help() {
|
fn test_draw_blocks_help() {
|
||||||
let mut setup = test_setup(87, 35, true, true);
|
let mut setup = test_setup(87, 37, true, true);
|
||||||
let tz = setup.app_data.lock().config.timezone.clone();
|
let tz = setup.app_data.lock().config.timezone.clone();
|
||||||
|
|
||||||
setup
|
setup
|
||||||
@@ -457,36 +482,45 @@ mod tests {
|
|||||||
|
|
||||||
for (row_index, result_row) in get_result(&setup) {
|
for (row_index, result_row) in get_result(&setup) {
|
||||||
for (result_cell_index, result_cell) in result_row.iter().enumerate() {
|
for (result_cell_index, result_cell) in result_row.iter().enumerate() {
|
||||||
|
println!(
|
||||||
|
"{} {} {} {} {}",
|
||||||
|
row_index,
|
||||||
|
result_cell_index,
|
||||||
|
result_cell.symbol(),
|
||||||
|
result_cell.bg,
|
||||||
|
result_cell.fg
|
||||||
|
);
|
||||||
match (row_index, result_cell_index) {
|
match (row_index, result_cell_index) {
|
||||||
// first & last row, and first & last char on each row, is reset/reset, making sure that the help info is centered in the given area
|
// first & last row, and first & last char on each row, is reset/reset, making sure that the help info is centered in the given area
|
||||||
(0 | 34, _) | (0..=33, 0 | 86) => {
|
(0 | 36, _) | (0..=35, 0 | 86) => {
|
||||||
assert_eq!(result_cell.bg, Color::Reset);
|
assert_eq!(result_cell.bg, Color::Reset);
|
||||||
assert_eq!(result_cell.fg, Color::Reset);
|
assert_eq!(result_cell.fg, Color::Reset);
|
||||||
}
|
}
|
||||||
// border is black on magenta
|
// border is red on black
|
||||||
(1 | 32, _) | (1..=31, 1 | 85) => {
|
(1 | 34, _) | (1..=31, 1 | 85) => {
|
||||||
assert_eq!(result_cell.bg, Color::Magenta);
|
assert_eq!(result_cell.bg, Color::Magenta);
|
||||||
assert_eq!(result_cell.fg, Color::Black);
|
assert_eq!(result_cell.fg, Color::Black);
|
||||||
}
|
}
|
||||||
// oxker logo && description
|
// Buttons
|
||||||
(2..=10, 2..=85)
|
(2..=10, 2..=85)
|
||||||
| (12, 19..=66)
|
| (12, 19..=66)
|
||||||
| (14, 2..=10 | 13..=27)
|
| (14, 2..=10 | 13..=27)
|
||||||
| (15, 2..=10 | 13..=21 | 24..=40 | 43..=56)
|
| (15, 2..=10 | 13..=21 | 24..=40 | 43..=56)
|
||||||
| (16 | 23, 2..=12)
|
| (16 | 27 | 29, 2..=10)
|
||||||
| (17..=20 | 22 | 25 | 27, 2..=8)
|
| (17, 2..=11)
|
||||||
| (21, 2..=9 | 12..=18)
|
| (18 | 26, 2..=12)
|
||||||
| (24 | 26, 2..=10) => {
|
| (19 | 20 | 21 | 22 | 24 | 25 | 28 | 23 | 30, 2..=8)
|
||||||
|
| (24, 2..=9 | 12..=18) => {
|
||||||
assert_eq!(result_cell.bg, Color::Magenta);
|
assert_eq!(result_cell.bg, Color::Magenta);
|
||||||
assert_eq!(result_cell.fg, Color::White);
|
assert_eq!(result_cell.fg, Color::White);
|
||||||
}
|
}
|
||||||
// The URL is white and underlined
|
// The URL is yellow and underlined
|
||||||
(30, 25..=60) => {
|
(33, 25..=60) => {
|
||||||
assert_eq!(result_cell.bg, Color::Magenta);
|
assert_eq!(result_cell.bg, Color::Magenta);
|
||||||
assert_eq!(result_cell.fg, Color::White);
|
assert_eq!(result_cell.fg, Color::White);
|
||||||
assert_eq!(result_cell.modifier, Modifier::UNDERLINED);
|
assert_eq!(result_cell.modifier, Modifier::UNDERLINED);
|
||||||
}
|
}
|
||||||
// The rest is black on magenta
|
// The rest is red on black
|
||||||
_ => {
|
_ => {
|
||||||
assert_eq!(result_cell.bg, Color::Magenta);
|
assert_eq!(result_cell.bg, Color::Magenta);
|
||||||
assert_eq!(result_cell.fg, Color::Black);
|
assert_eq!(result_cell.fg, Color::Black);
|
||||||
@@ -498,8 +532,10 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
/// Test that the help panel gets drawn with custom colors
|
/// Test that the help panel gets drawn with custom colors
|
||||||
|
/// This test is incredibly annoying
|
||||||
|
/// println!("{} {} {} {} {}", row_index, result_cell_index, result_cell.symbol(), result_cell.bg, result_cell.fg);
|
||||||
fn test_draw_blocks_help_custom_colors() {
|
fn test_draw_blocks_help_custom_colors() {
|
||||||
let mut setup = test_setup(87, 35, true, true);
|
let mut setup = test_setup(87, 37, true, true);
|
||||||
let mut colors = AppColors::new();
|
let mut colors = AppColors::new();
|
||||||
let tz = setup.app_data.lock().config.timezone.clone();
|
let tz = setup.app_data.lock().config.timezone.clone();
|
||||||
|
|
||||||
@@ -521,34 +557,34 @@ mod tests {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
assert_snapshot!(setup.terminal.backend());
|
assert_snapshot!(setup.terminal.backend());
|
||||||
|
|
||||||
for (row_index, result_row) in get_result(&setup) {
|
for (row_index, result_row) in get_result(&setup) {
|
||||||
for (result_cell_index, result_cell) in result_row.iter().enumerate() {
|
for (result_cell_index, result_cell) in result_row.iter().enumerate() {
|
||||||
match (row_index, result_cell_index) {
|
match (row_index, result_cell_index) {
|
||||||
// first & last row, and first & last char on each row, is reset/reset, making sure that the help info is centered in the given area
|
// first & last row, and first & last char on each row, is reset/reset, making sure that the help info is centered in the given area
|
||||||
(0 | 34, _) | (0..=33, 0 | 86) => {
|
(0 | 36, _) | (0..=35, 0 | 86) => {
|
||||||
assert_eq!(result_cell.bg, Color::Reset);
|
assert_eq!(result_cell.bg, Color::Reset);
|
||||||
assert_eq!(result_cell.fg, Color::Reset);
|
assert_eq!(result_cell.fg, Color::Reset);
|
||||||
}
|
}
|
||||||
// border is red on black
|
// border is red on black
|
||||||
(1 | 32, _) | (1..=31, 1 | 85) => {
|
(1 | 34, _) | (1..=31, 1 | 85) => {
|
||||||
assert_eq!(result_cell.bg, Color::Black);
|
assert_eq!(result_cell.bg, Color::Black);
|
||||||
assert_eq!(result_cell.fg, Color::Red);
|
assert_eq!(result_cell.fg, Color::Red);
|
||||||
}
|
}
|
||||||
// oxker logo && description
|
// Buttons
|
||||||
(2..=10, 2..=85)
|
(2..=10, 2..=85)
|
||||||
| (12, 19..=66)
|
| (12, 19..=66)
|
||||||
| (14, 2..=10 | 13..=27)
|
| (14, 2..=10 | 13..=27)
|
||||||
| (15, 2..=10 | 13..=21 | 24..=40 | 43..=56)
|
| (15, 2..=10 | 13..=21 | 24..=40 | 43..=56)
|
||||||
| (16 | 23, 2..=12)
|
| (16 | 27 | 29, 2..=10)
|
||||||
| (17..=20 | 22 | 25 | 27, 2..=8)
|
| (17, 2..=11)
|
||||||
| (21, 2..=9 | 12..=18)
|
| (18 | 26, 2..=12)
|
||||||
| (24 | 26, 2..=10) => {
|
| (19 | 20 | 21 | 22 | 24 | 25 | 28 | 23 | 30, 2..=8)
|
||||||
|
| (24, 2..=9 | 12..=18) => {
|
||||||
assert_eq!(result_cell.bg, Color::Black);
|
assert_eq!(result_cell.bg, Color::Black);
|
||||||
assert_eq!(result_cell.fg, Color::Yellow);
|
assert_eq!(result_cell.fg, Color::Yellow);
|
||||||
}
|
}
|
||||||
// The URL is yellow and underlined
|
// The URL is yellow and underlined
|
||||||
(30, 25..=60) => {
|
(33, 25..=60) => {
|
||||||
assert_eq!(result_cell.bg, Color::Black);
|
assert_eq!(result_cell.bg, Color::Black);
|
||||||
assert_eq!(result_cell.fg, Color::Yellow);
|
assert_eq!(result_cell.fg, Color::Yellow);
|
||||||
assert_eq!(result_cell.modifier, Modifier::UNDERLINED);
|
assert_eq!(result_cell.modifier, Modifier::UNDERLINED);
|
||||||
@@ -566,39 +602,43 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
/// Help panel will show custom keymap if in use, with one definition for each entry
|
/// Help panel will show custom keymap if in use, with one definition for each entry
|
||||||
fn test_draw_blocks_help_custom_keymap_one_definition() {
|
fn test_draw_blocks_help_custom_keymap_one_definition() {
|
||||||
let mut setup = test_setup(98, 47, true, true);
|
let mut setup = test_setup(98, 50, true, true);
|
||||||
|
|
||||||
let input = Keymap {
|
let input = Keymap {
|
||||||
clear: (KeyCode::Char('a'), None),
|
clear: (KeyCode::Char('a'), None),
|
||||||
|
delete_confirm: (KeyCode::Char('b'), None),
|
||||||
delete_deny: (KeyCode::Char('c'), None),
|
delete_deny: (KeyCode::Char('c'), None),
|
||||||
delete_confirm: (KeyCode::Char('e'), None),
|
exec: (KeyCode::Char('d'), None),
|
||||||
exec: (KeyCode::Char('g'), None),
|
filter_mode: (KeyCode::Char('e'), None),
|
||||||
log_section_height_decrease: (KeyCode::Char('z'), None),
|
force_redraw: (KeyCode::Char('f'), None),
|
||||||
log_section_height_increase: (KeyCode::Char('x'), None),
|
log_scroll_back: (KeyCode::Char('g'), None),
|
||||||
log_section_toggle: (KeyCode::Char('W'), None),
|
log_scroll_forward: (KeyCode::Char('h'), None),
|
||||||
filter_mode: (KeyCode::Char('i'), None),
|
log_section_height_decrease: (KeyCode::Char('i'), None),
|
||||||
quit: (KeyCode::Char('k'), None),
|
log_section_height_increase: (KeyCode::Char('j'), None),
|
||||||
|
log_section_toggle: (KeyCode::Char('k'), None),
|
||||||
|
quit: (KeyCode::Char('l'), None),
|
||||||
save_logs: (KeyCode::Char('m'), None),
|
save_logs: (KeyCode::Char('m'), None),
|
||||||
scroll_down_many: (KeyCode::Char('o'), None),
|
scroll_down_many: (KeyCode::Char('n'), None),
|
||||||
scroll_down_one: (KeyCode::Char('q'), None),
|
scroll_down_one: (KeyCode::Char('o'), None),
|
||||||
scroll_end: (KeyCode::Char('s'), None),
|
scroll_end: (KeyCode::Char('p'), None),
|
||||||
scroll_start: (KeyCode::Char('u'), None),
|
scroll_many: KeyModifiers::ALT,
|
||||||
scroll_up_many: (KeyCode::Char('w'), None),
|
scroll_start: (KeyCode::Char('q'), None),
|
||||||
scroll_up_one: (KeyCode::Char('y'), None),
|
scroll_up_many: (KeyCode::Char('r'), None),
|
||||||
select_next_panel: (KeyCode::Char('0'), None),
|
scroll_up_one: (KeyCode::Char('s'), None),
|
||||||
select_previous_panel: (KeyCode::Char('2'), None),
|
select_next_panel: (KeyCode::Char('t'), None),
|
||||||
sort_by_name: (KeyCode::Char('4'), None),
|
select_previous_panel: (KeyCode::Char('u'), None),
|
||||||
sort_by_state: (KeyCode::Char('6'), None),
|
sort_by_cpu: (KeyCode::Char('v'), None),
|
||||||
sort_by_status: (KeyCode::Char('8'), None),
|
sort_by_id: (KeyCode::Char('w'), None),
|
||||||
sort_by_cpu: (KeyCode::F(1), None),
|
sort_by_image: (KeyCode::Char('x'), None),
|
||||||
sort_by_memory: (KeyCode::Char('#'), None),
|
sort_by_memory: (KeyCode::Char('y'), None),
|
||||||
sort_by_id: (KeyCode::Char('/'), None),
|
sort_by_name: (KeyCode::Char('z'), None),
|
||||||
sort_by_image: (KeyCode::Char(','), None),
|
sort_by_rx: (KeyCode::Char('0'), None),
|
||||||
sort_by_rx: (KeyCode::Char('.'), None),
|
sort_by_state: (KeyCode::Char('1'), None),
|
||||||
sort_by_tx: (KeyCode::Insert, None),
|
sort_by_status: (KeyCode::Char('2'), None),
|
||||||
sort_reset: (KeyCode::Up, None),
|
sort_by_tx: (KeyCode::Char('3'), None),
|
||||||
toggle_help: (KeyCode::Home, None),
|
sort_reset: (KeyCode::Char('4'), None),
|
||||||
toggle_mouse_capture: (KeyCode::PageDown, None),
|
toggle_help: (KeyCode::Char('5'), None),
|
||||||
|
toggle_mouse_capture: (KeyCode::Char('6'), None),
|
||||||
};
|
};
|
||||||
|
|
||||||
setup
|
setup
|
||||||
@@ -614,39 +654,43 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
/// Help panel will show custom keymap if in use, with two definition for each entry
|
/// Help panel will show custom keymap if in use, with two definition for each entry
|
||||||
fn test_draw_blocks_help_custom_keymap_two_definitions() {
|
fn test_draw_blocks_help_custom_keymap_two_definitions() {
|
||||||
let mut setup = test_setup(110, 47, true, true);
|
let mut setup = test_setup(110, 50, true, true);
|
||||||
|
|
||||||
let keymap = Keymap {
|
let keymap = Keymap {
|
||||||
clear: (KeyCode::Char('a'), Some(KeyCode::Char('b'))),
|
clear: (KeyCode::Char('a'), Some(KeyCode::Char('A'))),
|
||||||
delete_deny: (KeyCode::Char('c'), Some(KeyCode::Char('d'))),
|
delete_confirm: (KeyCode::Char('b'), Some(KeyCode::Char('B'))),
|
||||||
delete_confirm: (KeyCode::Char('e'), Some(KeyCode::Char('f'))),
|
delete_deny: (KeyCode::Char('c'), Some(KeyCode::Char('C'))),
|
||||||
exec: (KeyCode::Char('g'), Some(KeyCode::Char('h'))),
|
exec: (KeyCode::Char('d'), Some(KeyCode::Char('D'))),
|
||||||
log_section_height_decrease: (KeyCode::Char('A'), Some(KeyCode::Char('Z'))),
|
filter_mode: (KeyCode::Char('e'), Some(KeyCode::Char('E'))),
|
||||||
log_section_height_increase: (KeyCode::Char('B'), Some(KeyCode::Char('X'))),
|
force_redraw: (KeyCode::Char('f'), Some(KeyCode::Char('F'))),
|
||||||
log_section_toggle: (KeyCode::Char('C'), Some(KeyCode::Char('W'))),
|
log_scroll_back: (KeyCode::Char('f'), Some(KeyCode::Char('F'))),
|
||||||
filter_mode: (KeyCode::Char('i'), Some(KeyCode::Char('j'))),
|
log_scroll_forward: (KeyCode::Char('g'), Some(KeyCode::Char('G'))),
|
||||||
quit: (KeyCode::Char('k'), Some(KeyCode::Char('l'))),
|
log_section_height_decrease: (KeyCode::Char('h'), Some(KeyCode::Char('H'))),
|
||||||
save_logs: (KeyCode::Char('m'), Some(KeyCode::Char('n'))),
|
log_section_height_increase: (KeyCode::Char('i'), Some(KeyCode::Char('I'))),
|
||||||
scroll_down_many: (KeyCode::Char('o'), Some(KeyCode::Char('p'))),
|
log_section_toggle: (KeyCode::Char('j'), Some(KeyCode::Char('J'))),
|
||||||
scroll_down_one: (KeyCode::Char('q'), Some(KeyCode::Char('r'))),
|
quit: (KeyCode::Char('k'), Some(KeyCode::Char('K'))),
|
||||||
scroll_end: (KeyCode::Char('s'), Some(KeyCode::Char('t'))),
|
save_logs: (KeyCode::Char('l'), Some(KeyCode::Char('L'))),
|
||||||
scroll_start: (KeyCode::Char('u'), Some(KeyCode::Char('v'))),
|
scroll_down_many: (KeyCode::Char('m'), Some(KeyCode::Char('M'))),
|
||||||
scroll_up_many: (KeyCode::Char('w'), Some(KeyCode::Char('x'))),
|
scroll_down_one: (KeyCode::Char('n'), Some(KeyCode::Char('N'))),
|
||||||
scroll_up_one: (KeyCode::Char('y'), Some(KeyCode::Char('z'))),
|
scroll_end: (KeyCode::Char('o'), Some(KeyCode::Char('O'))),
|
||||||
select_next_panel: (KeyCode::Char('0'), Some(KeyCode::Char('1'))),
|
scroll_many: KeyModifiers::ALT,
|
||||||
select_previous_panel: (KeyCode::Char('2'), Some(KeyCode::Char('3'))),
|
scroll_start: (KeyCode::Char('p'), Some(KeyCode::Char('P'))),
|
||||||
sort_by_name: (KeyCode::Char('4'), Some(KeyCode::Char('5'))),
|
scroll_up_many: (KeyCode::Char('q'), Some(KeyCode::Char('Q'))),
|
||||||
sort_by_state: (KeyCode::Char('6'), Some(KeyCode::Char('7'))),
|
scroll_up_one: (KeyCode::Char('r'), Some(KeyCode::Char('R'))),
|
||||||
sort_by_status: (KeyCode::Char('8'), Some(KeyCode::Char('9'))),
|
select_next_panel: (KeyCode::Char('s'), Some(KeyCode::Char('S'))),
|
||||||
sort_by_cpu: (KeyCode::F(1), Some(KeyCode::F(12))),
|
select_previous_panel: (KeyCode::Char('t'), Some(KeyCode::Char('T'))),
|
||||||
sort_by_memory: (KeyCode::Char('#'), Some(KeyCode::Char('-'))),
|
sort_by_cpu: (KeyCode::Char('u'), Some(KeyCode::Char('U'))),
|
||||||
sort_by_id: (KeyCode::Char('/'), Some(KeyCode::Char('='))),
|
sort_by_id: (KeyCode::Char('v'), Some(KeyCode::Char('V'))),
|
||||||
sort_by_image: (KeyCode::Char(','), Some(KeyCode::Char('\\'))),
|
sort_by_image: (KeyCode::Char('w'), Some(KeyCode::Char('W'))),
|
||||||
sort_by_rx: (KeyCode::Char('.'), Some(KeyCode::Char(']'))),
|
sort_by_memory: (KeyCode::Char('x'), Some(KeyCode::Char('X'))),
|
||||||
sort_by_tx: (KeyCode::Insert, Some(KeyCode::BackTab)),
|
sort_by_name: (KeyCode::Char('y'), Some(KeyCode::Char('Y'))),
|
||||||
sort_reset: (KeyCode::Up, Some(KeyCode::Down)),
|
sort_by_rx: (KeyCode::Char('z'), Some(KeyCode::Char('Z'))),
|
||||||
toggle_help: (KeyCode::Home, Some(KeyCode::End)),
|
sort_by_state: (KeyCode::Char('0'), Some(KeyCode::Char('9'))),
|
||||||
toggle_mouse_capture: (KeyCode::PageDown, Some(KeyCode::PageUp)),
|
sort_by_status: (KeyCode::Char('1'), Some(KeyCode::Char('8'))),
|
||||||
|
sort_by_tx: (KeyCode::Char('2'), Some(KeyCode::Char('7'))),
|
||||||
|
sort_reset: (KeyCode::Char('3'), Some(KeyCode::Char('6'))),
|
||||||
|
toggle_help: (KeyCode::Char('4'), Some(KeyCode::Char('5'))),
|
||||||
|
toggle_mouse_capture: (KeyCode::Char('5'), Some(KeyCode::PageDown)),
|
||||||
};
|
};
|
||||||
|
|
||||||
setup
|
setup
|
||||||
@@ -662,39 +706,43 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
/// Help panel will show custom keymap if in use, with either one or two definition for each entry
|
/// Help panel will show custom keymap if in use, with either one or two definition for each entry
|
||||||
fn test_draw_blocks_help_one_and_two_definitions() {
|
fn test_draw_blocks_help_one_and_two_definitions() {
|
||||||
let mut setup = test_setup(110, 47, true, true);
|
let mut setup = test_setup(110, 50, true, true);
|
||||||
|
|
||||||
let keymap = Keymap {
|
let keymap = Keymap {
|
||||||
clear: (KeyCode::Char('a'), Some(KeyCode::Char('b'))),
|
clear: (KeyCode::Char('a'), Some(KeyCode::Char('A'))),
|
||||||
delete_deny: (KeyCode::Char('c'), None),
|
delete_confirm: (KeyCode::Char('b'), None),
|
||||||
delete_confirm: (KeyCode::Char('e'), Some(KeyCode::Char('f'))),
|
delete_deny: (KeyCode::Char('c'), Some(KeyCode::Char('C'))),
|
||||||
exec: (KeyCode::Char('g'), None),
|
exec: (KeyCode::Char('d'), None),
|
||||||
filter_mode: (KeyCode::Char('i'), Some(KeyCode::Char('j'))),
|
filter_mode: (KeyCode::Char('e'), Some(KeyCode::Char('E'))),
|
||||||
log_section_height_decrease: (KeyCode::Char('A'), Some(KeyCode::Char('Z'))),
|
force_redraw: (KeyCode::Char('f'), None),
|
||||||
log_section_height_increase: (KeyCode::Char('B'), Some(KeyCode::Char('X'))),
|
log_scroll_back: (KeyCode::Char('g'), Some(KeyCode::Char('G'))),
|
||||||
log_section_toggle: (KeyCode::Char('C'), Some(KeyCode::Char('W'))),
|
log_scroll_forward: (KeyCode::Char('h'), None),
|
||||||
quit: (KeyCode::Char('k'), None),
|
log_section_height_decrease: (KeyCode::Char('i'), Some(KeyCode::Char('I'))),
|
||||||
save_logs: (KeyCode::Char('m'), Some(KeyCode::Char('n'))),
|
log_section_height_increase: (KeyCode::Char('j'), None),
|
||||||
scroll_down_many: (KeyCode::Char('o'), None),
|
log_section_toggle: (KeyCode::Char('k'), Some(KeyCode::Char('K'))),
|
||||||
scroll_down_one: (KeyCode::Char('q'), Some(KeyCode::Char('r'))),
|
quit: (KeyCode::Char('l'), None),
|
||||||
scroll_end: (KeyCode::Char('s'), None),
|
save_logs: (KeyCode::Char('m'), Some(KeyCode::Char('M'))),
|
||||||
scroll_start: (KeyCode::Char('u'), Some(KeyCode::Char('v'))),
|
scroll_down_many: (KeyCode::Char('n'), None),
|
||||||
scroll_up_many: (KeyCode::Char('w'), None),
|
scroll_down_one: (KeyCode::Char('o'), Some(KeyCode::Char('O'))),
|
||||||
scroll_up_one: (KeyCode::Char('y'), Some(KeyCode::Char('z'))),
|
scroll_end: (KeyCode::Char('p'), None),
|
||||||
select_next_panel: (KeyCode::Char('0'), None),
|
scroll_many: KeyModifiers::ALT,
|
||||||
select_previous_panel: (KeyCode::Char('2'), Some(KeyCode::Char('3'))),
|
scroll_start: (KeyCode::Char('q'), Some(KeyCode::Char('Q'))),
|
||||||
sort_by_name: (KeyCode::Char('4'), None),
|
scroll_up_many: (KeyCode::Char('r'), None),
|
||||||
sort_by_state: (KeyCode::Char('6'), Some(KeyCode::Char('7'))),
|
scroll_up_one: (KeyCode::Char('s'), Some(KeyCode::Char('S'))),
|
||||||
sort_by_status: (KeyCode::Char('8'), None),
|
select_next_panel: (KeyCode::Char('t'), None),
|
||||||
sort_by_cpu: (KeyCode::F(1), Some(KeyCode::F(12))),
|
select_previous_panel: (KeyCode::Char('u'), Some(KeyCode::Char('U'))),
|
||||||
sort_by_memory: (KeyCode::Char('#'), None),
|
sort_by_cpu: (KeyCode::Char('v'), None),
|
||||||
sort_by_id: (KeyCode::Char('/'), Some(KeyCode::Char('='))),
|
sort_by_id: (KeyCode::Char('w'), Some(KeyCode::Char('W'))),
|
||||||
sort_by_image: (KeyCode::Char(','), None),
|
sort_by_image: (KeyCode::Char('x'), None),
|
||||||
sort_by_rx: (KeyCode::Char('.'), Some(KeyCode::Char(']'))),
|
sort_by_memory: (KeyCode::Char('y'), Some(KeyCode::Char('Y'))),
|
||||||
sort_by_tx: (KeyCode::Insert, None),
|
sort_by_name: (KeyCode::Char('z'), None),
|
||||||
sort_reset: (KeyCode::Up, Some(KeyCode::Down)),
|
sort_by_rx: (KeyCode::Char('0'), Some(KeyCode::Char('9'))),
|
||||||
toggle_help: (KeyCode::Home, None),
|
sort_by_state: (KeyCode::Char('1'), None),
|
||||||
toggle_mouse_capture: (KeyCode::PageDown, Some(KeyCode::PageUp)),
|
sort_by_status: (KeyCode::Char('2'), Some(KeyCode::Char('7'))),
|
||||||
|
sort_by_tx: (KeyCode::Char('3'), None),
|
||||||
|
sort_reset: (KeyCode::Char('4'), Some(KeyCode::Char('5'))),
|
||||||
|
toggle_help: (KeyCode::Char('5'), None),
|
||||||
|
toggle_mouse_capture: (KeyCode::Char('6'), Some(KeyCode::Char('7'))),
|
||||||
};
|
};
|
||||||
|
|
||||||
let tz = setup.app_data.lock().config.timezone.clone();
|
let tz = setup.app_data.lock().config.timezone.clone();
|
||||||
@@ -731,10 +779,10 @@ mod tests {
|
|||||||
for (row_index, result_row) in get_result(&setup) {
|
for (row_index, result_row) in get_result(&setup) {
|
||||||
for (result_cell_index, result_cell) in result_row.iter().enumerate() {
|
for (result_cell_index, result_cell) in result_row.iter().enumerate() {
|
||||||
match (row_index, result_cell_index) {
|
match (row_index, result_cell_index) {
|
||||||
(14, 31..=45) => {
|
(13, 31..=45) => {
|
||||||
assert_eq!(result_cell.fg, AppColors::new().popup_help.text);
|
assert_eq!(result_cell.fg, AppColors::new().popup_help.text);
|
||||||
}
|
}
|
||||||
(14, 46..=55) => {
|
(13, 46..=55) => {
|
||||||
assert_eq!(result_cell.fg, AppColors::new().popup_help.text_highlight);
|
assert_eq!(result_cell.fg, AppColors::new().popup_help.text_highlight);
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ pub fn draw(
|
|||||||
f.render_widget(paragraph, area);
|
f.render_widget(paragraph, area);
|
||||||
} else {
|
} else {
|
||||||
let padding = usize::from(area.height / 5);
|
let padding = usize::from(area.height / 5);
|
||||||
let logs = app_data.lock().get_logs(area.height, padding);
|
let logs = app_data.lock().get_logs(area.as_size(), padding);
|
||||||
if logs.is_empty() {
|
if logs.is_empty() {
|
||||||
let mut paragraph = Paragraph::new("no logs found")
|
let mut paragraph = Paragraph::new("no logs found")
|
||||||
.block(block)
|
.block(block)
|
||||||
@@ -356,7 +356,6 @@ mod tests {
|
|||||||
insert_logs(&setup);
|
insert_logs(&setup);
|
||||||
|
|
||||||
let fd = FrameData::from((&setup.app_data, &setup.gui_state));
|
let fd = FrameData::from((&setup.app_data, &setup.gui_state));
|
||||||
|
|
||||||
setup
|
setup
|
||||||
.terminal
|
.terminal
|
||||||
.draw(|f| {
|
.draw(|f| {
|
||||||
|
|||||||
+23
-14
@@ -72,7 +72,6 @@ pub fn max_line_width(text: &str) -> usize {
|
|||||||
.max()
|
.max()
|
||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generate block, add a border if is the selected panel,
|
/// Generate block, add a border if is the selected panel,
|
||||||
/// add custom title based on state of each panel
|
/// add custom title based on state of each panel
|
||||||
fn generate_block<'a>(
|
fn generate_block<'a>(
|
||||||
@@ -101,7 +100,15 @@ fn generate_block<'a>(
|
|||||||
let mut block = Block::default()
|
let mut block = Block::default()
|
||||||
.borders(Borders::ALL)
|
.borders(Borders::ALL)
|
||||||
.border_type(BorderType::Rounded)
|
.border_type(BorderType::Rounded)
|
||||||
.title(title);
|
.title(ratatui::text::Line::from(title).left_aligned());
|
||||||
|
|
||||||
|
if panel == SelectablePanel::Logs {
|
||||||
|
if let Some(x) = fd.scroll_title.as_ref() {
|
||||||
|
block = block
|
||||||
|
.title_bottom(x.to_owned())
|
||||||
|
.title_alignment(ratatui::layout::Alignment::Right);
|
||||||
|
}
|
||||||
|
}
|
||||||
if !fd.status.contains(&Status::Filter) {
|
if !fd.status.contains(&Status::Filter) {
|
||||||
if fd.selected_panel == panel {
|
if fd.selected_panel == panel {
|
||||||
block = block.border_style(Style::default().fg(colors.borders.selected));
|
block = block.border_style(Style::default().fg(colors.borders.selected));
|
||||||
@@ -151,7 +158,7 @@ pub mod tests {
|
|||||||
/// Create a FrameData struct from two Arc<mutex>'s, instead of from UI
|
/// Create a FrameData struct from two Arc<mutex>'s, instead of from UI
|
||||||
impl From<(&Arc<Mutex<AppData>>, &Arc<Mutex<GuiState>>)> for FrameData {
|
impl From<(&Arc<Mutex<AppData>>, &Arc<Mutex<GuiState>>)> for FrameData {
|
||||||
fn from(data: (&Arc<Mutex<AppData>>, &Arc<Mutex<GuiState>>)) -> Self {
|
fn from(data: (&Arc<Mutex<AppData>>, &Arc<Mutex<GuiState>>)) -> Self {
|
||||||
let (app_data, gui_data) = (data.0.lock(), data.1.lock());
|
let (mut app_data, gui_data) = (data.0.lock(), data.1.lock());
|
||||||
|
|
||||||
// let container_section_height = app_data.get_container_len();
|
// let container_section_height = app_data.get_container_len();
|
||||||
// let container_section_height = if container_section_height < 12 {
|
// let container_section_height = if container_section_height < 12 {
|
||||||
@@ -178,6 +185,7 @@ pub mod tests {
|
|||||||
loading_icon: gui_data.get_loading().to_string(),
|
loading_icon: gui_data.get_loading().to_string(),
|
||||||
log_height: gui_data.get_log_height(),
|
log_height: gui_data.get_log_height(),
|
||||||
log_title: app_data.get_log_title(),
|
log_title: app_data.get_log_title(),
|
||||||
|
scroll_title: app_data.get_scroll_title(gui_data.get_screen_width()),
|
||||||
port_max_lens: app_data.get_longest_port(),
|
port_max_lens: app_data.get_longest_port(),
|
||||||
ports: app_data.get_selected_ports(),
|
ports: app_data.get_selected_ports(),
|
||||||
selected_panel: gui_data.get_selected_panel(),
|
selected_panel: gui_data.get_selected_panel(),
|
||||||
@@ -208,6 +216,7 @@ pub mod tests {
|
|||||||
let gui_state = Arc::new(Mutex::new(gui_state));
|
let gui_state = Arc::new(Mutex::new(gui_state));
|
||||||
let fd = FrameData::from((&app_data, &gui_state));
|
let fd = FrameData::from((&app_data, &gui_state));
|
||||||
let area = Rect::new(0, 0, w, h);
|
let area = Rect::new(0, 0, w, h);
|
||||||
|
gui_state.lock().set_screen_width(w);
|
||||||
TuiTestSetup {
|
TuiTestSetup {
|
||||||
app_data,
|
app_data,
|
||||||
gui_state,
|
gui_state,
|
||||||
@@ -220,9 +229,9 @@ pub mod tests {
|
|||||||
|
|
||||||
/// Just a shorthand for when enumerating over result cells
|
/// Just a shorthand for when enumerating over result cells
|
||||||
pub fn get_result(
|
pub fn get_result(
|
||||||
setup: &TuiTestSetup,
|
setup: &'_ TuiTestSetup,
|
||||||
// w: u16,
|
// w: u16,
|
||||||
) -> std::iter::Enumerate<std::slice::Chunks<ratatui::buffer::Cell>> {
|
) -> std::iter::Enumerate<std::slice::Chunks<'_, ratatui::buffer::Cell>> {
|
||||||
setup
|
setup
|
||||||
.terminal
|
.terminal
|
||||||
.backend()
|
.backend()
|
||||||
@@ -276,7 +285,7 @@ pub mod tests {
|
|||||||
setup.app_data.lock().containers.items[0]
|
setup.app_data.lock().containers.items[0]
|
||||||
.ports
|
.ports
|
||||||
.push(ContainerPorts {
|
.push(ContainerPorts {
|
||||||
ip: Some(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1))),
|
ip: Some(IpAddr::V4(Ipv4Addr::LOCALHOST)),
|
||||||
private: 8003,
|
private: 8003,
|
||||||
public: Some(8003),
|
public: Some(8003),
|
||||||
});
|
});
|
||||||
@@ -305,7 +314,7 @@ pub mod tests {
|
|||||||
setup.app_data.lock().containers.items[1]
|
setup.app_data.lock().containers.items[1]
|
||||||
.ports
|
.ports
|
||||||
.push(ContainerPorts {
|
.push(ContainerPorts {
|
||||||
ip: Some(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1))),
|
ip: Some(IpAddr::V4(Ipv4Addr::LOCALHOST)),
|
||||||
private: 8003,
|
private: 8003,
|
||||||
public: Some(8003),
|
public: Some(8003),
|
||||||
});
|
});
|
||||||
@@ -340,7 +349,7 @@ pub mod tests {
|
|||||||
setup.app_data.lock().containers.items[0]
|
setup.app_data.lock().containers.items[0]
|
||||||
.ports
|
.ports
|
||||||
.push(ContainerPorts {
|
.push(ContainerPorts {
|
||||||
ip: Some(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1))),
|
ip: Some(IpAddr::V4(Ipv4Addr::LOCALHOST)),
|
||||||
private: 8003,
|
private: 8003,
|
||||||
public: Some(8003),
|
public: Some(8003),
|
||||||
});
|
});
|
||||||
@@ -373,7 +382,7 @@ pub mod tests {
|
|||||||
setup.app_data.lock().containers.items[0]
|
setup.app_data.lock().containers.items[0]
|
||||||
.ports
|
.ports
|
||||||
.push(ContainerPorts {
|
.push(ContainerPorts {
|
||||||
ip: Some(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1))),
|
ip: Some(IpAddr::V4(Ipv4Addr::LOCALHOST)),
|
||||||
private: 8003,
|
private: 8003,
|
||||||
public: Some(8003),
|
public: Some(8003),
|
||||||
});
|
});
|
||||||
@@ -402,7 +411,7 @@ pub mod tests {
|
|||||||
setup.app_data.lock().containers.items[0]
|
setup.app_data.lock().containers.items[0]
|
||||||
.ports
|
.ports
|
||||||
.push(ContainerPorts {
|
.push(ContainerPorts {
|
||||||
ip: Some(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1))),
|
ip: Some(IpAddr::V4(Ipv4Addr::LOCALHOST)),
|
||||||
private: 8003,
|
private: 8003,
|
||||||
public: Some(8003),
|
public: Some(8003),
|
||||||
});
|
});
|
||||||
@@ -434,7 +443,7 @@ pub mod tests {
|
|||||||
setup.app_data.lock().containers.items[0]
|
setup.app_data.lock().containers.items[0]
|
||||||
.ports
|
.ports
|
||||||
.push(ContainerPorts {
|
.push(ContainerPorts {
|
||||||
ip: Some(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1))),
|
ip: Some(IpAddr::V4(Ipv4Addr::LOCALHOST)),
|
||||||
private: 8003,
|
private: 8003,
|
||||||
public: Some(8003),
|
public: Some(8003),
|
||||||
});
|
});
|
||||||
@@ -464,7 +473,7 @@ pub mod tests {
|
|||||||
setup.app_data.lock().containers.items[0]
|
setup.app_data.lock().containers.items[0]
|
||||||
.ports
|
.ports
|
||||||
.push(ContainerPorts {
|
.push(ContainerPorts {
|
||||||
ip: Some(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1))),
|
ip: Some(IpAddr::V4(Ipv4Addr::LOCALHOST)),
|
||||||
private: 8003,
|
private: 8003,
|
||||||
public: Some(8003),
|
public: Some(8003),
|
||||||
});
|
});
|
||||||
@@ -498,7 +507,7 @@ pub mod tests {
|
|||||||
setup.app_data.lock().containers.items[0]
|
setup.app_data.lock().containers.items[0]
|
||||||
.ports
|
.ports
|
||||||
.push(ContainerPorts {
|
.push(ContainerPorts {
|
||||||
ip: Some(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1))),
|
ip: Some(IpAddr::V4(Ipv4Addr::LOCALHOST)),
|
||||||
private: 8003,
|
private: 8003,
|
||||||
public: Some(8003),
|
public: Some(8003),
|
||||||
});
|
});
|
||||||
@@ -530,7 +539,7 @@ pub mod tests {
|
|||||||
setup.app_data.lock().containers.items[0]
|
setup.app_data.lock().containers.items[0]
|
||||||
.ports
|
.ports
|
||||||
.push(ContainerPorts {
|
.push(ContainerPorts {
|
||||||
ip: Some(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1))),
|
ip: Some(IpAddr::V4(Ipv4Addr::LOCALHOST)),
|
||||||
private: 8003,
|
private: 8003,
|
||||||
public: Some(8003),
|
public: Some(8003),
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -182,7 +182,7 @@ mod tests {
|
|||||||
setup.app_data.lock().containers.items[0]
|
setup.app_data.lock().containers.items[0]
|
||||||
.ports
|
.ports
|
||||||
.push(ContainerPorts {
|
.push(ContainerPorts {
|
||||||
ip: Some(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1))),
|
ip: Some(IpAddr::V4(Ipv4Addr::LOCALHOST)),
|
||||||
private: 8003,
|
private: 8003,
|
||||||
public: Some(8003),
|
public: Some(8003),
|
||||||
});
|
});
|
||||||
|
|||||||
+4
-3
@@ -1,6 +1,5 @@
|
|||||||
---
|
---
|
||||||
source: src/ui/draw_blocks/help.rs
|
source: src/ui/draw_blocks/help.rs
|
||||||
assertion_line: 456
|
|
||||||
expression: setup.terminal.backend()
|
expression: setup.terminal.backend()
|
||||||
---
|
---
|
||||||
" "
|
" "
|
||||||
@@ -18,9 +17,12 @@ expression: setup.terminal.backend()
|
|||||||
" │ A simple tui to view & control docker containers │ "
|
" │ A simple tui to view & control docker containers │ "
|
||||||
" │ │ "
|
" │ │ "
|
||||||
" │ ( tab ) or ( shift+tab ) change panels │ "
|
" │ ( tab ) or ( shift+tab ) change panels │ "
|
||||||
" │ ( ↑ ↓ ) or ( j k ) or ( PgUp PgDown ) or ( Home End ) change selected line │ "
|
" │ ( ↑ ↓ ) or ( j k ) or ( PgUp PgDown ) or ( Home End ) scroll vertically │ "
|
||||||
|
" │ ( ← → ) horizontal scroll across logs │ "
|
||||||
|
" │ ( ctrl ) increase scroll speed, used in conjuction scroll keys │ "
|
||||||
" │ ( enter ) send docker container command │ "
|
" │ ( enter ) send docker container command │ "
|
||||||
" │ ( e ) exec into a container │ "
|
" │ ( e ) exec into a container │ "
|
||||||
|
" │ ( f ) force clear the screen & redraw the gui │ "
|
||||||
" │ ( h ) toggle this help information - or click heading │ "
|
" │ ( h ) toggle this help information - or click heading │ "
|
||||||
" │ ( s ) save logs to file │ "
|
" │ ( s ) save logs to file │ "
|
||||||
" │ ( m ) toggle mouse capture - if disabled, text on screen can be selected & copied │ "
|
" │ ( m ) toggle mouse capture - if disabled, text on screen can be selected & copied │ "
|
||||||
@@ -35,6 +37,5 @@ expression: setup.terminal.backend()
|
|||||||
" │ currently an early work in progress, all and any input appreciated │ "
|
" │ currently an early work in progress, all and any input appreciated │ "
|
||||||
" │ https://github.com/mrjackwills/oxker │ "
|
" │ https://github.com/mrjackwills/oxker │ "
|
||||||
" │ │ "
|
" │ │ "
|
||||||
" │ │ "
|
|
||||||
" ╰───────────────────────────────────────────────────────────────────────────────────╯ "
|
" ╰───────────────────────────────────────────────────────────────────────────────────╯ "
|
||||||
" "
|
" "
|
||||||
|
|||||||
+4
-2
@@ -17,9 +17,12 @@ expression: setup.terminal.backend()
|
|||||||
" │ A simple tui to view & control docker containers │ "
|
" │ A simple tui to view & control docker containers │ "
|
||||||
" │ │ "
|
" │ │ "
|
||||||
" │ ( tab ) or ( shift+tab ) change panels │ "
|
" │ ( tab ) or ( shift+tab ) change panels │ "
|
||||||
" │ ( ↑ ↓ ) or ( j k ) or ( PgUp PgDown ) or ( Home End ) change selected line │ "
|
" │ ( ↑ ↓ ) or ( j k ) or ( PgUp PgDown ) or ( Home End ) scroll vertically │ "
|
||||||
|
" │ ( ← → ) horizontal scroll across logs │ "
|
||||||
|
" │ ( ctrl ) increase scroll speed, used in conjuction scroll keys │ "
|
||||||
" │ ( enter ) send docker container command │ "
|
" │ ( enter ) send docker container command │ "
|
||||||
" │ ( e ) exec into a container │ "
|
" │ ( e ) exec into a container │ "
|
||||||
|
" │ ( f ) force clear the screen & redraw the gui │ "
|
||||||
" │ ( h ) toggle this help information - or click heading │ "
|
" │ ( h ) toggle this help information - or click heading │ "
|
||||||
" │ ( s ) save logs to file │ "
|
" │ ( s ) save logs to file │ "
|
||||||
" │ ( m ) toggle mouse capture - if disabled, text on screen can be selected & copied │ "
|
" │ ( m ) toggle mouse capture - if disabled, text on screen can be selected & copied │ "
|
||||||
@@ -34,6 +37,5 @@ expression: setup.terminal.backend()
|
|||||||
" │ currently an early work in progress, all and any input appreciated │ "
|
" │ currently an early work in progress, all and any input appreciated │ "
|
||||||
" │ https://github.com/mrjackwills/oxker │ "
|
" │ https://github.com/mrjackwills/oxker │ "
|
||||||
" │ │ "
|
" │ │ "
|
||||||
" │ │ "
|
|
||||||
" ╰───────────────────────────────────────────────────────────────────────────────────╯ "
|
" ╰───────────────────────────────────────────────────────────────────────────────────╯ "
|
||||||
" "
|
" "
|
||||||
|
|||||||
+50
-47
@@ -2,50 +2,53 @@
|
|||||||
source: src/ui/draw_blocks/help.rs
|
source: src/ui/draw_blocks/help.rs
|
||||||
expression: setup.terminal.backend()
|
expression: setup.terminal.backend()
|
||||||
---
|
---
|
||||||
" ╭ 0.00.000 ──────────────────────────────────────────────────────────────────────────────────╮ "
|
" ╭ 0.00.000 ──────────────────────────────────────────────────────────────────────────╮ "
|
||||||
" │ │ "
|
" │ │ "
|
||||||
" │ 88 │ "
|
" │ 88 │ "
|
||||||
" │ 88 │ "
|
" │ 88 │ "
|
||||||
" │ 88 │ "
|
" │ 88 │ "
|
||||||
" │ ,adPPYba, 8b, ,d8 88 ,d8 ,adPPYba, 8b,dPPYba, │ "
|
" │ ,adPPYba, 8b, ,d8 88 ,d8 ,adPPYba, 8b,dPPYba, │ "
|
||||||
" │ a8" "8a `Y8, ,8P' 88 ,a8" a8P_____88 88P' "Y8 │ "
|
" │ a8" "8a `Y8, ,8P' 88 ,a8" a8P_____88 88P' "Y8 │ "
|
||||||
" │ 8b d8 )888( 8888[ 8PP""""""" 88 │ "
|
" │ 8b d8 )888( 8888[ 8PP""""""" 88 │ "
|
||||||
" │ "8a, ,a8" ,d8" "8b, 88`"Yba, "8b, ,aa 88 │ "
|
" │ "8a, ,a8" ,d8" "8b, 88`"Yba, "8b, ,aa 88 │ "
|
||||||
" │ `"YbbdP"' 8P' `Y8 88 `Y8a `"Ybbd8"' 88 │ "
|
" │ `"YbbdP"' 8P' `Y8 88 `Y8a `"Ybbd8"' 88 │ "
|
||||||
" │ │ "
|
" │ │ "
|
||||||
" │ A simple tui to view & control docker containers │ "
|
" │ A simple tui to view & control docker containers │ "
|
||||||
" │ │ "
|
" │ │ "
|
||||||
" │ ( 0 ) select next panel │ "
|
" │ ( t ) select next panel │ "
|
||||||
" │ ( 2 ) select previous panel │ "
|
" │ ( u ) select previous panel │ "
|
||||||
" │ ( q ) scroll list down by one │ "
|
" │ ( o ) scroll list down by one │ "
|
||||||
" │ ( y ) scroll list up by one │ "
|
" │ ( s ) scroll list up by one │ "
|
||||||
" │ ( o ) scroll list down by many │ "
|
" │ ( n ) scroll list down by many │ "
|
||||||
" │ ( w ) scroll list by up many │ "
|
" │ ( r ) scroll list by up many │ "
|
||||||
" │ ( s ) scroll list to end │ "
|
" │ ( p ) scroll list to end │ "
|
||||||
" │ ( u ) scroll list to start │ "
|
" │ ( q ) scroll list to start │ "
|
||||||
" │ ( enter ) send docker container command │ "
|
" │ ( h ) horizontal scroll logs right │ "
|
||||||
" │ ( g ) exec into a container │ "
|
" │ ( g ) horizontal scroll logs left │ "
|
||||||
" │ ( Home ) toggle this help information - or click heading │ "
|
" │ ( Alt ) increase scroll speed, used in conjuction scroll keys │ "
|
||||||
" │ ( m ) save logs to file │ "
|
" │ ( enter ) send docker container command │ "
|
||||||
" │ ( Page Down ) toggle mouse capture - if disabled, text on screen can be selected & copied │ "
|
" │ ( d ) exec into a container │ "
|
||||||
" │ ( i ) enter filter mode │ "
|
" │ ( f ) force clear the screen & redraw the gui │ "
|
||||||
" │ ( Up ) reset container sorting │ "
|
" │ ( 5 ) toggle this help information - or click heading │ "
|
||||||
" │ ( 4 ) sort containers by name │ "
|
" │ ( m ) save logs to file │ "
|
||||||
" │ ( 6 ) sort containers by state │ "
|
" │ ( 6 ) toggle mouse capture - if disabled, text on screen can be selected & copied │ "
|
||||||
" │ ( 8 ) sort containers by status │ "
|
" │ ( e ) enter filter mode │ "
|
||||||
" │ ( F1 ) sort containers by cpu │ "
|
" │ ( 4 ) reset container sorting │ "
|
||||||
" │ ( # ) sort containers by memory │ "
|
" │ ( z ) sort containers by name │ "
|
||||||
" │ ( / ) sort containers by id │ "
|
" │ ( 1 ) sort containers by state │ "
|
||||||
" │ ( , ) sort containers by image │ "
|
" │ ( 2 ) sort containers by status │ "
|
||||||
" │ ( . ) sort containers by rx │ "
|
" │ ( v ) sort containers by cpu │ "
|
||||||
" │ ( Insert ) sort containers by tx │ "
|
" │ ( y ) sort containers by memory │ "
|
||||||
" │ ( z ) decrease log section height │ "
|
" │ ( w ) sort containers by id │ "
|
||||||
" │ ( x ) increase log section height │ "
|
" │ ( x ) sort containers by image │ "
|
||||||
" │ ( W ) toggle log section visibility │ "
|
" │ ( 0 ) sort containers by rx │ "
|
||||||
" │ ( a ) close dialog │ "
|
" │ ( 3 ) sort containers by tx │ "
|
||||||
" │ ( k ) quit at any time │ "
|
" │ ( i ) decrease log section height │ "
|
||||||
" │ │ "
|
" │ ( j ) increase log section height │ "
|
||||||
" │ currently an early work in progress, all and any input appreciated │ "
|
" │ ( k ) toggle log section visibility │ "
|
||||||
" │ https://github.com/mrjackwills/oxker │ "
|
" │ ( a ) close dialog │ "
|
||||||
" │ │ "
|
" │ ( l ) quit at any time │ "
|
||||||
" ╰────────────────────────────────────────────────────────────────────────────────────────────╯ "
|
" │ │ "
|
||||||
|
" │ currently an early work in progress, all and any input appreciated │ "
|
||||||
|
" │ https://github.com/mrjackwills/oxker │ "
|
||||||
|
" ╰────────────────────────────────────────────────────────────────────────────────────╯ "
|
||||||
|
|||||||
+50
-47
@@ -2,50 +2,53 @@
|
|||||||
source: src/ui/draw_blocks/help.rs
|
source: src/ui/draw_blocks/help.rs
|
||||||
expression: setup.terminal.backend()
|
expression: setup.terminal.backend()
|
||||||
---
|
---
|
||||||
" ╭ 0.00.000 ────────────────────────────────────────────────────────────────────────────────────────────────╮ "
|
" ╭ 0.00.000 ──────────────────────────────────────────────────────────────────────────────────────────╮ "
|
||||||
" │ │ "
|
" │ │ "
|
||||||
" │ 88 │ "
|
" │ 88 │ "
|
||||||
" │ 88 │ "
|
" │ 88 │ "
|
||||||
" │ 88 │ "
|
" │ 88 │ "
|
||||||
" │ ,adPPYba, 8b, ,d8 88 ,d8 ,adPPYba, 8b,dPPYba, │ "
|
" │ ,adPPYba, 8b, ,d8 88 ,d8 ,adPPYba, 8b,dPPYba, │ "
|
||||||
" │ a8" "8a `Y8, ,8P' 88 ,a8" a8P_____88 88P' "Y8 │ "
|
" │ a8" "8a `Y8, ,8P' 88 ,a8" a8P_____88 88P' "Y8 │ "
|
||||||
" │ 8b d8 )888( 8888[ 8PP""""""" 88 │ "
|
" │ 8b d8 )888( 8888[ 8PP""""""" 88 │ "
|
||||||
" │ "8a, ,a8" ,d8" "8b, 88`"Yba, "8b, ,aa 88 │ "
|
" │ "8a, ,a8" ,d8" "8b, 88`"Yba, "8b, ,aa 88 │ "
|
||||||
" │ `"YbbdP"' 8P' `Y8 88 `Y8a `"Ybbd8"' 88 │ "
|
" │ `"YbbdP"' 8P' `Y8 88 `Y8a `"Ybbd8"' 88 │ "
|
||||||
" │ │ "
|
" │ │ "
|
||||||
" │ A simple tui to view & control docker containers │ "
|
" │ A simple tui to view & control docker containers │ "
|
||||||
" │ │ "
|
" │ │ "
|
||||||
" │ ( 0 ) or ( 1 ) select next panel │ "
|
" │ ( s ) or ( S ) select next panel │ "
|
||||||
" │ ( 2 ) or ( 3 ) select previous panel │ "
|
" │ ( t ) or ( T ) select previous panel │ "
|
||||||
" │ ( q ) or ( r ) scroll list down by one │ "
|
" │ ( n ) or ( N ) scroll list down by one │ "
|
||||||
" │ ( y ) or ( z ) scroll list up by one │ "
|
" │ ( r ) or ( R ) scroll list up by one │ "
|
||||||
" │ ( o ) or ( p ) scroll list down by many │ "
|
" │ ( m ) or ( M ) scroll list down by many │ "
|
||||||
" │ ( w ) or ( x ) scroll list by up many │ "
|
" │ ( q ) or ( Q ) scroll list by up many │ "
|
||||||
" │ ( s ) or ( t ) scroll list to end │ "
|
" │ ( o ) or ( O ) scroll list to end │ "
|
||||||
" │ ( u ) or ( v ) scroll list to start │ "
|
" │ ( p ) or ( P ) scroll list to start │ "
|
||||||
" │ ( enter ) send docker container command │ "
|
" │ ( g ) or ( G ) horizontal scroll logs right │ "
|
||||||
" │ ( g ) or ( h ) exec into a container │ "
|
" │ ( f ) or ( F ) horizontal scroll logs left │ "
|
||||||
" │ ( Home ) or ( End ) toggle this help information - or click heading │ "
|
" │ ( Alt ) increase scroll speed, used in conjuction scroll keys │ "
|
||||||
" │ ( m ) or ( n ) save logs to file │ "
|
" │ ( enter ) send docker container command │ "
|
||||||
" │ ( Page Down ) or ( Page Up ) toggle mouse capture - if disabled, text on screen can be selected & copied │ "
|
" │ ( d ) or ( D ) exec into a container │ "
|
||||||
" │ ( i ) or ( j ) enter filter mode │ "
|
" │ ( f ) or ( F ) force clear the screen & redraw the gui │ "
|
||||||
" │ ( Up ) or ( Down ) reset container sorting │ "
|
" │ ( 4 ) or ( 5 ) toggle this help information - or click heading │ "
|
||||||
" │ ( 4 ) or ( 5 ) sort containers by name │ "
|
" │ ( l ) or ( L ) save logs to file │ "
|
||||||
" │ ( 6 ) or ( 7 ) sort containers by state │ "
|
" │ ( 5 ) or ( Page Down ) toggle mouse capture - if disabled, text on screen can be selected & copied │ "
|
||||||
" │ ( 8 ) or ( 9 ) sort containers by status │ "
|
" │ ( e ) or ( E ) enter filter mode │ "
|
||||||
" │ ( F1 ) or ( F12 ) sort containers by cpu │ "
|
" │ ( 3 ) or ( 6 ) reset container sorting │ "
|
||||||
" │ ( # ) or ( - ) sort containers by memory │ "
|
" │ ( y ) or ( Y ) sort containers by name │ "
|
||||||
" │ ( / ) or ( = ) sort containers by id │ "
|
" │ ( 0 ) or ( 9 ) sort containers by state │ "
|
||||||
" │ ( , ) or ( \ ) sort containers by image │ "
|
" │ ( 1 ) or ( 8 ) sort containers by status │ "
|
||||||
" │ ( . ) or ( ] ) sort containers by rx │ "
|
" │ ( u ) or ( U ) sort containers by cpu │ "
|
||||||
" │ ( Insert ) or ( Back Tab ) sort containers by tx │ "
|
" │ ( x ) or ( X ) sort containers by memory │ "
|
||||||
" │ ( A ) or ( Z ) decrease log section height │ "
|
" │ ( v ) or ( V ) sort containers by id │ "
|
||||||
" │ ( B ) or ( X ) increase log section height │ "
|
" │ ( w ) or ( W ) sort containers by image │ "
|
||||||
" │ ( C ) or ( W ) toggle log section visibility │ "
|
" │ ( z ) or ( Z ) sort containers by rx │ "
|
||||||
" │ ( a ) or ( b ) close dialog │ "
|
" │ ( 2 ) or ( 7 ) sort containers by tx │ "
|
||||||
" │ ( k ) or ( l ) quit at any time │ "
|
" │ ( h ) or ( H ) decrease log section height │ "
|
||||||
" │ │ "
|
" │ ( i ) or ( I ) increase log section height │ "
|
||||||
" │ currently an early work in progress, all and any input appreciated │ "
|
" │ ( j ) or ( J ) toggle log section visibility │ "
|
||||||
" │ https://github.com/mrjackwills/oxker │ "
|
" │ ( a ) or ( A ) close dialog │ "
|
||||||
" │ │ "
|
" │ ( k ) or ( K ) quit at any time │ "
|
||||||
" ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────╯ "
|
" │ │ "
|
||||||
|
" │ currently an early work in progress, all and any input appreciated │ "
|
||||||
|
" │ https://github.com/mrjackwills/oxker │ "
|
||||||
|
" ╰────────────────────────────────────────────────────────────────────────────────────────────────────╯ "
|
||||||
|
|||||||
+50
-47
@@ -2,50 +2,53 @@
|
|||||||
source: src/ui/draw_blocks/help.rs
|
source: src/ui/draw_blocks/help.rs
|
||||||
expression: setup.terminal.backend()
|
expression: setup.terminal.backend()
|
||||||
---
|
---
|
||||||
" ╭ 0.00.000 ────────────────────────────────────────────────────────────────────────────────────────────────╮ "
|
" ╭ 0.00.000 ──────────────────────────────────────────────────────────────────────────────────╮ "
|
||||||
" │ │ "
|
" │ │ "
|
||||||
" │ 88 │ "
|
" │ 88 │ "
|
||||||
" │ 88 │ "
|
" │ 88 │ "
|
||||||
" │ 88 │ "
|
" │ 88 │ "
|
||||||
" │ ,adPPYba, 8b, ,d8 88 ,d8 ,adPPYba, 8b,dPPYba, │ "
|
" │ ,adPPYba, 8b, ,d8 88 ,d8 ,adPPYba, 8b,dPPYba, │ "
|
||||||
" │ a8" "8a `Y8, ,8P' 88 ,a8" a8P_____88 88P' "Y8 │ "
|
" │ a8" "8a `Y8, ,8P' 88 ,a8" a8P_____88 88P' "Y8 │ "
|
||||||
" │ 8b d8 )888( 8888[ 8PP""""""" 88 │ "
|
" │ 8b d8 )888( 8888[ 8PP""""""" 88 │ "
|
||||||
" │ "8a, ,a8" ,d8" "8b, 88`"Yba, "8b, ,aa 88 │ "
|
" │ "8a, ,a8" ,d8" "8b, 88`"Yba, "8b, ,aa 88 │ "
|
||||||
" │ `"YbbdP"' 8P' `Y8 88 `Y8a `"Ybbd8"' 88 │ "
|
" │ `"YbbdP"' 8P' `Y8 88 `Y8a `"Ybbd8"' 88 │ "
|
||||||
" │ │ "
|
" │ │ "
|
||||||
" │ A simple tui to view & control docker containers │ "
|
" │ A simple tui to view & control docker containers │ "
|
||||||
" │ │ "
|
" │ │ "
|
||||||
" │ ( 0 ) select next panel │ "
|
" │ ( t ) select next panel │ "
|
||||||
" │ ( 2 ) or ( 3 ) select previous panel │ "
|
" │ ( u ) or ( U ) select previous panel │ "
|
||||||
" │ ( q ) or ( r ) scroll list down by one │ "
|
" │ ( o ) or ( O ) scroll list down by one │ "
|
||||||
" │ ( y ) or ( z ) scroll list up by one │ "
|
" │ ( s ) or ( S ) scroll list up by one │ "
|
||||||
" │ ( o ) scroll list down by many │ "
|
" │ ( n ) scroll list down by many │ "
|
||||||
" │ ( w ) scroll list by up many │ "
|
" │ ( r ) scroll list by up many │ "
|
||||||
" │ ( s ) scroll list to end │ "
|
" │ ( p ) scroll list to end │ "
|
||||||
" │ ( u ) or ( v ) scroll list to start │ "
|
" │ ( q ) or ( Q ) scroll list to start │ "
|
||||||
" │ ( enter ) send docker container command │ "
|
" │ ( h ) horizontal scroll logs right │ "
|
||||||
" │ ( g ) exec into a container │ "
|
" │ ( g ) or ( G ) horizontal scroll logs left │ "
|
||||||
" │ ( Home ) toggle this help information - or click heading │ "
|
" │ ( Alt ) increase scroll speed, used in conjuction scroll keys │ "
|
||||||
" │ ( m ) or ( n ) save logs to file │ "
|
" │ ( enter ) send docker container command │ "
|
||||||
" │ ( Page Down ) or ( Page Up ) toggle mouse capture - if disabled, text on screen can be selected & copied │ "
|
" │ ( d ) exec into a container │ "
|
||||||
" │ ( i ) or ( j ) enter filter mode │ "
|
" │ ( f ) force clear the screen & redraw the gui │ "
|
||||||
" │ ( Up ) or ( Down ) reset container sorting │ "
|
" │ ( 5 ) toggle this help information - or click heading │ "
|
||||||
" │ ( 4 ) sort containers by name │ "
|
" │ ( m ) or ( M ) save logs to file │ "
|
||||||
" │ ( 6 ) or ( 7 ) sort containers by state │ "
|
" │ ( 6 ) or ( 7 ) toggle mouse capture - if disabled, text on screen can be selected & copied │ "
|
||||||
" │ ( 8 ) sort containers by status │ "
|
" │ ( e ) or ( E ) enter filter mode │ "
|
||||||
" │ ( F1 ) or ( F12 ) sort containers by cpu │ "
|
" │ ( 4 ) or ( 5 ) reset container sorting │ "
|
||||||
" │ ( # ) sort containers by memory │ "
|
" │ ( z ) sort containers by name │ "
|
||||||
" │ ( / ) or ( = ) sort containers by id │ "
|
" │ ( 1 ) sort containers by state │ "
|
||||||
" │ ( , ) sort containers by image │ "
|
" │ ( 2 ) or ( 7 ) sort containers by status │ "
|
||||||
" │ ( . ) or ( ] ) sort containers by rx │ "
|
" │ ( v ) sort containers by cpu │ "
|
||||||
" │ ( Insert ) sort containers by tx │ "
|
" │ ( y ) or ( Y ) sort containers by memory │ "
|
||||||
" │ ( A ) or ( Z ) decrease log section height │ "
|
" │ ( w ) or ( W ) sort containers by id │ "
|
||||||
" │ ( B ) or ( X ) increase log section height │ "
|
" │ ( x ) sort containers by image │ "
|
||||||
" │ ( C ) or ( W ) toggle log section visibility │ "
|
" │ ( 0 ) or ( 9 ) sort containers by rx │ "
|
||||||
" │ ( a ) or ( b ) close dialog │ "
|
" │ ( 3 ) sort containers by tx │ "
|
||||||
" │ ( k ) quit at any time │ "
|
" │ ( i ) or ( I ) decrease log section height │ "
|
||||||
" │ │ "
|
" │ ( j ) increase log section height │ "
|
||||||
" │ currently an early work in progress, all and any input appreciated │ "
|
" │ ( k ) or ( K ) toggle log section visibility │ "
|
||||||
" │ https://github.com/mrjackwills/oxker │ "
|
" │ ( a ) or ( A ) close dialog │ "
|
||||||
" │ │ "
|
" │ ( l ) quit at any time │ "
|
||||||
" ╰──────────────────────────────────────────────────────────────────────────────────────────────────────────╯ "
|
" │ │ "
|
||||||
|
" │ currently an early work in progress, all and any input appreciated │ "
|
||||||
|
" │ https://github.com/mrjackwills/oxker │ "
|
||||||
|
" ╰────────────────────────────────────────────────────────────────────────────────────────────╯ "
|
||||||
|
|||||||
+4
-4
@@ -2,7 +2,6 @@
|
|||||||
source: src/ui/draw_blocks/help.rs
|
source: src/ui/draw_blocks/help.rs
|
||||||
expression: setup.terminal.backend()
|
expression: setup.terminal.backend()
|
||||||
---
|
---
|
||||||
" "
|
|
||||||
" ╭ 0.00.000 ─────────────────────────────────────────────────────────────────────────╮ "
|
" ╭ 0.00.000 ─────────────────────────────────────────────────────────────────────────╮ "
|
||||||
" │ │ "
|
" │ │ "
|
||||||
" │ 88 │ "
|
" │ 88 │ "
|
||||||
@@ -19,9 +18,12 @@ expression: setup.terminal.backend()
|
|||||||
" │ logs timezone: Asia/Tokyo │ "
|
" │ logs timezone: Asia/Tokyo │ "
|
||||||
" │ │ "
|
" │ │ "
|
||||||
" │ ( tab ) or ( shift+tab ) change panels │ "
|
" │ ( tab ) or ( shift+tab ) change panels │ "
|
||||||
" │ ( ↑ ↓ ) or ( j k ) or ( PgUp PgDown ) or ( Home End ) change selected line │ "
|
" │ ( ↑ ↓ ) or ( j k ) or ( PgUp PgDown ) or ( Home End ) scroll vertically │ "
|
||||||
|
" │ ( ← → ) horizontal scroll across logs │ "
|
||||||
|
" │ ( ctrl ) increase scroll speed, used in conjuction scroll keys │ "
|
||||||
" │ ( enter ) send docker container command │ "
|
" │ ( enter ) send docker container command │ "
|
||||||
" │ ( e ) exec into a container │ "
|
" │ ( e ) exec into a container │ "
|
||||||
|
" │ ( f ) force clear the screen & redraw the gui │ "
|
||||||
" │ ( h ) toggle this help information - or click heading │ "
|
" │ ( h ) toggle this help information - or click heading │ "
|
||||||
" │ ( s ) save logs to file │ "
|
" │ ( s ) save logs to file │ "
|
||||||
" │ ( m ) toggle mouse capture - if disabled, text on screen can be selected & copied │ "
|
" │ ( m ) toggle mouse capture - if disabled, text on screen can be selected & copied │ "
|
||||||
@@ -36,6 +38,4 @@ expression: setup.terminal.backend()
|
|||||||
" │ currently an early work in progress, all and any input appreciated │ "
|
" │ currently an early work in progress, all and any input appreciated │ "
|
||||||
" │ https://github.com/mrjackwills/oxker │ "
|
" │ https://github.com/mrjackwills/oxker │ "
|
||||||
" │ │ "
|
" │ │ "
|
||||||
" │ │ "
|
|
||||||
" ╰───────────────────────────────────────────────────────────────────────────────────╯ "
|
" ╰───────────────────────────────────────────────────────────────────────────────────╯ "
|
||||||
" "
|
|
||||||
|
|||||||
+22
-22
@@ -4,25 +4,26 @@ expression: setup.terminal.backend()
|
|||||||
---
|
---
|
||||||
" name state status cpu memory/limit id image ↓ rx ↑ tx ( h ) exit help "
|
" name state status cpu memory/limit id image ↓ rx ↑ tx ( h ) exit help "
|
||||||
"╭ Containers 1/3 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮╭──────────────╮"
|
"╭ Containers 1/3 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮╭──────────────╮"
|
||||||
"│⚪ container_1 ✓ running Up 1 hour 03.00% 30.00 kB / 30.00 kB 1 image_1 0.00 kB 0.00 kB ││▶ pause │" Hidden by multi-width symbols: [(2, " ")]
|
"│⚪ container_1 ✓ running Up 1 ho╭ 0.00.000 ──────────────────────────────────────────────────────────────────────────╮ ││▶ pause │" Hidden by multi-width symbols: [(2, " ")]
|
||||||
"│ 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_2 ✓ running Up 2 ho│ │ ││ restart │"
|
||||||
"│ container_3 ✓ running Up 3 ho╭ 0.00.000 ──────────────────────────────────────────────────────────────────────────╮ ││ stop │"
|
"│ container_3 ✓ running Up 3 ho│ 88 │ ││ stop │"
|
||||||
"│ │ │ ││ delete │"
|
"│ │ 88 │ ││ delete │"
|
||||||
"│ │ 88 │ ││ │"
|
"│ │ 88 │ ││ │"
|
||||||
"╰────────────────────────────────────│ 88 │────────────────────╯╰──────────────╯"
|
"╰────────────────────────────────────│ ,adPPYba, 8b, ,d8 88 ,d8 ,adPPYba, 8b,dPPYba, │────────────────────╯╰──────────────╯"
|
||||||
"╭ Logs 3/3 - container_1 - image_1 ──│ 88 │────────────────────────────────────╮"
|
"╭ Logs 3/3 - container_1 - image_1 ──│ a8" "8a `Y8, ,8P' 88 ,a8" a8P_____88 88P' "Y8 │────────────────────────────────────╮"
|
||||||
"│ line 1 │ ,adPPYba, 8b, ,d8 88 ,d8 ,adPPYba, 8b,dPPYba, │ │"
|
"│ line 1 │ 8b d8 )888( 8888[ 8PP""""""" 88 │ │"
|
||||||
"│ line 2 │ a8" "8a `Y8, ,8P' 88 ,a8" a8P_____88 88P' "Y8 │ │"
|
"│ line 2 │ "8a, ,a8" ,d8" "8b, 88`"Yba, "8b, ,aa 88 │ │"
|
||||||
"│▶ line 3 │ 8b d8 )888( 8888[ 8PP""""""" 88 │ │"
|
"│▶ line 3 │ `"YbbdP"' 8P' `Y8 88 `Y8a `"Ybbd8"' 88 │ │"
|
||||||
"│ │ "8a, ,a8" ,d8" "8b, 88`"Yba, "8b, ,aa 88 │ │"
|
|
||||||
"│ │ `"YbbdP"' 8P' `Y8 88 `Y8a `"Ybbd8"' 88 │ │"
|
|
||||||
"│ │ │ │"
|
"│ │ │ │"
|
||||||
"│ │ A simple tui to view & control docker containers │ │"
|
"│ │ A simple tui to view & control docker containers │ │"
|
||||||
"│ │ │ │"
|
"│ │ │ │"
|
||||||
"│ │ ( tab ) or ( shift+tab ) change panels │ │"
|
"│ │ ( tab ) or ( shift+tab ) change panels │ │"
|
||||||
"│ │ ( ↑ ↓ ) or ( j k ) or ( PgUp PgDown ) or ( Home End ) change selected line │ │"
|
"│ │ ( ↑ ↓ ) or ( j k ) or ( PgUp PgDown ) or ( Home End ) scroll vertically │ │"
|
||||||
|
"│ │ ( ← → ) horizontal scroll across logs │ │"
|
||||||
|
"│ │ ( ctrl ) increase scroll speed, used in conjuction scroll keys │ │"
|
||||||
"│ │ ( enter ) send docker container command │ │"
|
"│ │ ( enter ) send docker container command │ │"
|
||||||
"│ │ ( e ) exec into a container │ │"
|
"│ │ ( e ) exec into a container │ │"
|
||||||
|
"│ │ ( f ) force clear the screen & redraw the gui │ │"
|
||||||
"│ │ ( h ) toggle this help information - or click heading │ │"
|
"│ │ ( h ) toggle this help information - or click heading │ │"
|
||||||
"│ │ ( s ) save logs to file │ │"
|
"│ │ ( s ) save logs to file │ │"
|
||||||
"│ │ ( m ) toggle mouse capture - if disabled, text on screen can be selected & copied │ │"
|
"│ │ ( m ) toggle mouse capture - if disabled, text on screen can be selected & copied │ │"
|
||||||
@@ -30,15 +31,14 @@ expression: setup.terminal.backend()
|
|||||||
"│ │ ( 0 ) stop sort │ │"
|
"│ │ ( 0 ) stop sort │ │"
|
||||||
"│ │ ( 1 - 9 ) sort by header - or click header │ │"
|
"│ │ ( 1 - 9 ) sort by header - or click header │ │"
|
||||||
"│ │ ( - = ) change log section height │ │"
|
"│ │ ( - = ) change log section height │ │"
|
||||||
"│ │ ( \ ) toggle log section visibility │ │"
|
"╰────────────────────────────────────│ ( \ ) toggle log section visibility │────────────────────────────────────╯"
|
||||||
"╰────────────────────────────────────│ ( esc ) close dialog │────────────────────────────────────╯"
|
"╭───────────────────────── cpu 03.00%│ ( esc ) close dialog │──────╮╭────────── ports ───────────╮"
|
||||||
"╭───────────────────────── cpu 03.00%│ ( q ) quit at any time │──────╮╭────────── ports ───────────╮"
|
"│10.00%│ •• │ ( q ) quit at any time │ ││ ip private public│"
|
||||||
"│10.00%│ •• │ │ ││ ip private public│"
|
"│ │ • • │ │ ││ 8001 │"
|
||||||
"│ │ • • │ currently an early work in progress, all and any input appreciated │ ││ 8001 │"
|
"│ │ •• • │ currently an early work in progress, all and any input appreciated │ ││127.0.0.1 8003 8003│"
|
||||||
"│ │ •• • │ https://github.com/mrjackwills/oxker │ ││127.0.0.1 8003 8003│"
|
"│ │ • • │ https://github.com/mrjackwills/oxker │ ││ │"
|
||||||
"│ │ • • │ │ ││ │"
|
"│ │ •• • • │ │ ││ │"
|
||||||
"│ │ •• • • ╰────────────────────────────────────────────────────────────────────────────────────╯ ││ │"
|
"│ │• •• │ │ ││ │"
|
||||||
"│ │• •• ││ │• •• ││ │"
|
"│ │• • ╰────────────────────────────────────────────────────────────────────────────────────╯ ││ │"
|
||||||
"│ │• • ││ │• • ││ │"
|
|
||||||
"│ │ ││ │ ││ │"
|
"│ │ ││ │ ││ │"
|
||||||
"╰───────────────────────────────────────────────────────────────╯╰───────────────────────────────────────────────────────────────╯╰────────────────────────────╯"
|
"╰───────────────────────────────────────────────────────────────╯╰───────────────────────────────────────────────────────────────╯╰────────────────────────────╯"
|
||||||
|
|||||||
+31
-14
@@ -187,6 +187,7 @@ pub struct GuiState {
|
|||||||
log_height: u16,
|
log_height: u16,
|
||||||
rerender: Arc<Rerender>,
|
rerender: Arc<Rerender>,
|
||||||
selected_panel: SelectablePanel,
|
selected_panel: SelectablePanel,
|
||||||
|
screen_width: u16,
|
||||||
show_logs: bool,
|
show_logs: bool,
|
||||||
status: HashSet<Status>,
|
status: HashSet<Status>,
|
||||||
pub info_box_text: Option<(String, Instant)>,
|
pub info_box_text: Option<(String, Instant)>,
|
||||||
@@ -205,6 +206,7 @@ impl GuiState {
|
|||||||
loading_index: 0,
|
loading_index: 0,
|
||||||
loading_set: HashSet::new(),
|
loading_set: HashSet::new(),
|
||||||
log_height: 75,
|
log_height: 75,
|
||||||
|
screen_width: 0,
|
||||||
rerender: Arc::clone(redraw),
|
rerender: Arc::clone(redraw),
|
||||||
selected_panel: SelectablePanel::default(),
|
selected_panel: SelectablePanel::default(),
|
||||||
show_logs,
|
show_logs,
|
||||||
@@ -215,7 +217,7 @@ impl GuiState {
|
|||||||
pub fn log_height_increase(&mut self) {
|
pub fn log_height_increase(&mut self) {
|
||||||
if self.show_logs && self.log_height <= 75 {
|
if self.show_logs && self.log_height <= 75 {
|
||||||
self.log_height = self.log_height.saturating_add(5);
|
self.log_height = self.log_height.saturating_add(5);
|
||||||
self.rerender.update();
|
self.rerender.update_draw();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -228,10 +230,20 @@ impl GuiState {
|
|||||||
self.show_logs = false;
|
self.show_logs = false;
|
||||||
self.selected_panel = SelectablePanel::Containers;
|
self.selected_panel = SelectablePanel::Containers;
|
||||||
}
|
}
|
||||||
self.rerender.update();
|
self.rerender.update_draw();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set the screen width, used for offset char calculations
|
||||||
|
pub const fn set_screen_width(&mut self, width: u16) {
|
||||||
|
self.screen_width = width;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the screen width, used for offset char calculations
|
||||||
|
pub const fn get_screen_width(&self) -> u16 {
|
||||||
|
self.screen_width
|
||||||
|
}
|
||||||
|
|
||||||
pub const fn get_show_logs(&self) -> bool {
|
pub const fn get_show_logs(&self) -> bool {
|
||||||
self.show_logs
|
self.show_logs
|
||||||
}
|
}
|
||||||
@@ -241,7 +253,7 @@ impl GuiState {
|
|||||||
if !self.show_logs && self.selected_panel == SelectablePanel::Logs {
|
if !self.show_logs && self.selected_panel == SelectablePanel::Logs {
|
||||||
self.selected_panel = SelectablePanel::Containers;
|
self.selected_panel = SelectablePanel::Containers;
|
||||||
}
|
}
|
||||||
self.rerender.update();
|
self.rerender.update_draw();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the log_height to zero, for now only used by tests
|
/// Set the log_height to zero, for now only used by tests
|
||||||
@@ -260,6 +272,11 @@ impl GuiState {
|
|||||||
self.intersect_panel.clear();
|
self.intersect_panel.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set the rerender clear to true, to flush the screen and redraw
|
||||||
|
pub fn set_clear(&self) {
|
||||||
|
self.rerender.set_clear();
|
||||||
|
}
|
||||||
|
|
||||||
/// Get the currently selected panel
|
/// Get the currently selected panel
|
||||||
pub const fn get_selected_panel(&self) -> SelectablePanel {
|
pub const fn get_selected_panel(&self) -> SelectablePanel {
|
||||||
self.selected_panel
|
self.selected_panel
|
||||||
@@ -275,7 +292,7 @@ impl GuiState {
|
|||||||
.first()
|
.first()
|
||||||
{
|
{
|
||||||
self.selected_panel = *data.0;
|
self.selected_panel = *data.0;
|
||||||
self.rerender.update();
|
self.rerender.update_draw();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -348,7 +365,7 @@ impl GuiState {
|
|||||||
self.status_del(Status::DeleteConfirm);
|
self.status_del(Status::DeleteConfirm);
|
||||||
}
|
}
|
||||||
self.delete_container_id = id;
|
self.delete_container_id = id;
|
||||||
self.rerender.update();
|
self.rerender.update_draw();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return a copy of the Status HashSet
|
/// Return a copy of the Status HashSet
|
||||||
@@ -369,7 +386,7 @@ impl GuiState {
|
|||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
self.rerender.update();
|
self.rerender.update_draw();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Inset the ExecMode into self, and set the Status as exec
|
/// Inset the ExecMode into self, and set the Status as exec
|
||||||
@@ -378,7 +395,7 @@ impl GuiState {
|
|||||||
pub fn set_exec_mode(&mut self, mode: ExecMode) {
|
pub fn set_exec_mode(&mut self, mode: ExecMode) {
|
||||||
self.exec_mode = Some(mode);
|
self.exec_mode = Some(mode);
|
||||||
self.status.insert(Status::Exec);
|
self.status.insert(Status::Exec);
|
||||||
self.rerender.update();
|
self.rerender.update_draw();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_exec_mode(&self) -> Option<ExecMode> {
|
pub fn get_exec_mode(&self) -> Option<ExecMode> {
|
||||||
@@ -390,7 +407,7 @@ impl GuiState {
|
|||||||
pub fn status_push(&mut self, status: Status) {
|
pub fn status_push(&mut self, status: Status) {
|
||||||
if status != Status::Exec {
|
if status != Status::Exec {
|
||||||
self.status.insert(status);
|
self.status.insert(status);
|
||||||
self.rerender.update();
|
self.rerender.update_draw();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -403,7 +420,7 @@ impl GuiState {
|
|||||||
{
|
{
|
||||||
self.selected_panel = self.selected_panel.next();
|
self.selected_panel = self.selected_panel.next();
|
||||||
}
|
}
|
||||||
self.rerender.update();
|
self.rerender.update_draw();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Change to previous selectable panel
|
/// Change to previous selectable panel
|
||||||
@@ -415,7 +432,7 @@ impl GuiState {
|
|||||||
{
|
{
|
||||||
self.selected_panel = self.selected_panel.prev();
|
self.selected_panel = self.selected_panel.prev();
|
||||||
}
|
}
|
||||||
self.rerender.update();
|
self.rerender.update_draw();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Insert a new loading_uuid into HashSet, and advance the loading_index by one frame, or reset to 0 if at end of array
|
/// Insert a new loading_uuid into HashSet, and advance the loading_index by one frame, or reset to 0 if at end of array
|
||||||
@@ -426,7 +443,7 @@ impl GuiState {
|
|||||||
self.loading_index += 1;
|
self.loading_index += 1;
|
||||||
}
|
}
|
||||||
self.loading_set.insert(uuid);
|
self.loading_set.insert(uuid);
|
||||||
self.rerender.update();
|
self.rerender.update_draw();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_loading(&self) -> bool {
|
pub fn is_loading(&self) -> bool {
|
||||||
@@ -459,7 +476,7 @@ impl GuiState {
|
|||||||
/// Stop the loading_spin function, and reset gui loading status
|
/// Stop the loading_spin function, and reset gui loading status
|
||||||
pub fn stop_loading_animation(&mut self, loading_uuid: Uuid) {
|
pub fn stop_loading_animation(&mut self, loading_uuid: Uuid) {
|
||||||
self.loading_set.remove(&loading_uuid);
|
self.loading_set.remove(&loading_uuid);
|
||||||
self.rerender.update();
|
self.rerender.update_draw();
|
||||||
if self.loading_set.is_empty() {
|
if self.loading_set.is_empty() {
|
||||||
self.loading_index = 0;
|
self.loading_index = 0;
|
||||||
if let Some(h) = &self.loading_handle {
|
if let Some(h) = &self.loading_handle {
|
||||||
@@ -472,12 +489,12 @@ impl GuiState {
|
|||||||
/// Set info box content
|
/// Set info box content
|
||||||
pub fn set_info_box(&mut self, text: &str) {
|
pub fn set_info_box(&mut self, text: &str) {
|
||||||
self.info_box_text = Some((text.to_owned(), std::time::Instant::now()));
|
self.info_box_text = Some((text.to_owned(), std::time::Instant::now()));
|
||||||
self.rerender.update();
|
self.rerender.update_draw();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Remove info box content
|
/// Remove info box content
|
||||||
pub fn reset_info_box(&mut self) {
|
pub fn reset_info_box(&mut self) {
|
||||||
self.info_box_text = None;
|
self.info_box_text = None;
|
||||||
self.rerender.update();
|
self.rerender.update_draw();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+30
-10
@@ -50,7 +50,7 @@ pub struct Ui {
|
|||||||
input_tx: Sender<InputMessages>,
|
input_tx: Sender<InputMessages>,
|
||||||
is_running: Arc<AtomicBool>,
|
is_running: Arc<AtomicBool>,
|
||||||
now: Instant,
|
now: Instant,
|
||||||
redraw: Arc<Rerender>,
|
rerender: Arc<Rerender>,
|
||||||
terminal: Terminal<CrosstermBackend<Stdout>>,
|
terminal: Terminal<CrosstermBackend<Stdout>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -73,7 +73,7 @@ impl Ui {
|
|||||||
gui_state: Arc<Mutex<GuiState>>,
|
gui_state: Arc<Mutex<GuiState>>,
|
||||||
input_tx: Sender<InputMessages>,
|
input_tx: Sender<InputMessages>,
|
||||||
is_running: Arc<AtomicBool>,
|
is_running: Arc<AtomicBool>,
|
||||||
redraw: Arc<Rerender>,
|
rerender: Arc<Rerender>,
|
||||||
) {
|
) {
|
||||||
match Self::setup_terminal() {
|
match Self::setup_terminal() {
|
||||||
Ok(mut terminal) => {
|
Ok(mut terminal) => {
|
||||||
@@ -85,7 +85,7 @@ impl Ui {
|
|||||||
input_tx,
|
input_tx,
|
||||||
is_running,
|
is_running,
|
||||||
now: Instant::now(),
|
now: Instant::now(),
|
||||||
redraw,
|
rerender,
|
||||||
terminal,
|
terminal,
|
||||||
};
|
};
|
||||||
if let Err(e) = ui.draw_ui().await {
|
if let Err(e) = ui.draw_ui().await {
|
||||||
@@ -169,6 +169,13 @@ impl Ui {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Check if the user has attempt to clear the screen, and if so clear and redraw
|
||||||
|
fn check_clear(&mut self) {
|
||||||
|
if self.rerender.get_clear() {
|
||||||
|
self.terminal.clear().ok();
|
||||||
|
self.rerender.update_draw();
|
||||||
|
}
|
||||||
|
}
|
||||||
/// Use external docker cli to exec into a container
|
/// Use external docker cli to exec into a container
|
||||||
async fn exec(&mut self) {
|
async fn exec(&mut self) {
|
||||||
let exec_mode = self.gui_state.lock().get_exec_mode();
|
let exec_mode = self.gui_state.lock().get_exec_mode();
|
||||||
@@ -191,7 +198,8 @@ impl Ui {
|
|||||||
/// Use the previously redrawn time, the current time, the docker_interval, and the redraw struct, to calculate
|
/// Use the previously redrawn time, the current time, the docker_interval, and the redraw struct, to calculate
|
||||||
/// if the screen should be redrawn or not
|
/// if the screen should be redrawn or not
|
||||||
fn should_redraw(&self, previous: &mut Instant, docker_interval_ms: u128) -> bool {
|
fn should_redraw(&self, previous: &mut Instant, docker_interval_ms: u128) -> bool {
|
||||||
let result = self.redraw.swap() || previous.elapsed().as_millis() >= docker_interval_ms;
|
let result =
|
||||||
|
self.rerender.swap_draw() || previous.elapsed().as_millis() >= docker_interval_ms;
|
||||||
if result {
|
if result {
|
||||||
*previous = std::time::Instant::now();
|
*previous = std::time::Instant::now();
|
||||||
}
|
}
|
||||||
@@ -205,7 +213,15 @@ impl Ui {
|
|||||||
let docker_interval_ms = u128::from(self.app_data.lock().config.docker_interval_ms);
|
let docker_interval_ms = u128::from(self.app_data.lock().config.docker_interval_ms);
|
||||||
let mut drawn_at = std::time::Instant::now();
|
let mut drawn_at = std::time::Instant::now();
|
||||||
|
|
||||||
|
if let Ok(size) = self.terminal.size() {
|
||||||
|
self.gui_state.lock().set_screen_width(size.width);
|
||||||
|
}
|
||||||
|
|
||||||
while self.is_running.load(Ordering::SeqCst) {
|
while self.is_running.load(Ordering::SeqCst) {
|
||||||
|
// if self.redraw.get_clear() {
|
||||||
|
// self.terminal.clear().ok();
|
||||||
|
// continue;
|
||||||
|
// }
|
||||||
if self.should_redraw(&mut drawn_at, docker_interval_ms) {
|
if self.should_redraw(&mut drawn_at, docker_interval_ms) {
|
||||||
let fd = FrameData::from(&*self);
|
let fd = FrameData::from(&*self);
|
||||||
|
|
||||||
@@ -239,18 +255,21 @@ impl Ui {
|
|||||||
event::MouseEventKind::Down(_)
|
event::MouseEventKind::Down(_)
|
||||||
| event::MouseEventKind::ScrollDown
|
| event::MouseEventKind::ScrollDown
|
||||||
| event::MouseEventKind::ScrollUp => {
|
| event::MouseEventKind::ScrollUp => {
|
||||||
self.input_tx.send(InputMessages::MouseEvent(m)).await.ok();
|
self.input_tx
|
||||||
|
.send(InputMessages::MouseEvent((m, m.modifiers)))
|
||||||
|
.await
|
||||||
|
.ok();
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
} else if let Event::Resize(_, _) = event {
|
} else if let Event::Resize(width, _) = event {
|
||||||
self.gui_state.lock().clear_area_map();
|
self.gui_state.lock().clear_area_map();
|
||||||
// self.gui_state.lock().set_window_height(row);
|
|
||||||
|
|
||||||
self.terminal.autoresize().ok();
|
self.terminal.autoresize().ok();
|
||||||
|
self.gui_state.lock().set_screen_width(width);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
self.check_clear();
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -279,7 +298,6 @@ pub struct FrameData {
|
|||||||
filter_by: FilterBy,
|
filter_by: FilterBy,
|
||||||
filter_term: Option<String>,
|
filter_term: Option<String>,
|
||||||
has_containers: bool,
|
has_containers: bool,
|
||||||
// container_section_height: u16,
|
|
||||||
log_height: u16,
|
log_height: u16,
|
||||||
show_logs: bool,
|
show_logs: bool,
|
||||||
has_error: Option<AppError>,
|
has_error: Option<AppError>,
|
||||||
@@ -290,13 +308,14 @@ pub struct FrameData {
|
|||||||
port_max_lens: (usize, usize, usize),
|
port_max_lens: (usize, usize, usize),
|
||||||
ports: Option<(Vec<ContainerPorts>, State)>,
|
ports: Option<(Vec<ContainerPorts>, State)>,
|
||||||
selected_panel: SelectablePanel,
|
selected_panel: SelectablePanel,
|
||||||
|
scroll_title: Option<String>,
|
||||||
sorted_by: Option<(Header, SortedOrder)>,
|
sorted_by: Option<(Header, SortedOrder)>,
|
||||||
status: HashSet<Status>,
|
status: HashSet<Status>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&Ui> for FrameData {
|
impl From<&Ui> for FrameData {
|
||||||
fn from(ui: &Ui) -> Self {
|
fn from(ui: &Ui) -> Self {
|
||||||
let (app_data, gui_data) = (ui.app_data.lock(), ui.gui_state.lock());
|
let (mut app_data, gui_data) = (ui.app_data.lock(), ui.gui_state.lock());
|
||||||
|
|
||||||
let (filter_by, filter_term) = app_data.get_filter();
|
let (filter_by, filter_term) = app_data.get_filter();
|
||||||
Self {
|
Self {
|
||||||
@@ -317,6 +336,7 @@ impl From<&Ui> for FrameData {
|
|||||||
log_title: app_data.get_log_title(),
|
log_title: app_data.get_log_title(),
|
||||||
port_max_lens: app_data.get_longest_port(),
|
port_max_lens: app_data.get_longest_port(),
|
||||||
ports: app_data.get_selected_ports(),
|
ports: app_data.get_selected_ports(),
|
||||||
|
scroll_title: app_data.get_scroll_title(gui_data.get_screen_width()),
|
||||||
selected_panel: gui_data.get_selected_panel(),
|
selected_panel: gui_data.get_selected_panel(),
|
||||||
sorted_by: app_data.get_sorted(),
|
sorted_by: app_data.get_sorted(),
|
||||||
status: gui_data.get_status(),
|
status: gui_data.get_status(),
|
||||||
|
|||||||
+21
-7
@@ -1,21 +1,35 @@
|
|||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Rerender(AtomicBool);
|
pub struct Rerender {
|
||||||
|
draw: AtomicBool,
|
||||||
|
clear: AtomicBool,
|
||||||
|
}
|
||||||
|
|
||||||
impl Rerender {
|
impl Rerender {
|
||||||
pub const fn new() -> Self {
|
pub const fn new() -> Self {
|
||||||
Self(AtomicBool::new(true))
|
Self {
|
||||||
|
draw: AtomicBool::new(true),
|
||||||
|
clear: AtomicBool::new(false),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update(&self) {
|
pub fn update_draw(&self) {
|
||||||
self.0.store(true, Ordering::SeqCst);
|
self.draw.store(true, Ordering::SeqCst);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the value of the self, and set to false
|
pub fn get_clear(&self) -> bool {
|
||||||
pub fn swap(&self) -> bool {
|
self.clear.swap(false, Ordering::SeqCst)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_clear(&self) {
|
||||||
|
self.clear.store(true, Ordering::SeqCst);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the value of the draw, and set to false
|
||||||
|
pub fn swap_draw(&self) -> bool {
|
||||||
match self
|
match self
|
||||||
.0
|
.draw
|
||||||
.compare_exchange(true, false, Ordering::SeqCst, Ordering::SeqCst)
|
.compare_exchange(true, false, Ordering::SeqCst, Ordering::SeqCst)
|
||||||
{
|
{
|
||||||
Ok(previous_value) => previous_value,
|
Ok(previous_value) => previous_value,
|
||||||
|
|||||||
Reference in New Issue
Block a user