From 9e38ee3a99a303e55cee7017be36141e1e4e022b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Bombeck?= Date: Sat, 26 Sep 2026 13:32:52 +0200 Subject: [PATCH] fix(documents): report picker and card results through the shared outcome line, and register the disconnect as a destructive control --- .../destructive-control-guard.test.ts | 7 ++++++ .../success-affordance-guard.test.ts | 7 ++++++ .../sources/document-source-picker.tsx | 24 ++++++++++++++++++- .../integrations/document-sources-card.tsx | 22 +++++++---------- 4 files changed, 46 insertions(+), 14 deletions(-) diff --git a/src/__tests__/destructive-control-guard.test.ts b/src/__tests__/destructive-control-guard.test.ts index 27a745581..fcf209cfe 100644 --- a/src/__tests__/destructive-control-guard.test.ts +++ b/src/__tests__/destructive-control-guard.test.ts @@ -579,6 +579,13 @@ const REGISTRY: DestructiveEntry[] = [ recovery: "permanent", confirm: ["AlertDialog"], })), + { + file: "components/settings/integrations/document-sources-card.tsx", + destroys: + "the stored Paperless-ngx or Papra address and API token; documents already imported stay in the vault — reconnecting means typing the token again", + recovery: "permanent", + confirm: ["AlertDialog"], + }, ]; // ── Detectors ───────────────────────────────────────────────────────────── diff --git a/src/__tests__/success-affordance-guard.test.ts b/src/__tests__/success-affordance-guard.test.ts index 8cd324ece..d8f561058 100644 --- a/src/__tests__/success-affordance-guard.test.ts +++ b/src/__tests__/success-affordance-guard.test.ts @@ -161,6 +161,13 @@ const PINNED_AFFORDANCES: Record< "src/components/documents/document-card.tsx": { "text-success": 1 }, "src/components/documents/document-detail-sheet.tsx": { "toast.success": 2 }, "src/components/documents/documents-view.tsx": { "toast.success": 3 }, + // The document picker's per-row result: tinted only for the `imported` / + // `duplicate` outcome the import route returned for that one document, i.e. + // a document the vault now holds. The run's headline goes through + // WrittenOutcomeLine; a row sits inside a button, where its

cannot. + "src/components/documents/sources/document-source-picker.tsx": { + "text-success": 1, + }, "src/components/error-details.tsx": { CheckCircle2: 2, "text-success": 1 }, "src/components/illness/episode-menu.tsx": { CheckCircle2: 2, diff --git a/src/components/documents/sources/document-source-picker.tsx b/src/components/documents/sources/document-source-picker.tsx index 2199193dc..2c91ce277 100644 --- a/src/components/documents/sources/document-source-picker.tsx +++ b/src/components/documents/sources/document-source-picker.tsx @@ -69,6 +69,9 @@ import { invalidateKeys, queryKeys } from "@/lib/query-keys"; import { cn } from "@/lib/utils"; import type { InboundDocumentKindValue } from "@/lib/validations/inbound-documents"; +import { WrittenOutcomeLine } from "@/components/outcome/written-outcome-line"; +import type { WrittenOutcome } from "@/lib/outcome/written-outcome"; + import { formatBytes } from "../vault-utils"; import { errorCodeOf, @@ -306,7 +309,7 @@ export function DocumentSourcePicker({ data-slot="document-source-selection" > {finished - ? t("documents.sourcePicker.summary", counts) + ? null : running ? t("documents.sourcePicker.importing") : t("documents.sourcePicker.selectedCount", { @@ -469,6 +472,14 @@ export function DocumentSourcePicker({ ) : null} + {finished ? ( + + ) : null} + {stopMessage ? (

0 ? "success" : "empty"; + return held > 0 ? "partial" : "failed"; +} + /** One row's progress or result, under its title. */ function RunLine({ run }: { run: RowRun }) { const { t } = useTranslations(); diff --git a/src/components/settings/integrations/document-sources-card.tsx b/src/components/settings/integrations/document-sources-card.tsx index b198d16ec..d63cfd30d 100644 --- a/src/components/settings/integrations/document-sources-card.tsx +++ b/src/components/settings/integrations/document-sources-card.tsx @@ -16,7 +16,7 @@ * (UI standards §12). */ import { useMutation, useQueryClient } from "@tanstack/react-query"; -import { Archive, CheckCircle2, Loader2, Unlink } from "lucide-react"; +import { Archive, Check, Loader2, Unlink } from "lucide-react"; import { useState } from "react"; import { @@ -38,6 +38,7 @@ import { PasswordInput } from "@/components/ui/password-input"; import { SettingsCardActions } from "@/components/settings/_card-actions"; import { SettingsCardHeader } from "@/components/settings/_card-header"; import { SettingsCard } from "@/components/settings/settings-card"; +import { WrittenOutcomeLine } from "@/components/outcome/written-outcome-line"; import { errorCodeOf, sourceErrorMessage, @@ -111,8 +112,8 @@ export function DocumentSourcesCard() { > {systemName(option)} {isConnected ? ( - ) : null} @@ -328,16 +329,11 @@ function SourceForm({ {outcome ? ( -

- {outcome.message} -

+ ) : null}