From 671e333454028e373c85e920708660b40bb15283 Mon Sep 17 00:00:00 2001 From: Astha Singh Date: Sun, 31 May 2026 00:16:24 +0530 Subject: [PATCH 1/3] Disable runtime actions when disconnected --- adiuvare/tui/screens/audit.py | 25 +++++++++++++++++++++++++ adiuvare/tui/screens/events.py | 30 ++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+) diff --git a/adiuvare/tui/screens/audit.py b/adiuvare/tui/screens/audit.py index 3ab15cc..0fb1131 100644 --- a/adiuvare/tui/screens/audit.py +++ b/adiuvare/tui/screens/audit.py @@ -223,6 +223,7 @@ def _action_states(self, event: dict | None) -> dict[str, ActionAvailability]: has = event is not None verdict = str(event.get("verdict", "allow")) if event else "allow" ip = str(event.get("ip", "") or "") if event else "" +<<<<<<< HEAD has_ip = bool(ip and ip != "-") connected = self._app().connected select_first = "Select an audit row first" @@ -264,6 +265,30 @@ def _update_actions(self) -> None: blocked_reasons=blocked_reasons, ) ) +======= + connected = self._app().connected + + self.query_one("#audit-ban-ip", Button).disabled = ( + not connected or not has or not ip or ip == "-" + ) + + self.query_one("#audit-unban-ip", Button).disabled = ( + not connected or not has or not ip or ip == "-" + ) + + self.query_one("#audit-monitor", Button).disabled = ( + not connected or not has + ) + + self.query_one("#audit-unmonitor", Button).disabled = ( + not connected or not has + ) + + self.query_one("#audit-whitelist", Button).disabled = ( + not connected or not has or verdict == "allow" + ) + self.query_one("#audit-export-btn", Button).disabled = not has +>>>>>>> 8493416 (Disable runtime actions when disconnected) def _render_detail(self) -> None: panel = self.query_one("#audit-detail-panel", Static) diff --git a/adiuvare/tui/screens/events.py b/adiuvare/tui/screens/events.py index d79a0a8..791f673 100644 --- a/adiuvare/tui/screens/events.py +++ b/adiuvare/tui/screens/events.py @@ -242,11 +242,41 @@ def _action_states(self, event: dict | None) -> dict[str, ActionAvailability]: has = event is not None verdict = str(event.get("verdict", "allow")) if event else "allow" ip = str(event.get("ip", "") or "") if event else "" +<<<<<<< HEAD has_ip = bool(ip and ip != "-") connected = self._app().connected select_first = "Select an event row first" runtime = require_runtime_connection +======= + connected = self._app().connected + + self.query_one("#events-confirm", Button).disabled = not has or verdict == "block" + self.query_one("#events-whitelist", Button).disabled = ( + not connected or not has + ) + + self.query_one("#events-monitor", Button).disabled = ( + not connected or not has + ) + + self.query_one("#events-unmonitor", Button).disabled = ( + not connected or not has + ) + + self.query_one("#events-unblock-monitor", Button).disabled = ( + not connected or not has or verdict != "block" + ) + + self.query_one("#events-ban-ip", Button).disabled = ( + not connected or not has or not ip or ip == "-" + ) + + self.query_one("#events-unban-ip", Button).disabled = ( + not connected or not has or not ip or ip == "-" + ) + self.query_one("#events-export", Button).disabled = not has +>>>>>>> 8493416 (Disable runtime actions when disconnected) return { "events-confirm": runtime( From d3c497721fcec87494d820610f2715b22215be71 Mon Sep 17 00:00:00 2001 From: Astha Singh Date: Sun, 31 May 2026 00:16:24 +0530 Subject: [PATCH 2/3] Disable runtime actions when disconnected --- adiuvare/tui/screens/audit.py | 25 --------------- adiuvare/tui/screens/events.py | 57 +++++++++++++++++----------------- 2 files changed, 28 insertions(+), 54 deletions(-) diff --git a/adiuvare/tui/screens/audit.py b/adiuvare/tui/screens/audit.py index 0fb1131..3ab15cc 100644 --- a/adiuvare/tui/screens/audit.py +++ b/adiuvare/tui/screens/audit.py @@ -223,7 +223,6 @@ def _action_states(self, event: dict | None) -> dict[str, ActionAvailability]: has = event is not None verdict = str(event.get("verdict", "allow")) if event else "allow" ip = str(event.get("ip", "") or "") if event else "" -<<<<<<< HEAD has_ip = bool(ip and ip != "-") connected = self._app().connected select_first = "Select an audit row first" @@ -265,30 +264,6 @@ def _update_actions(self) -> None: blocked_reasons=blocked_reasons, ) ) -======= - connected = self._app().connected - - self.query_one("#audit-ban-ip", Button).disabled = ( - not connected or not has or not ip or ip == "-" - ) - - self.query_one("#audit-unban-ip", Button).disabled = ( - not connected or not has or not ip or ip == "-" - ) - - self.query_one("#audit-monitor", Button).disabled = ( - not connected or not has - ) - - self.query_one("#audit-unmonitor", Button).disabled = ( - not connected or not has - ) - - self.query_one("#audit-whitelist", Button).disabled = ( - not connected or not has or verdict == "allow" - ) - self.query_one("#audit-export-btn", Button).disabled = not has ->>>>>>> 8493416 (Disable runtime actions when disconnected) def _render_detail(self) -> None: panel = self.query_one("#audit-detail-panel", Static) diff --git a/adiuvare/tui/screens/events.py b/adiuvare/tui/screens/events.py index 791f673..a1820ab 100644 --- a/adiuvare/tui/screens/events.py +++ b/adiuvare/tui/screens/events.py @@ -242,41 +242,40 @@ def _action_states(self, event: dict | None) -> dict[str, ActionAvailability]: has = event is not None verdict = str(event.get("verdict", "allow")) if event else "allow" ip = str(event.get("ip", "") or "") if event else "" -<<<<<<< HEAD has_ip = bool(ip and ip != "-") connected = self._app().connected select_first = "Select an event row first" runtime = require_runtime_connection -======= - connected = self._app().connected - - self.query_one("#events-confirm", Button).disabled = not has or verdict == "block" - self.query_one("#events-whitelist", Button).disabled = ( - not connected or not has - ) - - self.query_one("#events-monitor", Button).disabled = ( - not connected or not has - ) - - self.query_one("#events-unmonitor", Button).disabled = ( - not connected or not has - ) - - self.query_one("#events-unblock-monitor", Button).disabled = ( - not connected or not has or verdict != "block" - ) - - self.query_one("#events-ban-ip", Button).disabled = ( - not connected or not has or not ip or ip == "-" - ) - self.query_one("#events-unban-ip", Button).disabled = ( - not connected or not has or not ip or ip == "-" - ) - self.query_one("#events-export", Button).disabled = not has ->>>>>>> 8493416 (Disable runtime actions when disconnected) + return { + "events-confirm": runtime( + ActionAvailability( + has and verdict != "block", + select_first if not has else "Already blocked", + ), + connected, + ), + "events-whitelist": runtime(ActionAvailability(has, select_first), connected), + "events-monitor": runtime(ActionAvailability(has, select_first), connected), + "events-unmonitor": runtime(ActionAvailability(has, select_first), connected), + "events-unblock-monitor": runtime( + ActionAvailability( + has and verdict == "block", + select_first if not has else "Only for blocked events", + ), + connected, + ), + "events-ban-ip": runtime( + ActionAvailability(has and has_ip, select_first if not has else "No IP on event"), + connected, + ), + "events-unban-ip": runtime( + ActionAvailability(has and has_ip, select_first if not has else "No IP on event"), + connected, + ), + "events-export": ActionAvailability(has, select_first), + } return { "events-confirm": runtime( From 3ea4d606fe7e8e44b67c7483142d32e01b96b5a7 Mon Sep 17 00:00:00 2001 From: Astha Singh Date: Sun, 31 May 2026 01:10:28 +0530 Subject: [PATCH 3/3] Add coverage for disconnected event actions --- tests/test_tui.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tests/test_tui.py b/tests/test_tui.py index 9b8be83..4d93a91 100644 --- a/tests/test_tui.py +++ b/tests/test_tui.py @@ -282,6 +282,10 @@ async def test_events_disabled_actions_show_reasons(app): unblock = app.query_one("#events-unblock-monitor", Button) whitelist = app.query_one("#events-whitelist", Button) export_btn = app.query_one("#events-export", Button) + monitor = app.query_one("#events-monitor", Button) + unmonitor = app.query_one("#events-unmonitor", Button) + ban_ip = app.query_one("#events-ban-ip", Button) + unban_ip = app.query_one("#events-unban-ip", Button) status = app.query_one("#events-action-status", Static) assert confirm.disabled is True @@ -290,6 +294,15 @@ async def test_events_disabled_actions_show_reasons(app): assert unblock.disabled is True assert "Requires live runtime connection" in (unblock.tooltip or "") assert whitelist.disabled is True + assert monitor.disabled is True + assert unmonitor.disabled is True + assert ban_ip.disabled is True + assert unban_ip.disabled is True + + assert "Requires live runtime connection" in (monitor.tooltip or "") + assert "Requires live runtime connection" in (unmonitor.tooltip or "") + assert "Requires live runtime connection" in (ban_ip.tooltip or "") + assert "Requires live runtime connection" in (unban_ip.tooltip or "") assert export_btn.disabled is False status_text = str(status.render()) assert "Disconnected" in status_text