Updated OTP Generate with new workflow
This commit is contained in:
@@ -1,4 +1,6 @@
|
||||
import difflib
|
||||
import re
|
||||
from typing import List
|
||||
|
||||
from textual.containers import Horizontal, Vertical
|
||||
from textual.css.query import NoMatches
|
||||
@@ -6,14 +8,16 @@ from textual.message import Message
|
||||
from textual.widget import Widget
|
||||
from textual.widgets import Button, SelectionList, Static, Switch, TextArea
|
||||
|
||||
from models.agent import Agent
|
||||
|
||||
|
||||
class MultiAgentSelector(Widget):
|
||||
class AgentsSelected(Message):
|
||||
def __init__(self, selected_agents):
|
||||
def __init__(self, selected_agents: List[Agent]):
|
||||
super().__init__()
|
||||
self.selected_agents = selected_agents
|
||||
|
||||
def __init__(self, all_agents: list[dict]):
|
||||
def __init__(self, all_agents: List[Agent]):
|
||||
super().__init__()
|
||||
self.all_agents = all_agents
|
||||
self._match_type = "exact"
|
||||
@@ -48,7 +52,6 @@ class MultiAgentSelector(Widget):
|
||||
yield text_area
|
||||
|
||||
with Horizontal(id="switch_search_container") as switch_search:
|
||||
|
||||
switch = Switch(value=False, id="match_switch")
|
||||
switch.styles.width = "auto"
|
||||
switch.styles.margin = (1, 0, 0, 0)
|
||||
@@ -62,7 +65,6 @@ class MultiAgentSelector(Widget):
|
||||
|
||||
search = Button("🔍 Search", id="search_button")
|
||||
search.styles.margin = (1, 0, 0, 0)
|
||||
|
||||
yield search
|
||||
|
||||
with Horizontal() as select_buttons:
|
||||
@@ -76,17 +78,24 @@ class MultiAgentSelector(Widget):
|
||||
select_none_button.styles.margin = (1, 0, 0, 1)
|
||||
yield select_none_button
|
||||
|
||||
submit_button = Button(
|
||||
"► Continue with Selected", id="submit_selection", variant="primary"
|
||||
)
|
||||
submit_button.styles.margin = (0, 5, 2, 1)
|
||||
submit_button.styles.padding = (0, 6, 0, 0)
|
||||
yield submit_button
|
||||
with Horizontal() as button_row:
|
||||
button_row.styles.height = "auto"
|
||||
button_row.styles.margin = (1, 0, 0, 0)
|
||||
|
||||
back_button = Button("← Back", id="back_button")
|
||||
back_button.styles.width = "1fr"
|
||||
yield back_button
|
||||
|
||||
submit_button = Button(
|
||||
"▶ Select & Continue", id="submit_selection", variant="primary"
|
||||
)
|
||||
submit_button.styles.margin = (0, 5, 2, 1)
|
||||
submit_button.styles.padding = (0, 6, 0, 0)
|
||||
yield submit_button
|
||||
|
||||
# Right side - Results
|
||||
with Vertical() as right_pane:
|
||||
right_pane.styles.width = "2fr"
|
||||
|
||||
yield SelectionList(id="match_results")
|
||||
yield Static(id="unmatched_label")
|
||||
|
||||
@@ -97,24 +106,31 @@ class MultiAgentSelector(Widget):
|
||||
)
|
||||
|
||||
def on_button_pressed(self, event: Button.Pressed):
|
||||
btn_id = event.button.id # can be None for internal buttons
|
||||
btn_id = event.button.id
|
||||
|
||||
# Only query when needed
|
||||
try:
|
||||
match_list = self.query_one("#match_results", SelectionList)
|
||||
except NoMatches:
|
||||
# UI not mounted yet or id changed—just ignore gracefully
|
||||
return
|
||||
|
||||
if btn_id == "select_all":
|
||||
if btn_id == "back_button":
|
||||
self.app.pop_screen()
|
||||
event.stop()
|
||||
elif btn_id == "select_all":
|
||||
match_list.select_all()
|
||||
event.stop()
|
||||
elif btn_id == "select_none":
|
||||
match_list.deselect_all()
|
||||
event.stop()
|
||||
elif btn_id == "submit_selection":
|
||||
selected = list(match_list.selected)
|
||||
self.post_message(self.AgentsSelected(selected))
|
||||
# Get selected hostnames
|
||||
selected_hostnames = list(match_list.selected)
|
||||
# Convert back to Agent objects
|
||||
selected_agents = [
|
||||
agent
|
||||
for agent in self.all_agents
|
||||
if agent.hostname in selected_hostnames
|
||||
]
|
||||
self.post_message(self.AgentsSelected(selected_agents))
|
||||
event.stop()
|
||||
elif btn_id == "search_button":
|
||||
self.update_matches()
|
||||
@@ -137,22 +153,18 @@ class MultiAgentSelector(Widget):
|
||||
def match_devices(self, device_names: list[str]) -> tuple[list[str], list[str]]:
|
||||
if not self.all_agents or not device_names:
|
||||
return [], device_names
|
||||
agent_names = [agent["hostname"] for agent in self.all_agents]
|
||||
agent_names = [agent.hostname for agent in self.all_agents]
|
||||
matched = set()
|
||||
unmatched = []
|
||||
|
||||
for name in device_names:
|
||||
# Check if the name contains wildcards
|
||||
has_wildcards = "*" in name or "?" in name
|
||||
|
||||
if has_wildcards:
|
||||
# Use regex for wildcard matching
|
||||
import re
|
||||
|
||||
# Escape special regex characters except * and ?
|
||||
pattern = re.escape(name)
|
||||
# Convert wildcards to regex
|
||||
pattern = pattern.replace(r"\*", ".*").replace(r"\?", ".")
|
||||
# Make it case-insensitive and match full string
|
||||
regex = re.compile(f"^{pattern}$", re.IGNORECASE)
|
||||
|
||||
wildcard_matches = [
|
||||
|
||||
Reference in New Issue
Block a user