Two kinds of work, and a switch to say which
The sidebar rendered an agent chat and an ordinary one identically, in one list, so hours of machine work sat among a morning's questions. A switch below the pinned models now shows one kind at a time, stored on the account so it follows the reader to another browser. Three things it does that are not the obvious version: The switch is inside the fragment it swaps. Targeting only the tree would leave the two buttons showing the side you had just left -- the request works and the interface says otherwise, which is the failure this codebase keeps cataloguing. A folder can be emptied by the filter, or have been empty all along, and only the first is a reason to hide it. `shown_in` is that line: a folder somebody made a moment ago and has not filled yet stays on both sides, or it can never be found again, let alone filed into. With agent chats switched off there is no switch, and the sidebar goes back to showing everything rather than to one side of a fork nobody can move. An administrator turning the feature off would otherwise strand whoever last left the switch on Agents in an empty sidebar with no way out. The control reuses the composer's `.segmented`, which is the same choice in a different place, and the verb goes on the input rather than the wrapper. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -57,8 +57,7 @@ class Folder(UUIDPrimaryKey, Timestamps, Base):
|
||||
parent: Mapped[Folder | None] = relationship(back_populates="children", remote_side="Folder.id")
|
||||
chats: Mapped[list[Chat]] = relationship(back_populates="folder")
|
||||
|
||||
@property
|
||||
def visible_chats(self) -> list[Chat]:
|
||||
def visible_chats(self, kind: str = "") -> list[Chat]:
|
||||
"""The chats in this folder that belong in the sidebar.
|
||||
|
||||
The relationship itself stays unfiltered -- back-population needs every
|
||||
@@ -68,13 +67,52 @@ class Folder(UUIDPrimaryKey, Timestamps, Base):
|
||||
existed. The unfiled list has always filtered them (api/pages.py); the
|
||||
folder branch went through the relationship and filtered nothing.
|
||||
|
||||
`kind` narrows to one side of the sidebar's Chat/Agent switch. Empty
|
||||
means both, which is what every caller outside the sidebar wants.
|
||||
|
||||
Ordered like the unfiled list: pinned first, then most recently touched.
|
||||
"""
|
||||
kept = [chat for chat in self.chats if not chat.archived and not chat.temporary]
|
||||
kept = [
|
||||
chat
|
||||
for chat in self.chats
|
||||
if not chat.archived and not chat.temporary and (not kind or chat.kind == kind)
|
||||
]
|
||||
kept.sort(key=lambda chat: chat.updated_at, reverse=True)
|
||||
kept.sort(key=lambda chat: not chat.pinned)
|
||||
return kept
|
||||
|
||||
def visible_children(self, kind: str = "") -> list[Folder]:
|
||||
"""Sub-folders the sidebar should show on this side of the switch.
|
||||
|
||||
Here rather than in the template because Jinja's `selectattr` names a
|
||||
test, it does not call a method -- so the filter would have to be spelled
|
||||
out as a loop appending to a list, in a template that already includes
|
||||
itself recursively.
|
||||
"""
|
||||
return [child for child in self.children if child.shown_in(kind)]
|
||||
|
||||
def holds(self, kind: str = "") -> bool:
|
||||
"""Whether anything of this kind is anywhere under this folder.
|
||||
|
||||
Recursive, because a folder's only matching chat may be three levels
|
||||
down and judging on its own contents alone would bury it.
|
||||
"""
|
||||
if self.visible_chats(kind):
|
||||
return True
|
||||
return any(child.holds(kind) for child in self.children)
|
||||
|
||||
def shown_in(self, kind: str = "") -> bool:
|
||||
"""Whether this folder belongs on one side of the sidebar's switch.
|
||||
|
||||
Two different reasons a folder can have nothing in it, and only one of
|
||||
them is a reason to hide it. A folder full of ordinary chats is noise on
|
||||
the Agent side and is dropped. A folder that is empty of *everything* is
|
||||
a container somebody just made and has not filled yet -- hiding that one
|
||||
means it can never be found again, let alone filed into, so it shows on
|
||||
both sides and says "Empty" for itself.
|
||||
"""
|
||||
return self.holds(kind) or not self.holds()
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"<Folder {self.name}>"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user