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:
co-authored by
Claude Opus 5
parent
b03dfa24fd
commit
d7a614c96b
@@ -0,0 +1,76 @@
|
||||
{% from "_macros.html" import icon %}
|
||||
{#
|
||||
The Chat/Agent switch, the folder tree and the unfiled chats.
|
||||
|
||||
Its own partial because it is rendered from two places: the sidebar on every
|
||||
page, and `POST /api/preferences/sidebar-kind` when the switch is flicked.
|
||||
Pinned models stay above it in `sidebar.html` -- they start a chat of either
|
||||
kind and are not part of what is being switched.
|
||||
|
||||
The switch is INSIDE the swapped fragment on purpose. Targeting only the tree
|
||||
would leave the two buttons showing the side you just left, which is the same
|
||||
class of failure as a control whose verb goes somewhere the event does not:
|
||||
the request works and the interface says otherwise. Each button keeps a stable
|
||||
id so htmx puts focus back on the one that was pressed.
|
||||
|
||||
`sidebar_kind` is narrowed already: `sidebar_context` drops a folder holding
|
||||
nothing of this kind at any depth, so the heading below cannot appear above
|
||||
nothing. It is still passed down to `_folder.html`, which needs it for its own
|
||||
contents and for the children it recurses into.
|
||||
#}
|
||||
<div id="sidebar-tree">
|
||||
{% if sidebar_split %}
|
||||
{#
|
||||
The same component the new-chat screen uses to pick a kind, which is the
|
||||
same choice in a different place. The verb goes on the input, not on the
|
||||
wrapper: `change` fires on the control and bubbles through its DOM
|
||||
ancestors, and htmx binds its listener to the annotated element itself.
|
||||
|
||||
`hx-vals` rather than relying on the input's own value being collected --
|
||||
the two radios are not inside a form, so what htmx would gather is worth
|
||||
not depending on.
|
||||
#}
|
||||
<div class="segmented segmented--grow" role="group" aria-label="Which chats to show">
|
||||
{% for option, label, glyph in [("chat", "Chats", "chat"), ("agent", "Agents", "terminal")] %}
|
||||
<label class="segmented__option">
|
||||
<input type="radio" name="sidebar_kind" value="{{ option }}"
|
||||
id="sidebar-kind-{{ option }}"
|
||||
{{ 'checked' if sidebar_kind == option }}
|
||||
hx-post="/api/preferences/sidebar-kind"
|
||||
hx-vals='{"kind": "{{ option }}"}'
|
||||
hx-trigger="change"
|
||||
hx-target="#sidebar-tree" hx-swap="outerHTML">
|
||||
<span>{{ icon(glyph, "icon--sm") }} {{ label }}</span>
|
||||
</label>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if folders %}
|
||||
<div class="nav-group">
|
||||
<div class="nav-group__label">Folders</div>
|
||||
{% for folder in folders %}
|
||||
{% include "partials/_folder.html" %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="nav-group">
|
||||
<div class="nav-group__label">
|
||||
{{ "Agent chats" if sidebar_kind == "agent" else "Chats" }}
|
||||
</div>
|
||||
{% if unfiled_chats %}
|
||||
{% for chat_item in unfiled_chats %}
|
||||
{% include "partials/_chat_link.html" %}
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<p class="nav-empty">
|
||||
{%- if sidebar_kind == "agent" -%}
|
||||
No agent chats yet. Nothing is stirring out there.
|
||||
{%- else -%}
|
||||
No chats yet. The road begins here.
|
||||
{%- endif -%}
|
||||
</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
Reference in New Issue
Block a user