From 148e0a9391e4844518e2ab2ef1eadde9f1518708 Mon Sep 17 00:00:00 2001 From: Selectel ML Tokens Date: Thu, 10 Sep 2026 13:00:36 +0300 Subject: [PATCH] Fix: use 'refreshing' reactive to avoid Textual built-in loading dots Widget.loading is a Textual built-in reactive that swaps the widget for the default dots spinner. Our dashboard used the same name, so setting it True activated the built-in indicator (dots) instead of the dog loader. Renamed to 'refreshing' and assert app.screen.loading stays False in tests. --- src/selectel_ml_tui/ui/app.py | 10 +++++----- tests/test_tui.py | 6 ++++++ 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/selectel_ml_tui/ui/app.py b/src/selectel_ml_tui/ui/app.py index 82d3586..ced99e5 100644 --- a/src/selectel_ml_tui/ui/app.py +++ b/src/selectel_ml_tui/ui/app.py @@ -134,7 +134,7 @@ class DashboardScreen(Screen[Any]): ] data = reactive(DashboardData()) - loading = reactive(False) + refreshing = reactive(False) def __init__( self, @@ -169,22 +169,22 @@ class DashboardScreen(Screen[Any]): @work(exclusive=True, group="refresh") async def _refresh(self) -> None: - self.loading = True + self.refreshing = True try: self.data = await self._service.refresh() except Exception as exc: # noqa: BLE001 - показываем toast при ошибке self.notify(f"Ошибка обновления: {exc}", severity="error") finally: - self.loading = False + self.refreshing = False - def watch_loading(self, loading: bool) -> None: + def watch_refreshing(self, refreshing: bool) -> None: """Показать/скрыть собачку и строку прогресса при обновлении.""" try: loader = self.query_one("#dog-loader", DogLoader) line = self.query_one("#progress-line", Static) except NoMatches: # watcher может сработать до монтирования детей return - if loading: + if refreshing: loader.add_class("visible") loader.start() line.update("[b]🐕 Собачка обновляет статистику…[/]") diff --git a/tests/test_tui.py b/tests/test_tui.py index 2f0bd14..3c3570f 100644 --- a/tests/test_tui.py +++ b/tests/test_tui.py @@ -317,9 +317,12 @@ async def test_dog_loader_hidden_when_idle(tmp_path) -> None: await pilot.pause() loader = app.screen.query_one("#dog-loader", DogLoader) assert not loader.has_class("visible") + assert loader.display is False assert not loader.running line = app.screen.query_one("#progress-line", Static) assert str(line.render()) == "" + # встроенный loading Textual не должен активироваться (иначе — точки) + assert app.screen.loading is False async def test_dog_loader_shown_during_refresh(tmp_path) -> None: @@ -339,13 +342,16 @@ async def test_dog_loader_shown_during_refresh(tmp_path) -> None: await pilot.pause() loader = app.screen.query_one("#dog-loader", DogLoader) assert loader.has_class("visible") + assert loader.display is True assert loader.running line = app.screen.query_one("#progress-line", Static) assert "обновляет статистику" in str(line.render()) + assert app.screen.loading is False release.set() await pilot.pause(0.1) assert not loader.has_class("visible") + assert loader.display is False assert not loader.running assert str(line.render()) == ""