diff --git a/CHANGELOG.md b/CHANGELOG.md index a09d74550..3f7f113bf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,8 @@ ## [1.28.38] — 2026-07-16 — Documents polish, waist reminders, bulk sharing The document vault gets a round of overdue polish. The list cards drop a -stray glyph and give the real filename its own line so it stops being cut +stray glyph — the "read by AI" mark it carried moves into the document's +detail view — and give the real filename its own line so it stops being cut off; the detail view's close button is aligned correctly (a shared sheet primitive was reserving space for a button it wasn't showing). The action that opens a document in the coach now reads "Coach fragen". diff --git a/e2e/documents-ai.spec.ts b/e2e/documents-ai.spec.ts index ad33f54b7..1bb3b71d0 100644 --- a/e2e/documents-ai.spec.ts +++ b/e2e/documents-ai.spec.ts @@ -357,26 +357,18 @@ test.describe("document vault — AI assist + content search", () => { page, }) => { // CONTENT_DOC_ID is seeded with source "vision" (an AI provider read it). - // No mocks: the real list GET threads the provenance through. v1.28.22 — - // the marker lives on the vault CARD's meta row (an inline glyph beside - // date · size), not in the sheet. Surface the card through search (the - // grid is virtualized, so a targeted card must be brought into view the - // way a user would). - await page.goto("/documents"); - await expect( - page.getByRole("heading", { name: "Documents" }), - ).toBeVisible(); - await page - .getByRole("searchbox", { name: "Search documents" }) - .fill(CONTENT_BODY_WORD); - await expect( - page.getByRole("button", { name: "Open Radiology note" }), - ).toBeVisible({ timeout: 10_000 }); + // No mocks: the real detail GET threads the provenance through. v1.28.38 — + // the vault card no longer carries the AI-read glyph (it looked wrong on + // the card face); the provenance now lives as a calm muted meta line in the + // document DETAIL view. Deep-link straight to the document so the sheet + // opens deterministically (the vault grid is virtualized). + await page.goto(`/documents?doc=${CONTENT_DOC_ID}`); + const sheet = page.getByRole("dialog"); + await expect(sheet).toBeVisible(); - const marker = page.locator( - `[data-document-id="${CONTENT_DOC_ID}"] [data-slot="document-card-ai-read"]`, - ); - await expect(marker.first()).toBeVisible(); + const marker = sheet.locator('[data-slot="document-detail-ai-read"]'); + await expect(marker).toBeVisible(); + await expect(marker).toHaveText("Read by AI"); }); // ── (f) Text-mode refuses a non-image before any OCR/upload ────────────── diff --git a/messages/de.json b/messages/de.json index 88df9f595..b44c2efcb 100644 --- a/messages/de.json +++ b/messages/de.json @@ -8355,6 +8355,7 @@ "close": "Ausblenden" }, "ai": { + "statusAiRead": "Von KI gelesen", "readDone": "Die KI hat dein Dokument gelesen.", "read": "Mit KI auslesen", "reread": "Erneut lesen", diff --git a/messages/en.json b/messages/en.json index 59a6a1d01..312ee4ee7 100644 --- a/messages/en.json +++ b/messages/en.json @@ -8355,6 +8355,7 @@ "close": "Hide" }, "ai": { + "statusAiRead": "Read by AI", "readDone": "The AI read your document.", "read": "Read with AI", "reread": "Read again", diff --git a/messages/es.json b/messages/es.json index e7f7fd84e..d0a4e9700 100644 --- a/messages/es.json +++ b/messages/es.json @@ -8355,6 +8355,7 @@ "close": "Ocultar" }, "ai": { + "statusAiRead": "Leído por IA", "readDone": "La IA leyó tu documento.", "read": "Leer con IA", "reread": "Leer de nuevo", diff --git a/messages/fr.json b/messages/fr.json index b1f04b4e3..4e444d565 100644 --- a/messages/fr.json +++ b/messages/fr.json @@ -8355,6 +8355,7 @@ "close": "Masquer" }, "ai": { + "statusAiRead": "Lu par l’IA", "readDone": "L’IA a lu votre document.", "read": "Lire avec l’IA", "reread": "Relire", diff --git a/messages/it.json b/messages/it.json index 9c62d4510..42b207b9c 100644 --- a/messages/it.json +++ b/messages/it.json @@ -8355,6 +8355,7 @@ "close": "Nascondi" }, "ai": { + "statusAiRead": "Letto dall’IA", "readDone": "L’IA ha letto il tuo documento.", "read": "Leggi con l’IA", "reread": "Leggi di nuovo", diff --git a/messages/pl.json b/messages/pl.json index 392590bd1..8122f13f0 100644 --- a/messages/pl.json +++ b/messages/pl.json @@ -8355,6 +8355,7 @@ "close": "Ukryj" }, "ai": { + "statusAiRead": "Odczytane przez AI", "readDone": "AI odczytało Twój dokument.", "read": "Odczytaj z AI", "reread": "Odczytaj ponownie", diff --git a/src/components/documents/document-detail-sheet.tsx b/src/components/documents/document-detail-sheet.tsx index aa34664d4..48c3409b6 100644 --- a/src/components/documents/document-detail-sheet.tsx +++ b/src/components/documents/document-detail-sheet.tsx @@ -62,6 +62,7 @@ import { invalidateKeys, queryKeys } from "@/lib/query-keys"; import { cn } from "@/lib/utils"; import { INBOUND_DOCUMENT_KINDS, + isAiReadSource, type DocumentSuggestionDto, type DocumentSummaryMode, type InboundDocumentDetailDto, @@ -420,6 +421,12 @@ export function DocumentDetailSheet({ const title = doc?.title ?? doc?.filename ?? t("documents.card.untitled"); const Icon = doc ? DOCUMENT_KIND_ICONS[doc.kind] : null; const originalHref = doc ? `/api/documents/inbound/${doc.id}/original` : "#"; + // AI-read provenance — surfaced here (the detail view) as calm muted meta + // since v1.28.38 dropped the vault-card glyph. Same condition the AI section + // uses: a content index exists AND its source is a provider vision/text read. + const aiRead = doc + ? doc.hasContentIndex && isAiReadSource(doc.contentIndexSource) + : false; return ( <> @@ -752,6 +759,15 @@ export function DocumentDetailSheet({ })} {doc.filename ? ` · ${doc.filename}` : ""}
+ + {aiRead ? ( ++ {t("documents.ai.statusAiRead")} +
+ ) : null} ) : null}