Coverage for src/lilbee/cli/tui/widgets/sessions_drawer.py: 100%

28 statements  

« prev     ^ index     » next       coverage.py v7.15.2, created at 2026-09-28 17:20 +0000

1"""Sessions side drawer: the session list docked left so chat stays live. 

2 

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. 

5The drawer closes when the embedded panel opens a chat or asks to close. 

6""" 

7 

8from __future__ import annotations 

9 

10from pathlib import Path 

11from typing import ClassVar 

12 

13from textual import on 

14from textual.app import ComposeResult 

15from textual.message import Message 

16from textual.screen import Screen 

17 

18from lilbee.cli.tui.widgets.drawer import Drawer 

19from lilbee.cli.tui.widgets.session_list import SessionListPanel 

20 

21_DRAWER_CSS = (Path(__file__).parent / "sessions_drawer.tcss").read_text(encoding="utf-8") 

22 

23# CSS class set on the host screen so app.tcss insets the docked bars to the 

24# space right of the drawer. 

25_HOST_OPEN_CLASS = "sessions-open" 

26 

27 

28class SessionsDrawer(Drawer): 

29 """Session switcher as a non-modal left-side drawer; closed with esc or ctrl+o.""" 

30 

31 DEFAULT_CSS: ClassVar[str] = _DRAWER_CSS 

32 

33 def __init__(self) -> None: 

34 super().__init__(id="sessions-drawer") 

35 self._host: Screen[object] | None = None 

36 

37 def compose(self) -> ComposeResult: 

38 yield SessionListPanel() 

39 

40 def on_mount(self) -> None: 

41 """Inset the host screen's docked bars so the drawer sits beside them.""" 

42 self._host = self.screen 

43 self._host.add_class(_HOST_OPEN_CLASS) 

44 

45 def on_unmount(self) -> None: 

46 """Restore the bars to full width when the drawer closes by any path.""" 

47 if self._host is not None: 

48 self._host.remove_class(_HOST_OPEN_CLASS) 

49 

50 @on(SessionListPanel.ChatOpened) 

51 @on(SessionListPanel.CloseRequested) 

52 def _on_leave(self, _event: Message) -> None: 

53 self.remove()