Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 27 additions & 18 deletions src/toad/widgets/session_details.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@

from typing import TYPE_CHECKING

from textual.content import Content
from textual.reactive import var
from textual.widgets import Collapsible, Static

from toad.line_blocks import LineRole, MutedRole, NoticeRole, WorkingRole
from toad.widgets.input_delivery import DetailAction, InputDeliveryBar
from toad.widgets.native_history import NativeHistory
from toad.widgets.observed_thread_activity import ObservedThreadActivity
Expand Down Expand Up @@ -38,9 +40,6 @@ class SessionDetails(Collapsible, ObservedThreadActivity):
width: 1fr; height: 1; padding: 0 1; text-wrap: nowrap; text-overflow: ellipsis;
}
SessionDetails > Contents { height: auto; padding: 0 1; overflow-y: auto; }
SessionDetails.-working > CollapsibleTitle { color: $accent; }
SessionDetails.-attention > CollapsibleTitle { color: $warning; }
SessionDetails .session-notifications { height: auto; }
"""

def __init__(
Expand All @@ -53,19 +52,29 @@ def __init__(
self.history = history
self.history_details = SessionHistoryDetails(transcript, history)
self.delivery = delivery
self.notifications = Static("", markup=False, classes="session-notifications")
self.notifications = Static("", markup=False)
super().__init__(
DetailAction("Inspect session", markup=False, id="session-inspect"),
self.notifications, *(item for item in (history, delivery) if item is not None),
title="", collapsed=True, id="session-details",
)

@property
def status_working(self) -> bool:
"""Work described by the title, not the independent ACP request lease."""
if self.row is not None and self.row.shown:
return self.row.working
return self.turns is not None and self.turns.owner.busy
def title_role(self) -> type[LineRole]:
"""Derive existing theme paint from the original status sources."""
if self.history_details.attention:
return NoticeRole
if self.delivery is not None and (self.delivery.delivery.current or self.delivery.error):
return NoticeRole
row = self.row
if row is not None and row.shown:
if row.attention:
return NoticeRole
if row.working:
return WorkingRole
elif self.turns is not None and self.turns.owner.busy:
return WorkingRole
return MutedRole

def on_mount(self) -> None:
super().on_mount()
Expand All @@ -81,27 +90,27 @@ def activity_changed(self) -> None:
self._refresh_summary()
super().activity_changed()

def notify_style_update(self) -> None:
super().notify_style_update()
if self.is_mounted:
self._refresh_summary()

def _refresh_summary(self, *_args) -> None:
row = self.row
shown = row is not None and row.shown
owner = self.turns.owner if self.turns is not None else None
attention = shown and row.attention
if shown:
title = row.summary[0]
else:
title = owner.status if owner is not None else ""
if self.title != title:
self.title = title
# The status is already the disclosure's title, not a second row inside.
detail = "\n".join(row.lines[1:]) if shown else ""
self.notifications.update(detail)
self.notifications.display = bool(detail)
attention |= self.history_details.attention
if self.delivery is not None:
delivery = self.delivery.delivery
attention |= bool(delivery.current or self.delivery.error)
self.set_class(attention, "-attention")
self.set_class(self.status_working, "-working")
label = Content.styled(title, self.app.colours.style(self.title_role))
# Native Content compares text and spans; no last-title/status mirror.
if not Content.from_text(self.title, markup=False).is_same(label):
self.title = label
self.overview_text = self.history_details.overview(row.lines if shown else ())
self.display = bool(title)

Expand Down
Loading