From 5cb079dad74f864b222b88f05dac8ab5d4ebe8f4 Mon Sep 17 00:00:00 2001 From: Zarithas Date: Mon, 10 Nov 2025 17:21:18 -0500 Subject: [PATCH] Fixed Breaking Legacy change --- utils/tui.py | 71 ++++++++++++++-------------------- widgets/agentmoveoperations.py | 5 ++- widgets/multiagentselector.py | 5 ++- 3 files changed, 36 insertions(+), 45 deletions(-) diff --git a/utils/tui.py b/utils/tui.py index a930d03..8cadf33 100644 --- a/utils/tui.py +++ b/utils/tui.py @@ -20,6 +20,7 @@ from textual.widgets import ( from flows.otp import otp_activities_by_agent, otp_revoke from flows.prepPolicy import menu_policy_enforce +from flows.quietAgent import findQuietAgents from models.agent import Agent from models.policy import Policy from screens.moveagentworkflowscreen import MoveAgentWorkflowScreen @@ -325,6 +326,8 @@ class MainMenuScreen(Screen): self.app.push_screen(OTPWorkflowScreen(self.app.devices)) event.stop() return # Don't exit the app + case "find_quiet_button": + _PENDING_JOB = ("legacy", findQuietAgents, (self.app.api,), {}) case "otp_activities_button": _PENDING_JOB = ("legacy", otp_activities_by_agent, (self.app.api,), {}) case "otp_revoke_button": @@ -353,7 +356,6 @@ class Loxide(App): text-align: center; } """ - BINDINGS = [ ("q", "quit", "Quit"), ("d", "open_dir", "Open Directory"), @@ -367,17 +369,20 @@ class Loxide(App): if not os.path.isdir(wd): wd = os.getcwd() self.working_dir = wd + # Initial data load + self.refresh_data() - # Add error handling for API calls + def refresh_data(self) -> None: + """Public method to refresh policies and devices from the API.""" try: self.policies = [ - Policy(**row.to_dict()) for _, row in api.policy_find_all().iterrows() + Policy(**row.to_dict()) + for _, row in self.api.policy_find_all().iterrows() ] self.devices = [ - Agent(**row.to_dict()) for _, row in api.agent_find_all().iterrows() + Agent(**row.to_dict()) + for _, row in self.api.agent_find_all().iterrows() ] - - # Enrich agents with policy information if self.policies and self.devices: for agent in self.devices: agent.enrich_with_policies(self.policies) @@ -401,6 +406,8 @@ class Loxide(App): self.exit() def action_open_dir(self) -> None: + # Refresh data before proceeding + self.refresh_data() screen = self.screen_stack[-1] if isinstance(screen, MainMenuScreen): if screen.current_tab != "dir": @@ -417,7 +424,6 @@ def _restore_terminal_for_legacy() -> None: sys.stdout.write("\033[?1000l\033[?1002l\033[?1003l\033[?1006l") sys.stdout.write("\033[2J\033[H") sys.stdout.flush() - if os.name == "nt": try: import ctypes @@ -434,7 +440,6 @@ def _restore_terminal_for_legacy() -> None: def _run_legacy_job(func, args, kwargs) -> None: logger.debug("Running legacy job: %s", getattr(func, "__name__", func)) _restore_terminal_for_legacy() - try: func(*args, **kwargs) finally: @@ -449,24 +454,31 @@ def _run_legacy_job(func, args, kwargs) -> None: # --------------------------------------------------------------------------- def run_Loxide(api: AirlockAPIWrapper) -> None: global _PENDING_JOB + base_dir = get_base_directory() + env_path = base_dir / ".env" + dotenv.load_dotenv(dotenv_path=env_path, override=True) - while True: - base_dir = get_base_directory() - env_path = base_dir / ".env" - dotenv.load_dotenv(dotenv_path=env_path, override=True) + max_attempts = 5 + attempts = 0 + while attempts < max_attempts: + attempts += 1 + logger.debug("Starting job loop iteration (attempt %d)", attempts) _PENDING_JOB = None app = Loxide(api) try: app.run() except SystemExit as exc: - logger.debug("Caught SystemExit from Textual: %s", exc) + if exc.code != 0: + logger.debug("Caught SystemExit from Textual: %s", exc) + raise job = _PENDING_JOB logger.debug("After app.run(), _PENDING_JOB = %r", job) if not job: + logger.debug("No job pending, exiting loop") break if job[0] == "legacy": @@ -475,49 +487,24 @@ def run_Loxide(api: AirlockAPIWrapper) -> None: continue if job[0] == "restart": - # just loop again; fresh .env was already loaded at the top + logger.debug("Restarting job loop") continue if job[0] == "multi_agent_action": - # Handle multi-agent selection logger.info("Multi-agent action with selected agents: %s", job[1]) continue - # NEW: Handle OTP workflow if job[0] == "otp_workflow": _, devices, requestor, reasoning, duration = job - # Call your OTP generation with the parameters def otp_generate_with_params(): - - print(f"\n{'='*60}") - print("OTP GENERATION") - print(f"{'='*60}") - print(f"Requestor: {requestor}") - print(f"Reasoning: {reasoning}") - print(f"Duration: {duration} minutes") - print(f"\nGenerating OTPs for {len(devices)} devices:") - print(f"{'='*60}\n") - - # Call your actual OTP generation function - # You'll need to adapt otp_generate to accept these parameters - # For now, this is a placeholder showing the structure - for device in devices: - print(f"Device: {device}") - print(f" Requestor: {requestor}") - print(f" Reason: {reasoning}") - print(f" Duration: {duration} minutes") - # TODO: Actually call your API to generate OTP - # result = api.generate_otp(device, requestor, reasoning, duration) - print() - - print(f"{'='*60}") - print("OTP Generation Complete!") - print(f"{'='*60}") + # Your OTP logic here + pass _run_legacy_job(otp_generate_with_params, (), {}) continue + logger.error("Unknown job type: %r", job) break diff --git a/widgets/agentmoveoperations.py b/widgets/agentmoveoperations.py index 6cfe7f3..03e5da4 100644 --- a/widgets/agentmoveoperations.py +++ b/widgets/agentmoveoperations.py @@ -506,6 +506,7 @@ class AgentMoveOperations(Widget): unsuccessful = [] status_label = self.query_one("#status_label", Static) status_label.update("Exporting CSV...") + self.app.refresh_data() agents = self.agents policies = self.app.policies path = self.app.working_dir @@ -604,6 +605,8 @@ class AgentMoveOperations(Widget): successful.append((agent, f"Moved to {mode}: {result}")) logger.info(f"Successfully toggled {agent.hostname} to {mode}") + self.app.refresh_data() + except Exception as e: unsuccessful.append((agent, str(e))) logger.error(f"Failed to toggle {agent.hostname}: {e}") @@ -728,7 +731,7 @@ class AgentMoveOperations(Widget): status_label.update(f"Error: {str(e)}") self.operation_in_progress = False return - + self.app.refresh_data() self.operation_in_progress = False status_label.update("Operation complete!") diff --git a/widgets/multiagentselector.py b/widgets/multiagentselector.py index 92016b7..f4ea371 100644 --- a/widgets/multiagentselector.py +++ b/widgets/multiagentselector.py @@ -80,11 +80,11 @@ class MultiAgentSelector(Widget): select_buttons.styles.margin = (0, 0, 0, 0) select_none_button = Button("🚫 Select None", id="select_none") - select_none_button.styles.margin = (1, 0, 0, 1) + select_none_button.styles.margin = (1, 1, 0, 1) yield select_none_button select_all_button = Button("✅ Select All", id="select_all") - select_all_button.styles.margin = (1, 1, 0, 1) + select_all_button.styles.margin = (1, 0, 0, 1) yield select_all_button with Horizontal() as button_row: @@ -93,6 +93,7 @@ class MultiAgentSelector(Widget): back_button = Button("← Back", id="back_button") back_button.styles.width = "1fr" + back_button.styles.margin = (0, 0, 0, 1) yield back_button submit_button = Button(