diff --git a/src/inspect_ai/_display/textual/app.py b/src/inspect_ai/_display/textual/app.py index 30313cc9b..4900d32fd 100644 --- a/src/inspect_ai/_display/textual/app.py +++ b/src/inspect_ai/_display/textual/app.py @@ -351,18 +351,30 @@ def set_title(self, title: str) -> None: tab.label = Text.from_markup(title) def activate(self) -> None: + # show the tab tabs = self.app.query_one(TabbedContent) tabs.show_tab(self.tab_id) + # focus the first focuable child (this seems to be necessary + # to get textual to reliably make the switch). after that, focus + # the tabs control so the user can switch back w/ the keyboard + tab_pane = self.app.query_one(f"#{self.tab_id}") + panel = cast(InputPanel, tab_pane.children[0]) + for child in panel.children: + if child.focusable: + child.focus() + self.app.query_one(ContentTabs).focus() + break + def deactivate(self) -> None: tabs = self.app.query_one(TabbedContent) if tabs.active == self.tab_id: self.app.activate_tasks_tab() def close(self) -> None: - self.app.activate_tasks_tab() tabs = self.app.query_one(TabbedContent) tabs.remove_pane(self.tab_id) + self.app.activate_tasks_tab() class TextualTaskScreen(TaskScreen, Generic[TR]): diff --git a/src/inspect_ai/util/_panel.py b/src/inspect_ai/util/_panel.py index 112929334..5d781e344 100644 --- a/src/inspect_ai/util/_panel.py +++ b/src/inspect_ai/util/_panel.py @@ -60,6 +60,22 @@ async def input_panel(title: str, panel: type[TP]) -> TP: 'title' running at once. Therefore, if the panel doesn't exist it is created, otherwise a reference to the existing panel is returned. + Examples: + Create/activate an input panel (the panel will remain after + the scope exits -- see below for open/close semantics) + + ```python + panel = await input_panel("Custom", CustomPanel) + panel.activate() + ``` + + Activate and close an input panel using a context manager: + + ```python + async with await input_panel("Custom", CustomPanel) as panel: + ... + ``` + Args: title (str): Input panel title. panel (type[TP]): Type of panel widget (must derive from `InputPanel`)