mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-10 13:22:14 +00:00
fix(coach): name the attached document(s) in the fenced banner; keep the attach menu within its popover
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.
This commit is contained in:
1 parent
65f90160c7
commit
f6e6593bcb
9 files changed
+45
-16
No files matched your search
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -18,7 +18,7 @@ import { CoachConversation } from "../coach-conversation";
|
||||
* When the Coach is fenced — here seeded via the `/coach?doc=<id>` hand-off,
|
||||
* which stages ONE document as a pending first-turn attachment before any
|
||||
* thread exists — the shared `<CoachConversation>` 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("<CoachConversation> 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.
|
||||
|
||||
@@ -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 ? (
|
||||
<div
|
||||
data-slot="coach-doc-scope"
|
||||
className="border-border/70 bg-muted/20 flex shrink-0 flex-col gap-1 border-b px-4 py-2 sm:px-6"
|
||||
>
|
||||
<div className="flex min-w-0 items-center gap-2 text-xs">
|
||||
<span className="bg-primary/15 text-primary inline-flex shrink-0 items-center gap-1 rounded-full px-2 py-0.5 font-medium">
|
||||
<Paperclip className="size-3" aria-hidden="true" />
|
||||
{attachedCount === 1
|
||||
? t("insights.coach.attach.documentsAttachedOne")
|
||||
: t("insights.coach.attach.documentsAttachedOther", {
|
||||
count: attachedCount,
|
||||
})}
|
||||
<span className="bg-primary/15 text-primary inline-flex min-w-0 items-center gap-1 rounded-full px-2 py-0.5 font-medium">
|
||||
<Paperclip className="size-3 shrink-0" aria-hidden="true" />
|
||||
<span className="truncate">{docScopeText}</span>
|
||||
</span>
|
||||
</div>
|
||||
<p className="text-muted-foreground text-[11px] leading-snug">
|
||||
|
||||
@@ -595,13 +595,19 @@ export function CoachInput({
|
||||
<Paperclip className="size-5 sm:size-4" aria-hidden="true" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="start" side="top" className="w-56">
|
||||
{/* v1.29.1 — the item labels shrink + truncate within the popover width
|
||||
(`min-w-0` + a `truncate` span) so a long localised label — e.g.
|
||||
"Neues Dokument hochladen" — can never overflow past the menu edge.
|
||||
Mirrors the vault picker items' width handling. */}
|
||||
<DropdownMenuContent align="start" side="top" className="w-60">
|
||||
<DropdownMenuItem
|
||||
data-slot="coach-input-attach-vault"
|
||||
onSelect={() => onPickFromVault?.()}
|
||||
>
|
||||
<FolderOpen className="size-4" aria-hidden="true" />
|
||||
{t("insights.coach.attach.menuChooseFromDocuments")}
|
||||
<FolderOpen className="size-4 shrink-0" aria-hidden="true" />
|
||||
<span className="min-w-0 flex-1 truncate">
|
||||
{t("insights.coach.attach.menuChooseFromDocuments")}
|
||||
</span>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem
|
||||
data-slot="coach-input-attach-upload"
|
||||
@@ -611,8 +617,10 @@ export function CoachInput({
|
||||
setTimeout(() => attachFileInputRef.current?.click(), 0)
|
||||
}
|
||||
>
|
||||
<Upload className="size-4" aria-hidden="true" />
|
||||
{t("insights.coach.attach.menuUploadNew")}
|
||||
<Upload className="size-4 shrink-0" aria-hidden="true" />
|
||||
<span className="min-w-0 flex-1 truncate">
|
||||
{t("insights.coach.attach.menuUploadNew")}
|
||||
</span>
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
|
||||
Reference in new issue
Block a user