Coverage for src/lilbee/cli/tui/widgets/sessions_drawer.py: 100%
35 statements
« prev ^ index » next coverage.py v7.15.2, created at 2026-08-14 11:46 +0000
« prev ^ index » next coverage.py v7.15.2, created at 2026-08-14 11:46 +0000
1"""Sessions side drawer: the session list docked left so chat stays live.
3Non-modal, mirroring the Fleet drawer. Docked left so the screen underneath
4reflows to the right and the chat prompt keeps working while the drawer is open.
5Resume, new-chat, and close come from the embedded panel as messages.
6"""
8from __future__ import annotations
10from pathlib import Path
11from typing import TYPE_CHECKING, ClassVar
13from textual import on
14from textual.app import ComposeResult
15from textual.screen import Screen
17from lilbee.cli.tui.widgets.drawer import Drawer
18from lilbee.cli.tui.widgets.session_list import SessionListPanel
20if TYPE_CHECKING:
21 from lilbee.cli.tui.app import LilbeeApp
23_DRAWER_CSS = (Path(__file__).parent / "sessions_drawer.tcss").read_text(encoding="utf-8")
25# CSS class set on the host screen so app.tcss insets the docked bars to the
26# space right of the drawer.
27_HOST_OPEN_CLASS = "sessions-open"
30class SessionsDrawer(Drawer):
31 """Session switcher as a non-modal left-side drawer; closed with esc or ctrl+o."""
33 DEFAULT_CSS: ClassVar[str] = _DRAWER_CSS
35 app: LilbeeApp # type: ignore[assignment]
37 def __init__(self) -> None:
38 super().__init__(id="sessions-drawer")
39 self._host: Screen[object] | None = None
41 def compose(self) -> ComposeResult:
42 yield SessionListPanel()
44 def on_mount(self) -> None:
45 """Inset the host screen's docked bars so the drawer sits beside them."""
46 self._host = self.screen
47 self._host.add_class(_HOST_OPEN_CLASS)
49 def on_unmount(self) -> None:
50 """Restore the bars to full width when the drawer closes by any path."""
51 if self._host is not None:
52 self._host.remove_class(_HOST_OPEN_CLASS)
54 @on(SessionListPanel.Resumed)
55 def _on_resumed(self, event: SessionListPanel.Resumed) -> None:
56 self.app.resume_session(event.session_id)
57 self.remove()
59 @on(SessionListPanel.NewChat)
60 def _on_new_chat(self, _event: SessionListPanel.NewChat) -> None:
61 self.app.new_chat()
62 self.remove()
64 @on(SessionListPanel.CloseRequested)
65 def _on_close(self, _event: SessionListPanel.CloseRequested) -> None:
66 self.remove()