From f6e6593bcbe611095cfe6e6811b444016657c699 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Bombeck?= Date: Fri, 17 Jul 2026 10:40:15 +0200 Subject: [PATCH] fix(coach): name the attached document(s) in the fenced banner; keep the attach menu within its popover MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The fenced-conversation banner said a generic "N documents attached", which gave no hint what a thread was about when returning to it later. It now names the attached document(s): one document shows its title, two show both, three or more show the first two plus an "and N more" tail. Reuses the existing "Chatting about: …" doc-scope phrasing and the attachment DTO titles; the title truncates within the pill so a long name never breaks the banner. Falls back to a plain count only when no title has resolved yet. Also constrain the composer attach menu: a long localised label — e.g. "Neues Dokument hochladen" — could run past the popover edge. The menu items now shrink and truncate within the menu width, mirroring the vault picker items. Adds a "chattingAboutMore" string across all six locales. --- messages/de.json | 1 + messages/en.json | 1 + messages/es.json | 1 + messages/fr.json | 1 + messages/it.json | 1 + messages/pl.json | 1 + .../__tests__/coach-doc-scope-banner.test.tsx | 6 ++-- .../coach-panel/coach-conversation.tsx | 31 ++++++++++++++----- .../insights/coach-panel/coach-input.tsx | 18 ++++++++--- 9 files changed, 45 insertions(+), 16 deletions(-) diff --git a/messages/de.json b/messages/de.json index 5f73c945f..3dfe3715f 100644 --- a/messages/de.json +++ b/messages/de.json @@ -2184,6 +2184,7 @@ "docScope": { "badge": "Dokument", "chattingAbout": "Chat über: {title}", + "chattingAboutMore": "Chat über: {titles} und {count} weitere", "notIndexedHint": "Lies dieses Dokument zuerst im Archiv mit KI ein, damit der Coach dazu antworten kann." }, "actionsMenu": "Aktionen", diff --git a/messages/en.json b/messages/en.json index c23a5ead6..d789de5f6 100644 --- a/messages/en.json +++ b/messages/en.json @@ -2184,6 +2184,7 @@ "docScope": { "badge": "Document", "chattingAbout": "Chatting about: {title}", + "chattingAboutMore": "Chatting about: {titles} and {count} more", "notIndexedHint": "Read this document with AI first in the vault so the Coach can answer about it." }, "actionsMenu": "Actions", diff --git a/messages/es.json b/messages/es.json index 2c0f8d1c6..fdd912d82 100644 --- a/messages/es.json +++ b/messages/es.json @@ -2184,6 +2184,7 @@ "docScope": { "badge": "Documento", "chattingAbout": "Hablando sobre: {title}", + "chattingAboutMore": "Hablando sobre: {titles} y {count} más", "notIndexedHint": "Primero lee este documento con IA en el archivo para que el Coach pueda responder sobre él." }, "actionsMenu": "Acciones", diff --git a/messages/fr.json b/messages/fr.json index 6f06aca64..ac8b3e0c8 100644 --- a/messages/fr.json +++ b/messages/fr.json @@ -2184,6 +2184,7 @@ "docScope": { "badge": "Document", "chattingAbout": "Discussion sur : {title}", + "chattingAboutMore": "Discussion sur : {titles} et {count} de plus", "notIndexedHint": "Lis d'abord ce document avec l'IA dans le coffre pour que le Coach puisse y répondre." }, "actionsMenu": "Actions", diff --git a/messages/it.json b/messages/it.json index c91cc3c60..32d7464c8 100644 --- a/messages/it.json +++ b/messages/it.json @@ -2184,6 +2184,7 @@ "docScope": { "badge": "Documento", "chattingAbout": "Stai parlando di: {title}", + "chattingAboutMore": "Stai parlando di: {titles} e altri {count}", "notIndexedHint": "Leggi prima questo documento con l'IA nell'archivio così il Coach può rispondere." }, "actionsMenu": "Azioni", diff --git a/messages/pl.json b/messages/pl.json index a5fe37ce7..c5e8028ff 100644 --- a/messages/pl.json +++ b/messages/pl.json @@ -2184,6 +2184,7 @@ "docScope": { "badge": "Dokument", "chattingAbout": "Rozmowa o: {title}", + "chattingAboutMore": "Rozmowa o: {titles} i {count} więcej", "notIndexedHint": "Najpierw wczytaj ten dokument z pomocą AI w archiwum, aby Coach mógł na jego temat odpowiadać." }, "actionsMenu": "Działania", diff --git a/src/components/insights/coach-panel/__tests__/coach-doc-scope-banner.test.tsx b/src/components/insights/coach-panel/__tests__/coach-doc-scope-banner.test.tsx index d3e989cf0..b9cff0913 100644 --- a/src/components/insights/coach-panel/__tests__/coach-doc-scope-banner.test.tsx +++ b/src/components/insights/coach-panel/__tests__/coach-doc-scope-banner.test.tsx @@ -18,7 +18,7 @@ import { CoachConversation } from "../coach-conversation"; * When the Coach is fenced — here seeded via the `/coach?doc=` hand-off, * which stages ONE document as a pending first-turn attachment before any * thread exists — the shared `` surface paints the - * `coach-doc-scope` banner: a paperclip + "N documents attached" count and the + * `coach-doc-scope` banner: a paperclip + the attached document name(s) and the * honest fencing line (the coach runs WITHOUT access to health data and reads * only the attached documents). While a staged attachment is still being * content-indexed the banner adds the "still being indexed" hint. On a normal @@ -73,8 +73,8 @@ describe(" fenced banner (S7)", () => { makeClient(true), ); expect(html).toContain('data-slot="coach-doc-scope"'); - // Exactly one document staged → the singular count. - expect(html).toContain("1 document attached"); + // Exactly one document staged → the banner names it, not a generic count. + expect(html).toContain(`Chatting about: ${TITLE}`); // The honest fencing line is always present on a fenced conversation. expect(html).toContain(FENCING_LINE); // Indexed → no "still being indexed" hint. diff --git a/src/components/insights/coach-panel/coach-conversation.tsx b/src/components/insights/coach-panel/coach-conversation.tsx index 7ff5cb493..4eddfbb7b 100644 --- a/src/components/insights/coach-panel/coach-conversation.tsx +++ b/src/components/insights/coach-panel/coach-conversation.tsx @@ -954,20 +954,35 @@ export function CoachConversation({ // ONLY the attached documents, and counts the attachments. Rendered in BOTH // surfaces (page + drawer) above the thread so the fence is always visible. // Null on a normal health thread. - const attachedCount = attachmentPills.length; + // v1.29.1 — name the attached document(s) in the banner so returning to a + // fenced thread later is clear about what it is about, instead of a generic + // "N documents attached". One doc → its title; two → both, comma-joined + // through the reused `docScope.chattingAbout` phrasing; three or more → the + // first two plus an "and N more" tail. Falls back to the plain count only when + // no title has resolved yet (a sticky-fenced thread whose attachment is still + // in flight), so the banner is never empty. + const attachedTitles = attachmentPills.map((pill) => pill.title); + const attachedCount = attachedTitles.length; + const docScopeText = + attachedCount === 0 + ? t("insights.coach.attach.documentsAttachedOther", { count: 0 }) + : attachedCount <= 2 + ? t("insights.coach.docScope.chattingAbout", { + title: attachedTitles.join(", "), + }) + : t("insights.coach.docScope.chattingAboutMore", { + titles: attachedTitles.slice(0, 2).join(", "), + count: attachedCount - 2, + }); const docScopeBanner = fenced ? (
- -

diff --git a/src/components/insights/coach-panel/coach-input.tsx b/src/components/insights/coach-panel/coach-input.tsx index f62ee7aaa..358810d47 100644 --- a/src/components/insights/coach-panel/coach-input.tsx +++ b/src/components/insights/coach-panel/coach-input.tsx @@ -595,13 +595,19 @@ export function CoachInput({