Files
oxkerclone/REVIEW_FINDINGS.md
Niko Syring d41761d6e9 feat: complete Rust-to-Go rewrite with Bubbletea v2
Rewrites oxker from Rust/ratatui to Go/Bubbletea, migrated to the
Bubbletea v2 API (charm.land/bubbletea/v2). Removes all original Rust
source files and legacy Go modules (internal/ui, internal/input, bubbles).

Key changes:
- View() returns tea.View with declarative AltScreen and MouseMode
- KeyMsg → KeyPressMsg, MouseMsg → MouseClickMsg/WheelMsg/MotionMsg/ReleaseMsg
- execWriteKey rewritten for v2 key fields (Code/Mod/Text)
- Mouse toggle via View field instead of imperative commands
- Filter/search text input uses msg.Text for v2 space key compat

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 03:41:14 +01:00

18 KiB

Oxker Go Rewrite — Review Findings

Systematischer Vergleich aller Original-Rust-Dateien mit der Go-Reimplementierung. 6 parallele Review-Agenten, ~130 Findings gesamt.


CRITICAL (App funktioniert falsch)

C1. CPU immer 0 — ContainerStatsOneShot liefert leere precpu_stats

  • Source: Docker Integration Review #11
  • Rust: docker_data/mod.rs:136-143stream: false, one_shot: false + .take(1)
  • Go: docker/client.go:70ContainerStatsOneShot setzt one-shot=true
  • Problem: Mit one-shot=true liefert Docker leere precpu_stats, CPU-Berechnung ergibt 0
  • Fix: ContainerStats mit stream=false statt ContainerStatsOneShot verwenden
  • Status: [x] FIXED

C2. uint64 Underflow bei CPU-Berechnung

  • Source: Docker Integration Review #6/#7
  • Rust: docker_data/mod.rs:86-91saturating_sub verhindert Underflow
  • Go: app.go:1120-1121 — plain uint64 Subtraktion, kann wrappen
  • Fix: Guard: if TotalUsage < PreTotalUsage { return 0 }
  • Status: [x] FIXED

C3. --host Flag wird ignoriert

  • Source: Docker Integration Review #1
  • Rust: main.rs:47-57 — Config Host > DOCKER_HOST env > default socket
  • Go: docker/client.go:17-22 — nur FromEnv, ignoriert Config.Host
  • Fix: docker.New() soll optionalen Host akzeptieren, client.WithHost(host) verwenden
  • Status: [x] FIXED

C4. Logs ShowStderr Config ignoriert

  • Source: Docker Integration Review #8
  • Rust: docker_data/mod.rs:256-258config.show_std_err
  • Go: app.go:1089-1091 — hardcoded ShowStderr: true
  • Fix: ShowStderr: a.Config.ShowStdErr
  • Status: [x] FIXED

C5. Bandwidth-Chart zeigt kumulative Bytes statt Rate

  • Source: Data Model Review #8
  • Rust: container_state.rs:627-672NetworkBandwidth.to_vec_f64 berechnet Deltas
  • Go: app.go:1493-1508fmtRate(c.RxBytes) auf kumulative Rohwerte
  • Fix: Bandwidth als Differenz zwischen aufeinanderfolgenden Einträgen berechnen
  • Status: [x] FIXED

C6. RunningUnhealthy — fehlt pause/restart in Commands

  • Source: Data Model Review #2, Main UI Review #6
  • Rust: container_state.rs:451Running(_) => [Pause, Restart, Stop, Delete]
  • Go: app.go:1749-1750RunningUnhealthy nur ["stop", "delete"]
  • Fix: Gleiche Commands wie RunningHealthy
  • Status: [x] FIXED

C7. Enter führt immer ersten Command aus — kein Command-Selection

  • Source: Input Review #6, Data Model Review #4, Main UI Review #8
  • Rust: input_handler/mod.rs:267 — prüft panel == Commands, nutzt selected_docker_controls()
  • Go: app.go:922cmds[0] immer, unabhängig von Panel
  • Fix: CmdSelectedIdx Feld, nur bei ActivePanel == PanelCommands ausführen
  • Status: [x] FIXED

C8. Ctrl+C quit nicht in Filter/Search-Modus

  • Source: Input Review #9
  • Rust: input_handler/mod.rs:762-763 — Ctrl+C immer quit
  • Go: app.go:360-367 — Filter/Search early return, Ctrl+C wird nie erreicht
  • Fix: Ctrl+C Check vor Mode-Dispatch
  • Status: [x] FIXED

C9. Mouse-Events nicht blockiert in Overlay-Modi

  • Source: Input Review #10
  • Rust: input_handler/mod.rs:74-84 — blockiert Mouse in Error/Help/Filter/Search/DeleteConfirm
  • Go: app.go:638 — keine Mode-Checks, Mouse immer aktiv
  • Fix: Mode-Checks am Anfang von handleMouse
  • Status: [x] FIXED

C10. Info-Popup Auto-Dismiss fehlt (4 Sekunden)

  • Source: Popups Review #9
  • Rust: info.rs:52-54instant.elapsed() > 4000ms
  • Go: app.go:1003-1006 — Kommentar sagt "handled by tick", aber kein Timer
  • Fix: tea.Tick(4*time.Second)InfoDismissMsg
  • Status: [x] FIXED

HIGH (UI sieht falsch aus)

H1. CPU-Format ohne Zero-Padding

  • Source: Main UI Review #2
  • Rust: container_state.rs:521{:05.2}%00.00%, 05.34%
  • Go: app.go:1325%.2f%%0.00%, 5.34%
  • Fix: fmt.Sprintf("%05.2f%%", c.CPUPercent)
  • Status: [x] FIXED

H2. Container-Spalten ohne Farben (Name/ID/Image/RX/TX)

  • Source: Main UI Review #10/#11
  • Rust: containers.rs:26-33 — Name/ID/Image mit containers.text (Blue), RX/TX eigene Farben
  • Go: app.go:1321-1332 — kein Styling
  • Fix: lipgloss.Foreground für Name/ID/Image und separate Farben für RX/TX
  • Status: [x] FIXED

H3. Command-Farben falsch

  • Source: Main UI Review #5
  • Rust: restart=Magenta, delete=Gray, resume=Blue, start=Green, stop=Red, pause=Yellow
  • Go: restart/resume/start=Green, stop/delete=Red, pause=Yellow
  • Fix: Jeder Command eigene Farbe
  • Status: [x] FIXED

H4. Layout-Proportionen falsch

  • Source: Main UI Review #17
  • Rust: ui/mod.rs:400 — 75%/25% (oben/unten)
  • Go: app.go:1664-1686 — 30% Container, 22% Charts, Rest Logs
  • Fix: 75%/25% Split, dann Container/Logs innerhalb der 75%
  • Status: [x] FIXED

H5. Ports: :: und 0 statt leer

  • Source: Charts/Ports Review #15/#16
  • Rust: container_state.rs:156-160 — None → leerer String
  • Go: app.go:1522-1523:: für leere IP, 0 für fehlenden Public Port
  • Fix: Leere Strings statt :: und 0
  • Status: [x] FIXED

H6. Falsches Highlight-Symbol

  • Source: Main UI Review #12
  • Rust: mod.rs:47 (offener Kreis)
  • Go: app.go:1315 (gefüllter Kreis, blau)
  • Fix: verwenden
  • Status: [x] FIXED

H7. Default-Sort fehlt (nach CreatedAt)

  • Source: Data Model Review #13
  • Rust: mod.rs:492-499 — sort by created + Name als Tiebreaker
  • Go: app.go:829-831 — kein Sort bei SortNone
  • Fix: Bei SortNone nach CreatedAt sortieren, Name als Tiebreaker
  • Status: [x] FIXED

H8. Sort verliert Selection

  • Source: Data Model Review #6
  • Rust: mod.rs:377-387 — re-selects Container by ID nach Sort
  • Go: app.go:812-827 — SelectedIdx bleibt gleich, Container an Position ändert sich
  • Fix: Nach Sort alten Container per ID finden und SelectedIdx aktualisieren
  • Status: [x] FIXED

H9. Sort Tiebreaker by Name fehlt

  • Source: Data Model Review #15
  • Rust: mod.rs:437-484.then_with(|| name.cmp(name))
  • Go: app.go:834-866 — kein Tiebreaker
  • Fix: Name-Vergleich als Tiebreaker bei Gleichheit
  • Status: [x] FIXED

H10. State-Reihenfolge beim Sort falsch

  • Source: Data Model Review #14
  • Rust: container_state.rs:316-327 — Healthy=0, Unhealthy=1, Paused=2, Restarting=3, etc.
  • Go: iota-Reihenfolge weicht ab (Exited vor Restarting)
  • Fix: order() Methode mit Rust-Mapping
  • Status: [x] FIXED

H11. Search-Highlight: ganze Zeile statt Substring

  • Source: Charts/Ports Review #22
  • Rust: Substring-Level Highlighting
  • Go: app.go:1422-1423 — ganze Zeile gelb
  • Fix: Nur gematchten Substring highlighten
  • Status: [x] FIXED

H12. Help wird als Vollbild gerendert statt Overlay

  • Source: Popups Review #11
  • Rust: mod.rs:477-480 — Overlay auf Base View
  • Go: app.go:1175-1177 — ersetzt komplett den View
  • Fix: Base View rendern, dann Help darüber legen
  • Status: [x] FIXED

H13. Log-Zeilen: Byte-Length statt Rune-Length für UTF-8

  • Source: Main UI Review #28
  • Rust: .chars().count() für Width
  • Go: app.go:1409-1414len(line) (Bytes)
  • Fix: []rune(line) oder runewidth verwenden
  • Status: [x] FIXED

H14. Bandwidth-Chart: Keine historischen Daten gerendert

  • Source: Charts/Ports Review #6
  • Rust: chart_bandwidth.rs:92-109 — zwei Line-Datasets (RX/TX)
  • Go: app.go:1493-1508 — nur Text-Labels, kein Sparkline
  • Fix: Sparklines für RX/TX History hinzufügen
  • Status: [x] FIXED

H15. LogHeight Default: 40 statt 75

  • Source: Popups Review #23
  • Rust: gui_state.rs:220 — default 75
  • Go: app.go:213 — default 40
  • Fix: Default auf 75 ändern
  • Status: [x] FIXED

MEDIUM (Verhaltensunterschiede)

M1. Binate Stats-Sammlung fehlt (keine Deduplizierung)

  • Source: Docker Integration Review #2
  • Rust: docker_data/mod.rs:44-61 — Binate-Enum, Spawn-Deduplizierung
  • Go: app.go:1043-1081 — keine Tracking, Duplikate möglich
  • Fix: pendingStats map[string]bool für In-Flight Tracking
  • Status: [x] FIXED

M2. Logs: Tail-500 statt inkrementell (since-Timestamp)

  • Source: Docker Integration Review #9
  • Rust: docker_data/mod.rs:256-273since Parameter, akkumuliert
  • Go: app.go:1091Tail: "500", ersetzt jedes Mal
  • Status: [x] FIXED — uses since for incremental fetching after initial load

M3. Per-Container Log-Speicher fehlt

  • Source: Data Model Review #3
  • Rust: ContainerItem.logs — HashSet mit Dedup, per-Container Scroll
  • Go: App.LogLines — einzelner globaler Slice
  • Status: [x] FIXED — Container.Logs/LogScroll/LogHScroll with save/restore on selection change

M4. Container-Selbstfilterung (oxker-Container verstecken) fehlt

  • Source: Docker Integration Review #12, Data Model Review #9
  • Rust: docker_data/mod.rs:229-234 — ENTRY_POINT Filter
  • Go: keine Selbstfilterung
  • Status: [x] FIXED — respects Config.ShowSelf

M5. Docker Ping-Check bei Startup fehlt

  • Source: Docker Integration Review #15
  • Rust: main.rs:68-88 — Ping + Error mit Host-Pfad
  • Go: app.go:207docker.New() Error wird ignoriert
  • Status: [x] FIXED — Ping + Host in error message

M6. Filter-Mode: / beendet nicht den Modus (wird als Text eingegeben)

  • Source: Input Review #14
  • Rust: input_handler:523-528/ beendet Filter-Mode
  • Go: app.go:570-590/ wird als Zeichen eingefügt
  • Status: [x] FIXED (already implemented — / in enter case)

M7. Search-Mode: # beendet nicht den Modus

  • Source: Input Review #15
  • Rust: input_handler:409-414# beendet Search-Mode
  • Go: app.go:598-631# wird als Zeichen eingefügt
  • Status: [x] FIXED (already implemented — # in enter case)

M8. Direkte Action-Keys (s/x/r/d/p/u) existieren in Rust nicht

  • Source: Input Review #17
  • Rust: Actions nur über Commands-Panel mit Enter
  • Go: app.go:478-489 — direkte Shortcuts
  • Note: Go-Erweiterung, könnte gewollt sein, aber kollidiert mit Rust-Keybindings
  • Status: [x] WONTFIX — bewusste Erweiterung, Shortcuts sind nützlich

M9. Mouse-Scroll-Amount: 3 statt 1 (mit 10x Modifier)

  • Source: Input Review #19
  • Rust: input_handler:828-829 — Scroll by 1 oder 10 mit Ctrl
  • Go: app.go:639-644 — hardcoded 3
  • Status: [x] FIXED (already 1)

M10. Mouse-Scroll in Inspect-Mode nicht unterstützt

  • Source: Input Review #20
  • Rust: input_handler:810-818 — Mouse-Scroll im Inspect
  • Go: handleMouse hat keinen Inspect-Check
  • Status: [x] FIXED (via C9)

M11. Error-Mode: andere Keys nicht blockiert

  • Source: Input Review #24
  • Rust: handle_error — nur clear/quit Keys
  • Go: Sort-Keys, Scroll-Keys etc. funktionieren während Error
  • Status: [x] FIXED (via C8)

M12. Unknown-State: falsche Commands

  • Source: Main UI Review #7
  • Rust: container_state.rs:452Unknown => [Delete] nur
  • Go: app.go:1753-1754Unknown => [start, restart, delete]
  • Status: [x] FIXED (via C6)

M13. Commands-Panel Scroll fehlt

  • Source: Input Review #5
  • Rust: docker_controls_scroll bewegt Command-Selection
  • Go: Scroll im Commands-Panel ändert Container-Selection
  • Status: [x] FIXED (via C7)

M14. Commands-Panel Breite: fest 14 statt 10%

  • Source: Main UI Review #4
  • Rust: ui/mod.rs:419Percentage(10)
  • Go: app.go:1278cmdW := 14
  • Status: [x] FIXED — 10% mit min 12

M15. DockerConnect Error: kein Countdown, kein Auto-Exit

  • Source: Popups Review #6/#17
  • Rust: 5-Sekunden Countdown, Auto-Exit, Host-Anzeige
  • Go: Standard-Error-Popup
  • Status: [x] FIXED — 5s countdown + auto-exit + host in error message

M16. Delete-Dialog: Name nicht bold/highlighted

  • Source: Popups Review #1
  • Rust: delete_confirm.rs:44-53 — Name bold + highlighted
  • Go: app.go:1542 — einfacher String
  • Status: [x] FIXED

M17. Help-View: stark reduzierter Inhalt

  • Source: Popups Review #12
  • Rust: ~570 Zeilen, Logo, Version, Config-Pfad, Timezone, alle Keys
  • Go: ~20 Zeilen, nur Basis-Keys
  • Status: [x] FIXED — erweitert mit Config-Pfad, Panel-Info, vollständiger Keybinding-Liste

M18. Container-Name: führender / wird nicht entfernt

  • Source: Charts/Ports Review #30
  • Rust: inspect.rs:35-38 — Strip / Prefix
  • Go: Name direkt verwendet
  • Status: [x] FIXED (already done via TrimPrefix)

M19. Inspect: Wrapping statt Truncation

  • Source: Charts/Ports Review #29
  • Rust: inspect.rs:133Wrap { trim: false }
  • Go: app.go:1603 — Truncation
  • Status: [x] FIXED

M20. Spaltenbreiten fest statt dynamisch

  • Source: Main UI Review #1, Data Model Review #17
  • Rust: mod.rs:845-879 — max Width pro Spalte aus Daten
  • Go: app.go:1264-1273 — feste Prozent-Widths
  • Status: [x] FIXED — dynamic widths based on container data

M21. State-Icons: andere Unicode-Zeichen

  • Source: Main UI Review #24
  • Rust: , , , , !, ?
  • Go: , , , , !, ?
  • Status: [x] FIXED — ✓ statt ✔

M22. Search-Navigation: Ctrl+N/P statt Down/Up

  • Source: Input Review #16
  • Rust: Down/Up Arrow für nächsten/vorherigen Match
  • Go: Ctrl+N/Ctrl+P
  • Status: [x] FIXED (already supports both Down/Up and Ctrl+N/P)

M23. Log-Search Case-Sensitivity nicht konfigurierbar

  • Source: Data Model Review #19
  • Rust: config.log_search_case_sensitive
  • Go: immer case-insensitive
  • Status: [x] FIXED — respects Config.LogSearchCaseSensitive

M24. Filter wraps around (Go), Rust stoppt an Grenzen

  • Source: Data Model Review #16
  • Rust: FilterBy::next()/prev() gibt None an Grenzen
  • Go: Modulo-Wrapping
  • Status: [x] FIXED — stoppt an Grenzen

M25. Overlay-Popups: base Parameter wird ignoriert

  • Source: Popups Review #16
  • Go: overlayError(base), overlayInfo(base) — base wird nie verwendet
  • Status: [x] FIXED — overlay placement with transparent bg

LOW (Kosmetische/Konfigurationsunterschiede)

L1. Alle Farben hardcoded statt aus Config

  • Betrifft: alle Panels, Popups, Charts, Headers
  • Config AppColors existiert, wird aber nie gelesen
  • Status: [x] FIXED — colorOr() resolver, borders/commands/state colors from config

L2. Custom Keymaps nicht implementiert

  • Config Keymap existiert, wird aber nie verwendet
  • Alle Keys sind hardcoded Strings
  • Status: [x] FIXED — keyMatch() checks config keymap with hardcoded fallbacks

L3. Mouse-Capture Toggle (m Key) fehlt

  • Source: Input Review #1
  • Status: [x] FIXED

L4. Force-Redraw Key (f) fehlt

  • Source: Input Review #2
  • Status: [x] FIXED — tea.ClearScreen

L5. Container-Name/Image Truncation bei 30 Zeichen

  • Source: Data Model Review #18
  • Status: [x] FIXED (handled by dynamic column widths M20)

L6. CpuStats Epsilon: 0.001 statt 0.01

  • Source: Data Model Review #24
  • Status: [x] FIXED (already 0.001)

L7. fmtRate fehlt GB/s Tier

  • Source: Data Model Review #23
  • Status: [x] FIXED

L8. InspectData: Name/ID nicht beim Inspizieren gespeichert

  • Source: Data Model Review #21
  • Status: [x] FIXED (already shown in viewInspect title)

L9. Scroll-Speed Modifier: Shift statt Ctrl

  • Source: Input Review #3
  • Status: [x] FIXED (already uses J/K = Shift+j/k)

L10. Horizontal-Scroll in Search-Mode fehlt

  • Source: Input Review #8
  • Status: [x] FIXED — left/right in search mode

L11. Header: "show help" → "exit help" Toggle fehlt

  • Source: Main UI Review #19
  • Status: [x] FIXED

L12. Header: ↓ rx / ↑ tx Pfeile existieren nicht in Rust

  • Source: Main UI Review #20
  • Status: [x] FIXED — removed arrows

L13. Charts: State-abhängige Farben fehlen

  • Source: Charts/Ports Review #4/#8
  • Status: [x] FIXED — dim color for non-running states

L14. Charts: Y-Achse Max-Wert fehlt

  • Source: Charts/Ports Review #2
  • Status: [x] FIXED — max label shown

L15. Filter-Bar: kein dediziertes UI (nur inline Text)

  • Source: Charts/Ports Review #17/#18
  • Status: [x] FIXED — dedicated styled filter bar

L16. Search-Bar: kein dediziertes UI (nur inline Text)

  • Source: Charts/Ports Review #20/#21
  • Status: [x] FIXED — dedicated styled search bar

L17. Ports: Title nicht zentriert, nicht als Border-Title

  • Source: Charts/Ports Review #31
  • Status: [x] FIXED — centered title

L18. Inspect: Scroll-Clamping fehlt

  • Source: Charts/Ports Review #27
  • Status: [x] FIXED — clampInspectScroll()

L19. "No containers" Message fehlt

  • Source: Main UI Review #29
  • Status: [x] FIXED

L20. Minimum Terminal-Size Handling fehlt

  • Source: Main UI Review #30
  • Status: [x] FIXED — 60x10 minimum with message

L21. Logs: "parsing logs" Init-State fehlt

  • Source: Main UI Review #14
  • Status: [x] FIXED

L22. Logs: scroll_padding fehlt

  • Source: Main UI Review #15
  • Status: [x] FIXED — auto-follow when at bottom

L23. Logs: color_logs Toggle fehlt

  • Source: Main UI Review #16
  • Status: [x] FIXED — stripAnsi when ColorLogs=false

L24. appendMax Slice-Leak (kein Ring-Buffer)

  • Source: Data Model Review #22
  • Status: [x] FIXED — in-place copy instead of reslice

L25. Delete-Dialog: Container-Not-Found Guard fehlt

  • Source: Popups Review #2
  • Status: [x] FIXED — guard + default name

L26. Network: alle Interfaces statt nur eth0

  • Source: Docker Integration Review #3
  • Note: Go-Verhalten ist besser, bewusste Abweichung
  • Status: [x] WONTFIX — bewusste Verbesserung