Skip to content

R8a: full redesign of the Chat Library dialog - #164

Merged
dovvnloading merged 1 commit into
mainfrom
r8a/library-redesign
Jul 28, 2026
Merged

R8a: full redesign of the Chat Library dialog#164
dovvnloading merged 1 commit into
mainfrom
r8a/library-redesign

Conversation

@dovvnloading

Copy link
Copy Markdown
Owner

Problem

The Chat Library dialog was a permanently-boxed flat list: title + two timestamps per row, click-to-select then a separate Load Chat button, and a shared toolbar row that mutated state depending on "whichever row is currently selected" (swapping into an inline title editor for Rename, or a warning message for Delete). No content preview, no date grouping, no per-row actions.

Research

Looked at how chat-history and workspace-save lists are handled in comparable modern software before redesigning. The consistent patterns: date-bucketed grouping (Today/Yesterday/Previous 7 Days/Previous 30 Days/Older), one clear primary action per row (click the row itself), at most two secondary actions scoped to that row (not a shared toolbar), and a real content snapshot rather than title-only rows. A recent, widely-noted regression in comparable software also specifically flagged rename/delete controls going missing - which shaped the decision to keep those controls always visible here rather than hover-gated.

Change

Backend (backend/chat_library.py): each chat row now carries a one-line preview (the last chat message) and a messageCount, computed once at save time from the chat data already in memory - not parsed back out of the stored JSON blob on every list read, which would mean loading every row's full data (images can be embedded as base64 inside it) just to render a list of titles. Real ISO timestamps (createdAtIso/updatedAtIso) are exposed for date-bucketing, alongside the existing human-formatted labels. A migration adds the two new columns to existing chats.db files in place.

Frontend (ChatLibraryDialog.tsx): rows are flat/borderless at rest, matching the composer island's own "flat until hover, one accent element" language, grouped under sticky date headers. Clicking a row's body loads that chat directly - no separate select step. Rename swaps the title line for an inline input; delete swaps the action icons for an inline confirm - both scoped to their own row, never a shared toolbar. Action icons stay always visible (not hover-revealed). New Chat is a persistent header action. Real empty states for "never saved anything" vs. "search has no matches."

Test plan

  • Backend: 995 passed, including new coverage for the preview/message-count extraction and its save→list round-trip
  • Frontend: tsc --noEmit clean, lint 0 errors, 794 tests passed (13 new/rewritten for the redesigned interaction model), build succeeds
  • Verified live against the real, populated ~/.graphlink/chats.db (21 saved chats): the schema migration applied cleanly with no errors, all five date groups rendered with real data, every legacy (pre-migration) row correctly fell back to a "No messages yet" placeholder, and rename/delete/search were exercised non-destructively (opened and cancelled) without mutating any real saved chat

The library was a permanently-boxed flat list with a shared toolbar that
mutated based on "whichever row is selected" (New Chat / Load Chat /
Rename / Delete swapping into an inline title-editor or a delete-confirm
warning) - no content preview, no date grouping, click-to-select-then-
click-Load as a two-step action. Researched how chat-history/workspace-
save lists are handled elsewhere before redesigning: date-bucketed
grouping (Today/Yesterday/Previous 7 Days/Previous 30 Days/Older), one
clear primary action per row, at most two scoped secondary actions, and a
genuine content snapshot rather than title-only rows are all now standard
expectations this dialog didn't meet.

Backend: chats now carry a one-line preview (the last chat message) and a
message count, computed once at save time from the same in-memory
chat_data dict already being serialized - not parsed back out of the
stored JSON blob on every list read, which would mean loading every row's
full data (images can be embedded as base64 inside it) just to render a
list of titles. Real ISO timestamps are also exposed for date-bucketing;
the existing human-formatted labels are unchanged. A migration adds the
two new columns to existing chats.db files in place.

Frontend: rows are flat/borderless at rest (the same "flat until hover,
one accent element" language the composer island just established) and
group under sticky date headers. Clicking a row's body loads that chat
directly - no separate select step. Rename and delete are scoped to their
own row (an inline title-swap for rename, an inline confirm for delete,
never a shared toolbar) and stay always visible rather than hover-gated,
since a hover-only reveal reintroduces the "rename/delete controls went
missing" regression comparable software has shipped and been criticized
for. New Chat is a persistent header action, independent of any row.

Verified against the real, populated ~/.graphlink/chats.db: the schema
migration applies cleanly to existing rows, all five date groups render
with real data, and every legacy (pre-migration) row falls back to a
"No messages yet" placeholder rather than a blank line.
@dovvnloading
dovvnloading merged commit c675fab into main Jul 28, 2026
2 checks passed
@dovvnloading
dovvnloading deleted the r8a/library-redesign branch July 28, 2026 18:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant