diff --git a/src/logsqueak/tui/screens/block_selection.py b/src/logsqueak/tui/screens/block_selection.py index 922c245..4eabd5d 100644 --- a/src/logsqueak/tui/screens/block_selection.py +++ b/src/logsqueak/tui/screens/block_selection.py @@ -105,6 +105,10 @@ def __init__( self._llm_worker: Optional[Worker] = None self._indexing_worker: Optional[Worker] = None + # Status panel update timer + from textual.timer import Timer + self._status_update_timer: Optional[Timer] = None + def _initialize_block_states_from_journals( self, journals: Dict[str, LogseqOutline] @@ -254,10 +258,18 @@ def on_mount(self) -> None: # Update bottom panel with initial block self._update_current_block() + # Start polling timer to update status panel with background task progress + self._status_update_timer = self.set_interval(0.5, self._update_status_panel) + logger.info("phase1_on_mount_finished") def on_unmount(self) -> None: """Called when screen is unmounted.""" + # Stop status update timer + if self._status_update_timer: + self._status_update_timer.stop() + self._status_update_timer = None + # Cancel any running workers if self._llm_worker: self._llm_worker.cancel() @@ -556,6 +568,19 @@ def _update_selected_count(self) -> None: ) self.selected_count = count + def _update_status_panel(self) -> None: + """Update status panel with current background task progress. + + Called periodically by timer to show live progress from all background tasks, + including those started by other screens (e.g., page_indexing from Phase 1). + """ + try: + status_panel = self.query_one(StatusPanel) + status_panel.update_status() + except Exception: + # Widget not mounted or query failed + pass + # Background tasks def start_llm_classification(self) -> None: diff --git a/src/logsqueak/tui/screens/content_editing.py b/src/logsqueak/tui/screens/content_editing.py index 91bc224..9abbf3e 100644 --- a/src/logsqueak/tui/screens/content_editing.py +++ b/src/logsqueak/tui/screens/content_editing.py @@ -158,6 +158,10 @@ def __init__( self.candidate_page_names: Dict[str, list[str]] = {} # block_id -> page names self.page_contents: Dict[str, LogseqOutline] = {} # page_name -> outline + # Status panel update timer + from textual.timer import Timer + self._status_update_timer: Optional[Timer] = None + def compose(self) -> ComposeResult: """Compose the Phase 2 screen layout.""" with Container(id="phase2-container"): @@ -227,6 +231,29 @@ async def on_mount(self) -> None: if self.auto_start_workers: self._start_background_workers() + # Start polling timer to update status panel with background task progress + self._status_update_timer = self.set_interval(0.5, self._update_status_panel) + + def on_unmount(self) -> None: + """Called when screen is unmounted.""" + # Stop status update timer + if self._status_update_timer: + self._status_update_timer.stop() + self._status_update_timer = None + + def _update_status_panel(self) -> None: + """Update status panel with current background task progress. + + Called periodically by timer to show live progress from all background tasks, + including those started by other screens (e.g., page_indexing from Phase 1). + """ + try: + status_panel = self.query_one(StatusPanel) + status_panel.update_status() + except Exception: + # Widget not mounted or query failed + pass + def _start_background_workers(self) -> None: """Start background workers for LLM rewording and RAG search.""" if self.llm_client: diff --git a/src/logsqueak/tui/screens/integration_review.py b/src/logsqueak/tui/screens/integration_review.py index d3acc6c..a02c89f 100644 --- a/src/logsqueak/tui/screens/integration_review.py +++ b/src/logsqueak/tui/screens/integration_review.py @@ -184,6 +184,10 @@ def __init__( # Store polling timer so we can stop it when complete self._polling_timer = None + # Status panel update timer (separate from decision polling) + from textual.timer import Timer + self._status_update_timer: Optional[Timer] = None + def _group_decisions_by_block(self, decisions: List[IntegrationDecision]) -> dict: """Group decisions by knowledge_block_id. @@ -291,6 +295,9 @@ def on_mount(self) -> None: decision_list = self.query_one(DecisionList) decision_list.focus() + # Start polling timer to update status panel with background task progress + self._status_update_timer = self.set_interval(0.5, self._update_status_panel) + # Decisions are generated in Phase 2 and streamed into app.integration_decisions # Check task status to determine what to do blocks_ready = len(self.decisions_ready) @@ -330,6 +337,31 @@ def on_mount(self) -> None: status_panel = self.query_one(StatusPanel) status_panel.update_status() + def on_unmount(self) -> None: + """Called when screen is unmounted.""" + # Stop status update timer + if self._status_update_timer: + self._status_update_timer.stop() + self._status_update_timer = None + + # Stop decision polling timer + if self._polling_timer: + self._polling_timer.stop() + self._polling_timer = None + + def _update_status_panel(self) -> None: + """Update status panel with current background task progress. + + Called periodically by timer to show live progress from all background tasks, + including those started by other screens (e.g., page_indexing from Phase 1). + """ + try: + status_panel = self.query_one(StatusPanel) + status_panel.update_status() + except Exception: + # Widget not mounted or query failed + pass + def watch_current_decision_index(self, old_index: int, new_index: int) -> None: """React to changes in current_decision_index.