fix(documents): report picker and card results through the shared outcome line, and register the disconnect as a destructive control

This commit is contained in:
Marc-André Bombeck committed 2026-09-26 13:32:52 +02:00
1 parent d109d67889
commit 9e38ee3a99
4 files changed
+46 -14

No files matched your search

@@ -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({
</button>
) : null}
{finished ? (
<WrittenOutcomeLine
outcome={runOutcome(counts)}
message={t("documents.sourcePicker.summary", counts)}
testId="document-source-summary"
/>
) : null}
{stopMessage ? (
<p
role="alert"
@@ -597,6 +608,17 @@ export function DocumentSourcePicker({
);
}
/** How the run went, in the shared outcome vocabulary. */
function runOutcome(counts: {
imported: number;
present: number;
failed: number;
}): WrittenOutcome {
const held = counts.imported + counts.present;
if (counts.failed === 0) return held > 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();
@@ -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 ? (
<CheckCircle2
className="text-success size-3.5"
<Check
className="size-3.5"
aria-label={t("settings.documentSources.statusConnected")}
/>
) : null}
@@ -328,16 +329,11 @@ function SourceForm({
</div>
{outcome ? (
<p
role={outcome.tone === "error" ? "alert" : "status"}
data-slot="document-sources-outcome"
className={cn(
"text-sm",
outcome.tone === "error" ? "text-destructive" : "text-success",
)}
>
{outcome.message}
</p>
<WrittenOutcomeLine
outcome={outcome.tone === "error" ? "failed" : "success"}
message={outcome.message}
testId="document-sources-outcome"
/>
) : null}
<SettingsCardActions>