Compare commits
No commits in common. "main" and "fixes" have entirely different histories.
10 changed files with 78 additions and 390 deletions
|
|
@ -1,179 +0,0 @@
|
||||||
name: Multi-Platform Release Build
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
tags:
|
|
||||||
- "v*.*.*"
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
runs-on: docker
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
include:
|
|
||||||
- target: native
|
|
||||||
cross: false
|
|
||||||
platform: linux/arm64
|
|
||||||
|
|
||||||
- target: x86_64-unknown-linux-gnu
|
|
||||||
cross: true
|
|
||||||
platform: linux/amd64
|
|
||||||
deps: "build-essential gcc-x86-64-linux-gnu libc6-dev-amd64-cross pkg-config binutils-x86-64-linux-gnu"
|
|
||||||
env:
|
|
||||||
CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_LINKER: x86_64-linux-gnu-gcc
|
|
||||||
|
|
||||||
- target: x86_64-pc-windows-gnu
|
|
||||||
cross: true
|
|
||||||
platform: linux/amd64
|
|
||||||
deps: "gcc-mingw-w64-x86-64 g++-mingw-w64-x86-64 cmake nasm"
|
|
||||||
env:
|
|
||||||
CC_x86_64_pc_windows_gnu: x86_64-w64-mingw32-gcc
|
|
||||||
CARGO_TARGET_X86_64_PC_WINDOWS_GNU_LINKER: x86_64-w64-mingw32-gcc
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout code
|
|
||||||
uses: https://code.forgejo.org/actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Setup Rust
|
|
||||||
uses: https://github.com/dtolnay/rust-toolchain@stable
|
|
||||||
with:
|
|
||||||
toolchain: stable
|
|
||||||
|
|
||||||
- name: Cache Rust dependencies
|
|
||||||
uses: https://code.forgejo.org/actions/cache@v4
|
|
||||||
with:
|
|
||||||
path: |
|
|
||||||
~/.cargo/bin/
|
|
||||||
~/.cargo/registry/index/
|
|
||||||
~/.cargo/registry/cache/
|
|
||||||
~/.cargo/git/db/
|
|
||||||
target/
|
|
||||||
key: ${{ runner.os }}-cargo-${{ matrix.target }}-${{ hashFiles('**/Cargo.lock') }}
|
|
||||||
restore-keys: |
|
|
||||||
${{ runner.os }}-cargo-${{ matrix.target }}-
|
|
||||||
${{ runner.os }}-cargo-
|
|
||||||
|
|
||||||
- name: Native Build Release
|
|
||||||
if: matrix.target == 'native'
|
|
||||||
run: |
|
|
||||||
NATIVE_TARGET=$(rustc -vV | grep 'host:' | cut -d' ' -f2)
|
|
||||||
echo "Building for native target: $NATIVE_TARGET"
|
|
||||||
cargo build --release
|
|
||||||
TARGET_BINARY="target/release/uptime-kuma-dashboard"
|
|
||||||
OUTPUT_NAME="uptime-kuma-dashboard-$NATIVE_TARGET"
|
|
||||||
mkdir -p release-artifacts
|
|
||||||
cp "$TARGET_BINARY" "release-artifacts/$OUTPUT_NAME"
|
|
||||||
strip "release-artifacts/$OUTPUT_NAME" 2>/dev/null || true
|
|
||||||
chmod +x "release-artifacts/$OUTPUT_NAME"
|
|
||||||
ls -lh "release-artifacts/$OUTPUT_NAME"
|
|
||||||
|
|
||||||
- name: Get Rust version
|
|
||||||
id: rust-version
|
|
||||||
run: echo "version=$(rustc --version | cut -d' ' -f2)" >> $GITHUB_OUTPUT
|
|
||||||
|
|
||||||
- name: Cross-Build Linux x86_64 Release
|
|
||||||
if: matrix.target == 'x86_64-unknown-linux-gnu'
|
|
||||||
uses: docker://rust:slim
|
|
||||||
with:
|
|
||||||
args: >
|
|
||||||
sh -c "
|
|
||||||
rustup target add ${{ matrix.target }} &&
|
|
||||||
apt-get update && apt-get install -y ${{ matrix.deps }} &&
|
|
||||||
mkdir -p ~/.cargo &&
|
|
||||||
echo '[target.${{ matrix.target }}]\nlinker = \"x86_64-linux-gnu-gcc\"' > ~/.cargo/config.toml &&
|
|
||||||
cargo build --release --target ${{ matrix.target }} &&
|
|
||||||
mkdir -p release-artifacts &&
|
|
||||||
cp target/${{ matrix.target }}/release/uptime-kuma-dashboard release-artifacts/uptime-kuma-dashboard-${{ matrix.target }} &&
|
|
||||||
x86_64-linux-gnu-strip release-artifacts/uptime-kuma-dashboard-${{ matrix.target }} &&
|
|
||||||
chmod +x release-artifacts/uptime-kuma-dashboard-${{ matrix.target }}"
|
|
||||||
env: ${{ matrix.env }}
|
|
||||||
options: --platform ${{ matrix.platform }}
|
|
||||||
|
|
||||||
- name: Cross-Build Windows x86_64 Release
|
|
||||||
if: matrix.target == 'x86_64-pc-windows-gnu'
|
|
||||||
uses: docker://rust:slim
|
|
||||||
with:
|
|
||||||
args: >
|
|
||||||
sh -c "
|
|
||||||
rustup target add ${{ matrix.target }} &&
|
|
||||||
apt-get update && apt-get install -y ${{ matrix.deps }} &&
|
|
||||||
cargo build --release --target ${{ matrix.target }} &&
|
|
||||||
mkdir -p release-artifacts &&
|
|
||||||
cp target/${{ matrix.target }}/release/uptime-kuma-dashboard.exe release-artifacts/uptime-kuma-dashboard-${{ matrix.target }}.exe &&
|
|
||||||
ls -lh release-artifacts/"
|
|
||||||
env: ${{ matrix.env }}
|
|
||||||
options: --platform ${{ matrix.platform }}
|
|
||||||
|
|
||||||
- name: Upload artifacts
|
|
||||||
uses: https://data.forgejo.org/forgejo/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: binary-${{ matrix.target }}
|
|
||||||
path: release-artifacts/
|
|
||||||
retention-days: 1
|
|
||||||
|
|
||||||
create-release:
|
|
||||||
runs-on: docker
|
|
||||||
needs: build
|
|
||||||
permissions:
|
|
||||||
contents: write
|
|
||||||
steps:
|
|
||||||
- name: Checkout code
|
|
||||||
uses: https://code.forgejo.org/actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Download all artifacts
|
|
||||||
uses: https://data.forgejo.org/forgejo/download-artifact@v4
|
|
||||||
with:
|
|
||||||
path: all-artifacts/
|
|
||||||
|
|
||||||
- name: Prepare release artifacts
|
|
||||||
run: |
|
|
||||||
mkdir -p release-artifacts
|
|
||||||
find all-artifacts -type f -name "uptime-kuma-dashboard-*" -exec cp {} release-artifacts/ \;
|
|
||||||
ls -lh release-artifacts/
|
|
||||||
|
|
||||||
- name: Generate checksums
|
|
||||||
run: |
|
|
||||||
cd release-artifacts
|
|
||||||
sha256sum uptime-kuma-dashboard-* > SHA256SUMS.txt
|
|
||||||
cat SHA256SUMS.txt
|
|
||||||
|
|
||||||
- name: Create Release
|
|
||||||
uses: https://code.forgejo.org/actions/forgejo-release@v2
|
|
||||||
with:
|
|
||||||
direction: upload
|
|
||||||
url: https://git.marcodearaujo.com
|
|
||||||
repo: marcodearaujo/uptime-kuma-dashboard
|
|
||||||
token: ${{ secrets.FORGEJO_TOKEN }}
|
|
||||||
release-dir: release-artifacts
|
|
||||||
title: "Release ${{ forgejo.ref_name }}"
|
|
||||||
tag: ${{ forgejo.ref_name }}
|
|
||||||
release-notes: |
|
|
||||||
## 🚀 Multi-Platform Release
|
|
||||||
Compiled on Forgejo Runner **${{ runner.arch }}**
|
|
||||||
|
|
||||||
### 📦 Available Binaries
|
|
||||||
This release includes binaries for the following platforms:
|
|
||||||
- **Linux x86_64** (Intel/AMD 64-bit)
|
|
||||||
- **Linux ARM64** (aarch64) - Raspberry Pi 4, ARM servers
|
|
||||||
- **Windows x86_64** (64-bit)
|
|
||||||
|
|
||||||
### 🚀 How to use
|
|
||||||
#### Linux/ARM:
|
|
||||||
# Download the appropriate binary
|
|
||||||
wget https://your-forgejo.com/releases/download/${{ forgejo.ref_name }}/uptime-kuma-dashboard-<your-target>
|
|
||||||
# Make executable
|
|
||||||
chmod +x uptime-kuma-dashboard-*
|
|
||||||
# Run
|
|
||||||
./uptime-kuma-dashboard-* --base-url https://your-kuma --slug your-slug
|
|
||||||
|
|
||||||
#### Windows:
|
|
||||||
# Download uptime-kuma-dashboard-x86_64-pc-windows-gnu.exe
|
|
||||||
# Run in PowerShell or CMD
|
|
||||||
.\uptime-kuma-dashboard-x86_64-pc-windows-gnu.exe --base-url https://your-kuma --slug your-slug
|
|
||||||
|
|
||||||
### ✅ Verify Checksums
|
|
||||||
sha256sum -c SHA256SUMS.txt
|
|
||||||
|
|
||||||
### 🏗️ Build Information
|
|
||||||
- Rust Version: ${{ steps.rust-version.outputs.version }}
|
|
||||||
- Build Date: $(date +'%Y-%m-%d')
|
|
||||||
- Build Type: Release (optimized with LTO)
|
|
||||||
18
Cargo.lock
generated
18
Cargo.lock
generated
|
|
@ -78,9 +78,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anyhow"
|
name = "anyhow"
|
||||||
version = "1.0.101"
|
version = "1.0.100"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5f0e0fee31ef5ed1ba1316088939cea399010ed7731dba877ed44aeb407a75ea"
|
checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "atomic"
|
name = "atomic"
|
||||||
|
|
@ -249,9 +249,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap"
|
name = "clap"
|
||||||
version = "4.5.57"
|
version = "4.5.54"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6899ea499e3fb9305a65d5ebf6e3d2248c5fab291f300ad0a704fbe142eae31a"
|
checksum = "c6e6ff9dcd79cff5cd969a17a545d79e84ab086e444102a591e288a8aa3ce394"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap_builder",
|
"clap_builder",
|
||||||
"clap_derive",
|
"clap_derive",
|
||||||
|
|
@ -259,9 +259,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap_builder"
|
name = "clap_builder"
|
||||||
version = "4.5.57"
|
version = "4.5.54"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7b12c8b680195a62a8364d16b8447b01b6c2c8f9aaf68bee653be34d4245e238"
|
checksum = "fa42cf4d2b7a41bc8f663a7cab4031ebafa1bf3875705bfaf8466dc60ab52c00"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anstream",
|
"anstream",
|
||||||
"anstyle",
|
"anstyle",
|
||||||
|
|
@ -271,9 +271,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap_derive"
|
name = "clap_derive"
|
||||||
version = "4.5.55"
|
version = "4.5.49"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a92793da1a46a5f2a02a6f4c46c6496b28c43638adea8306fcb0caa1634f24e5"
|
checksum = "2a0b5487afeab2deb2ff4e03a807ad1a03ac532ff5a2cee5d86884440c7f7671"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"heck",
|
"heck",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
|
|
@ -2668,7 +2668,7 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uptime-kuma-dashboard"
|
name = "uptime-kuma-dashboard"
|
||||||
version = "0.38.2"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"chrono",
|
"chrono",
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,16 @@
|
||||||
[package]
|
[package]
|
||||||
name = "uptime-kuma-dashboard"
|
name = "uptime-kuma-dashboard"
|
||||||
version = "0.38.2"
|
version = "0.1.0"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
clap = { version = "4.5.57", features = ["derive", "env"] }
|
clap = { version = "4.5.54", features = ["derive", "env"] }
|
||||||
reqwest = { version = "0.13.1", default-features = false, features = [
|
reqwest = { version = "0.13.1", default-features = false, features = [
|
||||||
"blocking",
|
"blocking",
|
||||||
"json",
|
"json",
|
||||||
"rustls",
|
"rustls",
|
||||||
] }
|
] }
|
||||||
anyhow = "1.0.101"
|
anyhow = "1.0"
|
||||||
fluent-templates = "0.13.2"
|
fluent-templates = "0.13.2"
|
||||||
unic-langid = "0.9.6"
|
unic-langid = "0.9.6"
|
||||||
sys-locale = "0.3.2"
|
sys-locale = "0.3.2"
|
||||||
|
|
|
||||||
21
LICENSE
21
LICENSE
|
|
@ -1,21 +0,0 @@
|
||||||
MIT License
|
|
||||||
|
|
||||||
Copyright (c) 2025 Marco De Araujo
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
145
README.md
145
README.md
|
|
@ -1,145 +0,0 @@
|
||||||
# Uptime Kuma Terminal Dashboard
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
A terminal-based monitoring dashboard for Uptime Kuma that displays service status, uptime percentages, and historical performance data directly in your terminal. Built with Rust for performance and reliability.
|
|
||||||
|
|
||||||
## Demo
|
|
||||||
|
|
||||||
<video width="800" controls>
|
|
||||||
<source src="assets/demo.webm" type="video/webm">
|
|
||||||
Your browser does not support the video tag.
|
|
||||||
</video>
|
|
||||||
|
|
||||||
## Overview
|
|
||||||
|
|
||||||
This personal project started as a way to monitor my home lab services without needing a web browser. It connects to your Uptime Kuma instance API and presents a clean, color-coded view of your services' status with real-time updates. The dashboard works great on servers, remote terminals, or anywhere you prefer a lightweight monitoring solution.
|
|
||||||
|
|
||||||
Perfect for DevOps engineers, system administrators, or anyone who prefers terminal workflows over web interfaces for quick status checks.
|
|
||||||
|
|
||||||
## Features
|
|
||||||
|
|
||||||
- Real-time service monitoring with automatic refresh
|
|
||||||
- Color-coded status indicators (green for up, red for down)
|
|
||||||
- Historical uptime visualization with compact status history lines
|
|
||||||
- Responsive terminal UI that adapts to window size
|
|
||||||
- Internationalization support (English and Portuguese)
|
|
||||||
- Configurable refresh intervals
|
|
||||||
- Minimal resource usage (runs efficiently even on low-power devices)
|
|
||||||
- Keyboard navigation support (arrow keys, home/end)
|
|
||||||
- Mobile-friendly design for SSH connections
|
|
||||||
|
|
||||||
## Tech Stack
|
|
||||||
|
|
||||||
This project demonstrates proficiency with several modern technologies:
|
|
||||||
|
|
||||||
- **Rust** (core language with async capabilities)
|
|
||||||
- **ratatui** (terminal UI framework)
|
|
||||||
- **reqwest** (HTTP client for API communication)
|
|
||||||
- **serde** (JSON serialization/deserialization)
|
|
||||||
- **clap** (command-line argument parsing)
|
|
||||||
- **fluent-templates** (internationalization framework)
|
|
||||||
- REST API integration patterns
|
|
||||||
- Error handling and logging best practices
|
|
||||||
- Cross-platform terminal development
|
|
||||||
|
|
||||||
You can find the latest releases in the [Releases section](https://git.marcodearaujo.com/marcodearaujo/uptime-kuma-dashboard/releases).
|
|
||||||
|
|
||||||
## Installation
|
|
||||||
|
|
||||||
### Option 1: Download built Binary (Recommended)
|
|
||||||
|
|
||||||
1. Go to the [Releases page](https://git.marcodearaujo.com/marcodearaujo/uptime-kuma-dashboard/releases)
|
|
||||||
2. Download the binary for your operating system:
|
|
||||||
- **Linux (x86_64)**: `uptime-kuma-dashboard-x86_64-unknown-linux-gnu`
|
|
||||||
- **Linux (ARM64)**: `uptime-kuma-dashboard-aarch64-unknown-linux-gnu` (Raspberry Pi, ARM servers)
|
|
||||||
- **Windows**: `uptime-kuma-dashboard-x86_64-pc-windows-gnu.exe`
|
|
||||||
3. Verify the checksum (recommended for security):
|
|
||||||
```bash
|
|
||||||
sha256sum -c SHA256SUMS.txt
|
|
||||||
```
|
|
||||||
4. Make it executable (Linux/ARM only):
|
|
||||||
```bash
|
|
||||||
chmod +x uptime-kuma-dashboard-*
|
|
||||||
```
|
|
||||||
5. Run with your parameters:
|
|
||||||
```bash
|
|
||||||
./uptime-kuma-dashboard-* --base-url="http://your-kuma:3001/" --slug="your-slug"
|
|
||||||
```
|
|
||||||
|
|
||||||
### Option 2: Build From Source
|
|
||||||
|
|
||||||
### Prerequisites
|
|
||||||
|
|
||||||
- Rust 1.74+ toolchain (install via [rustup](https://rustup.rs/))
|
|
||||||
- Uptime Kuma instance with API access
|
|
||||||
|
|
||||||
### Build from Source
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Clone the repository
|
|
||||||
git clone https://git.marcodearaujo.com/marcodearaujo/uptime-kuma-dashboard.git
|
|
||||||
cd uptime-kuma-dashboard
|
|
||||||
|
|
||||||
# Build the project
|
|
||||||
cargo build --release
|
|
||||||
|
|
||||||
# Run the dashboard (replace with your Uptime Kuma URL and status page slug)
|
|
||||||
./target/release/uptime-kuma-dashboard \
|
|
||||||
--base-url="http://your-uptime-kuma-instance:3001/" \
|
|
||||||
--slug="your-status-page-slug"
|
|
||||||
```
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
The dashboard requires two parameters:
|
|
||||||
|
|
||||||
- `--base-url`: Your Uptime Kuma instance URL (including port)
|
|
||||||
- `--slug`: Your status page slug identifier
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
./uptime-kuma-dashboard --base-url="http://192.168.1.100:3001/" --slug="home-services"
|
|
||||||
```
|
|
||||||
|
|
||||||
**Controls during runtime:**
|
|
||||||
|
|
||||||
- `q` or `ESC`: Exit the dashboard
|
|
||||||
- `↑`/`↓` or `k`/`j`: Navigate through monitors
|
|
||||||
- `Home`/`End`: Jump to top/bottom of the list
|
|
||||||
|
|
||||||
## Configuration
|
|
||||||
|
|
||||||
You can set environment variables to avoid typing parameters each time:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
export UPTIME_KUMA_URL="http://your-uptime-kuma-instance:3001/"
|
|
||||||
export STATUS_PAGE_SLUG="your-status-page-slug"
|
|
||||||
```
|
|
||||||
|
|
||||||
## Development Notes
|
|
||||||
|
|
||||||
This project follows Rust best practices including:
|
|
||||||
|
|
||||||
- Comprehensive error handling with `anyhow`
|
|
||||||
- Internationalization-ready architecture
|
|
||||||
- Modular code organization
|
|
||||||
- Performance optimization for terminal rendering
|
|
||||||
- Cross-platform compatibility testing
|
|
||||||
|
|
||||||
The architecture separates concerns into:
|
|
||||||
|
|
||||||
- API client layer
|
|
||||||
- Data processing core
|
|
||||||
- UI rendering components
|
|
||||||
- Configuration management
|
|
||||||
- Internationalization system
|
|
||||||
|
|
||||||
## License
|
|
||||||
|
|
||||||
This project is available under the MIT License - see the [LICENSE](LICENSE) file for details.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
_Developed as a personal learning project to improve Rust skills and create a useful tool for my home lab monitoring. Feedback welcome!_
|
|
||||||
BIN
assets/demo.webm
BIN
assets/demo.webm
Binary file not shown.
|
|
@ -1,11 +1,9 @@
|
||||||
use std::time::Duration;
|
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use reqwest::blocking::Client;
|
use reqwest::blocking::Client;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
api::endpoints::UptimeKumaEndpoints,
|
api::endpoints::UptimeKumaEndpoints,
|
||||||
data::{self, heartbeat::HeartbeatResponse, status_page::model::StatusPageResponse}, i18n::t,
|
data::{self, heartbeat::HeartbeatResponse, status_page::model::StatusPageResponse},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
|
@ -15,9 +13,8 @@ pub struct UptimeKumaClient {
|
||||||
|
|
||||||
impl UptimeKumaClient {
|
impl UptimeKumaClient {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
let client = Client::builder().connect_timeout(Duration::from_secs(10)).timeout(Duration::from_secs(30)).build().unwrap_or_else(|_| panic!("{}", t("http-build-error")));
|
|
||||||
Self {
|
Self {
|
||||||
client,
|
client: Client::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,12 @@
|
||||||
use crate::api::{UptimeKumaClient, UptimeKumaEndpoints};
|
use crate::api::{UptimeKumaClient, UptimeKumaEndpoints};
|
||||||
use crate::core;
|
use crate::core;
|
||||||
|
use crate::data::{heartbeat::HeartbeatResponse, status_page::model::StatusPageResponse};
|
||||||
use crate::i18n::{t, t_with_args};
|
use crate::i18n::{t, t_with_args};
|
||||||
use crate::ui::{
|
use crate::ui::{
|
||||||
components::{render_footer, render_header, render_monitor_list},
|
components::{render_footer, render_header, render_monitor_list},
|
||||||
dashboard::model::DashboardViewState,
|
dashboard::model::DashboardViewState,
|
||||||
};
|
};
|
||||||
|
use anyhow::Result;
|
||||||
use crossterm::{
|
use crossterm::{
|
||||||
event::{self, DisableMouseCapture, EnableMouseCapture, Event, KeyCode, KeyEventKind},
|
event::{self, DisableMouseCapture, EnableMouseCapture, Event, KeyCode, KeyEventKind},
|
||||||
execute,
|
execute,
|
||||||
|
|
@ -22,6 +24,8 @@ use ratatui::{
|
||||||
use std::{
|
use std::{
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
io,
|
io,
|
||||||
|
sync::mpsc,
|
||||||
|
thread,
|
||||||
time::{Duration, Instant},
|
time::{Duration, Instant},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -29,6 +33,11 @@ const INITIAL_INTERVAL: u32 = 300;
|
||||||
const MAIN_LAYOUT_WITH_SCROLLBAR: [Constraint; 2] = [Constraint::Min(1), Constraint::Length(1)];
|
const MAIN_LAYOUT_WITH_SCROLLBAR: [Constraint; 2] = [Constraint::Min(1), Constraint::Length(1)];
|
||||||
const MAIN_LAYOUT_WITHOUT_SCROLLBAR: [Constraint; 1] = [Constraint::Min(1)];
|
const MAIN_LAYOUT_WITHOUT_SCROLLBAR: [Constraint; 1] = [Constraint::Min(1)];
|
||||||
|
|
||||||
|
enum FetchResult {
|
||||||
|
Heartbeat(Result<HeartbeatResponse>),
|
||||||
|
StatusPage(Result<StatusPageResponse>),
|
||||||
|
}
|
||||||
|
|
||||||
pub struct App {
|
pub struct App {
|
||||||
state: DashboardViewState,
|
state: DashboardViewState,
|
||||||
terminal: Terminal<CrosstermBackend<io::Stdout>>,
|
terminal: Terminal<CrosstermBackend<io::Stdout>>,
|
||||||
|
|
@ -40,26 +49,6 @@ pub struct App {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl App {
|
impl App {
|
||||||
pub fn new(endpoints: UptimeKumaEndpoints) -> io::Result<Self> {
|
|
||||||
let backend = CrosstermBackend::new(io::stdout());
|
|
||||||
let mut terminal = Terminal::new(backend)?;
|
|
||||||
terminal.hide_cursor()?;
|
|
||||||
|
|
||||||
let state = DashboardViewState::new();
|
|
||||||
|
|
||||||
let initial_interval = Duration::from_secs(INITIAL_INTERVAL as u64);
|
|
||||||
|
|
||||||
Ok(Self {
|
|
||||||
state,
|
|
||||||
terminal,
|
|
||||||
should_quit: false,
|
|
||||||
last_update: Instant::now(),
|
|
||||||
update_interval: initial_interval,
|
|
||||||
endpoints,
|
|
||||||
client: UptimeKumaClient::new(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn setup_terminal(&mut self) -> io::Result<()> {
|
fn setup_terminal(&mut self) -> io::Result<()> {
|
||||||
enable_raw_mode()?;
|
enable_raw_mode()?;
|
||||||
execute!(io::stdout(), EnterAlternateScreen, EnableMouseCapture)?;
|
execute!(io::stdout(), EnterAlternateScreen, EnableMouseCapture)?;
|
||||||
|
|
@ -191,7 +180,7 @@ impl App {
|
||||||
}
|
}
|
||||||
|
|
||||||
let max_scroll = state
|
let max_scroll = state
|
||||||
.get_total_length()
|
.get_total_lenght()
|
||||||
.saturating_sub(area[0].height as usize)
|
.saturating_sub(area[0].height as usize)
|
||||||
.saturating_add(1);
|
.saturating_add(1);
|
||||||
|
|
||||||
|
|
@ -259,11 +248,57 @@ impl App {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fetch_and_update_data(&mut self) -> anyhow::Result<()> {
|
pub fn new(endpoints: UptimeKumaEndpoints) -> io::Result<Self> {
|
||||||
let heartbeat_result = self.client.fetch_heartbeat(&self.endpoints)?;
|
let backend = CrosstermBackend::new(io::stdout());
|
||||||
let status_page_result = self.client.fetch_status_page(&self.endpoints)?;
|
let mut terminal = Terminal::new(backend)?;
|
||||||
|
terminal.hide_cursor()?;
|
||||||
|
|
||||||
let unified_data = core::unify_data(&status_page_result, &heartbeat_result);
|
let state = DashboardViewState::new();
|
||||||
|
|
||||||
|
let initial_interval = Duration::from_secs(INITIAL_INTERVAL as u64);
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
state,
|
||||||
|
terminal,
|
||||||
|
should_quit: false,
|
||||||
|
last_update: Instant::now(),
|
||||||
|
update_interval: initial_interval,
|
||||||
|
endpoints,
|
||||||
|
client: UptimeKumaClient::new(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fetch_and_update_data(&mut self) -> anyhow::Result<()> {
|
||||||
|
let (tx, rx) = mpsc::channel();
|
||||||
|
|
||||||
|
let heartbeat_client = self.client.clone();
|
||||||
|
let heartbeat_endpoints = self.endpoints.clone();
|
||||||
|
let tx_clone = tx.clone();
|
||||||
|
thread::spawn(move || {
|
||||||
|
let result = heartbeat_client.fetch_heartbeat(&heartbeat_endpoints);
|
||||||
|
tx.send(FetchResult::Heartbeat(result)).unwrap();
|
||||||
|
});
|
||||||
|
|
||||||
|
let status_page_client = self.client.clone();
|
||||||
|
let status_page_endpoints = self.endpoints.clone();
|
||||||
|
|
||||||
|
thread::spawn(move || {
|
||||||
|
let result = status_page_client.fetch_status_page(&status_page_endpoints);
|
||||||
|
tx_clone.send(FetchResult::StatusPage(result)).unwrap();
|
||||||
|
});
|
||||||
|
|
||||||
|
let mut heartbeat_result = None;
|
||||||
|
let mut status_page_result = None;
|
||||||
|
|
||||||
|
for _ in 0..2 {
|
||||||
|
match rx.recv()? {
|
||||||
|
FetchResult::Heartbeat(result) => heartbeat_result = Some(result?),
|
||||||
|
FetchResult::StatusPage(result) => status_page_result = Some(result?),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let heartbeat_data = heartbeat_result.unwrap();
|
||||||
|
let status_page_data = status_page_result.unwrap();
|
||||||
|
let unified_data = core::unify_data(&status_page_data, &heartbeat_data);
|
||||||
self.state = DashboardViewState::from_unified_data(unified_data);
|
self.state = DashboardViewState::from_unified_data(unified_data);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ static STATUS_LINE_CACHE: OnceLock<RwLock<HashMap<u64, Line<'static>>>> = OnceLo
|
||||||
|
|
||||||
pub fn render_monitor_list(main_frame: &mut Frame, area: Rect, state: &mut DashboardViewState) {
|
pub fn render_monitor_list(main_frame: &mut Frame, area: Rect, state: &mut DashboardViewState) {
|
||||||
let available_height = area.height as usize;
|
let available_height = area.height as usize;
|
||||||
let max_scroll = state.get_total_length().saturating_sub(available_height);
|
let max_scroll = state.get_total_lenght().saturating_sub(available_height);
|
||||||
|
|
||||||
if state.scroll_state.get_position() > max_scroll {
|
if state.scroll_state.get_position() > max_scroll {
|
||||||
state.scroll_state = state.scroll_state.position(max_scroll);
|
state.scroll_state = state.scroll_state.position(max_scroll);
|
||||||
|
|
@ -48,7 +48,7 @@ pub fn render_monitor_list(main_frame: &mut Frame, area: Rect, state: &mut Dashb
|
||||||
let mut current_y = area.y as usize;
|
let mut current_y = area.y as usize;
|
||||||
let mut rendered_height = 0;
|
let mut rendered_height = 0;
|
||||||
let mut lines_skipped = 0;
|
let mut lines_skipped = 0;
|
||||||
let half = state.get_total_length().saturating_div(2);
|
let half = state.get_total_lenght().saturating_div(2);
|
||||||
|
|
||||||
for group in state.groups.iter() {
|
for group in state.groups.iter() {
|
||||||
let group_height = group.monitors.len() + BORDER_LINES_VIEW;
|
let group_height = group.monitors.len() + BORDER_LINES_VIEW;
|
||||||
|
|
@ -259,6 +259,7 @@ fn get_cached_status_line(status_history: &[MonitorStatus]) -> Line<'static> {
|
||||||
spans.extend(
|
spans.extend(
|
||||||
status_history
|
status_history
|
||||||
.iter()
|
.iter()
|
||||||
|
.rev()
|
||||||
.take(STATUS_LINE_LENGTH)
|
.take(STATUS_LINE_LENGTH)
|
||||||
.map(|status| get_status_span(status).clone()),
|
.map(|status| get_status_span(status).clone()),
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -81,7 +81,7 @@ impl DashboardViewState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_total_length(&self) -> usize {
|
pub fn get_total_lenght(&self) -> usize {
|
||||||
self.total_length
|
self.total_length
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue