fix: resolve ruff lint errors in TUI modules

This commit is contained in:
AFredefon
2026-03-11 06:57:38 +01:00
parent 9cfbc29677
commit 462f6ed408
4 changed files with 28 additions and 20 deletions

View File

@@ -46,13 +46,14 @@ class SingleClickDataTable(DataTable):
class RowClicked(Message):
"""Fired on every single mouse click on a data row."""
def __init__(self, data_table: "SingleClickDataTable", cursor_row: int) -> None:
def __init__(self, data_table: SingleClickDataTable, cursor_row: int) -> None:
self.data_table = data_table
self.cursor_row = cursor_row
super().__init__()
@property
def control(self) -> "SingleClickDataTable":
def control(self) -> SingleClickDataTable:
"""Return the data table that fired this event."""
return self.data_table
async def _on_click(self, event: events.Click) -> None: # type: ignore[override]
@@ -471,7 +472,6 @@ class FuzzForgeApp(App[None]):
@work(thread=True)
def _run_build(self, server_name: str, image: str, hub_name: str) -> None:
"""Build a Docker/Podman image in a background thread."""
import subprocess
from fuzzforge_cli.tui.helpers import build_image, find_dockerfile_for_server
logs = self._build_logs.setdefault(image, [])
@@ -481,7 +481,7 @@ class FuzzForgeApp(App[None]):
logs.append(f"ERROR: Dockerfile not found for '{server_name}' in hub '{hub_name}'")
self._build_results[image] = False
self._active_builds.pop(image, None)
self.call_from_thread(self._on_build_done, image, False)
self.call_from_thread(self._on_build_done, image, success=False)
return
logs.append(f"Building {image} from {dockerfile.parent}")
@@ -493,13 +493,14 @@ class FuzzForgeApp(App[None]):
logs.append(f"ERROR: {exc}")
self._build_results[image] = False
self._active_builds.pop(image, None)
self.call_from_thread(self._on_build_done, image, False)
self.call_from_thread(self._on_build_done, image, success=False)
return
self._active_builds[image] = proc # replace pending marker with actual process
self.call_from_thread(self._refresh_hub) # show ⏳ in table
assert proc.stdout is not None
if proc.stdout is None:
return
for line in proc.stdout:
logs.append(line.rstrip())
@@ -507,10 +508,10 @@ class FuzzForgeApp(App[None]):
self._active_builds.pop(image, None)
success = proc.returncode == 0
self._build_results[image] = success
self.call_from_thread(self._on_build_done, image, success)
self.call_from_thread(self._on_build_done, image, success=success)
def _on_build_done(self, image: str, success: bool) -> None:
"""Called on the main thread when a background build finishes."""
def _on_build_done(self, image: str, *, success: bool) -> None:
"""Handle completion of a background build on the main thread."""
self._refresh_hub()
if success:
self.notify(f"{image} built successfully", severity="information")

View File

@@ -8,6 +8,7 @@ and managing linked MCP hub repositories.
from __future__ import annotations
import contextlib
import json
import os
import subprocess
@@ -301,9 +302,10 @@ def _discover_hub_dirs() -> list[Path]:
candidates: list[Path] = []
for base in (get_fuzzforge_user_dir() / "hubs", get_fuzzforge_dir() / "hubs"):
if base.is_dir():
for entry in base.iterdir():
if entry.is_dir() and (entry / ".git").is_dir():
candidates.append(entry)
candidates.extend(
entry for entry in base.iterdir()
if entry.is_dir() and (entry / ".git").is_dir()
)
return candidates
@@ -356,10 +358,8 @@ def load_hubs_registry() -> dict[str, Any]:
registry: dict[str, Any] = {"hubs": hubs}
# Persist so we don't re-scan on every load
try:
with contextlib.suppress(OSError):
save_hubs_registry(registry)
except OSError:
pass
return registry

View File

@@ -30,6 +30,7 @@ class BuildImageScreen(ModalScreen[bool]):
self._hub_name = hub_name
def compose(self) -> ComposeResult:
"""Build the confirmation dialog UI."""
with Vertical(id="build-dialog"):
yield Label(f"Build {self._image}", classes="dialog-title")
yield Label(
@@ -38,7 +39,7 @@ class BuildImageScreen(ModalScreen[bool]):
)
yield Label(
"The image will be built in the background.\n"
"You\'ll receive a notification when it\'s done.",
"You'll receive a notification when it's done.",
id="confirm-text",
)
with Horizontal(classes="dialog-buttons"):
@@ -46,10 +47,12 @@ class BuildImageScreen(ModalScreen[bool]):
yield _NoFocusButton("Cancel", variant="default", id="btn-cancel")
def on_button_pressed(self, event: Button.Pressed) -> None:
"""Handle Build or Cancel button clicks."""
if event.button.id == "btn-build":
self.dismiss(True)
self.dismiss(result=True)
elif event.button.id == "btn-cancel":
self.dismiss(False)
self.dismiss(result=False)
def action_cancel(self) -> None:
self.dismiss(False)
"""Dismiss the dialog when Escape is pressed."""
self.dismiss(result=False)

View File

@@ -29,6 +29,7 @@ class BuildLogScreen(ModalScreen[None]):
self._last_line: int = 0
def compose(self) -> ComposeResult:
"""Build the log viewer UI."""
with Vertical(id="build-dialog"):
yield Label(f"Build log — {self._image}", classes="dialog-title")
yield Label("", id="build-status")
@@ -37,6 +38,7 @@ class BuildLogScreen(ModalScreen[None]):
yield _NoFocusButton("Close", variant="default", id="btn-close")
def on_mount(self) -> None:
"""Initialize log polling when the screen is mounted."""
self._flush_log()
self.set_interval(0.5, self._poll_log)
@@ -63,12 +65,14 @@ class BuildLogScreen(ModalScreen[None]):
status.update(f"[red]✗ {self._image} build failed[/red]")
def _poll_log(self) -> None:
"""Called every 500 ms by set_interval."""
"""Poll for new log lines periodically."""
self._flush_log()
def on_button_pressed(self, event: Button.Pressed) -> None:
"""Handle Close button click."""
if event.button.id == "btn-close":
self.dismiss(None)
def action_close(self) -> None:
"""Dismiss the dialog when Escape is pressed."""
self.dismiss(None)