From 082c556a678c2357ce4e048cbeb09e79e02b9f01 Mon Sep 17 00:00:00 2001 From: root Date: Mon, 28 Sep 2026 16:58:38 +0800 Subject: [PATCH] =?UTF-8?q?fix(web):=20visual=20QA=20front-end=20items=20U?= =?UTF-8?q?4=E2=80=93U6,=20U13=E2=80=93U16=20and=20copy=20list?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - U4: form save failures toast the first problem and scroll/focus the first invalid field (policy draft, settings cards, resource drawers, subscription form) via lib/form-errors. - U5: FormField keeps 8px between a hint and the next label. - U6: file manager status bar keeps free space left-aligned, clear of the Agent button. - U13: move/copy dialog stops "target is the source folder / inside the source" before requesting a preview (transferTargetProblem + tests). - U14: account popover uses the solid float material. - U15/U16: inbox tile hint shortened; TMDB assign dialog uses the shared Select and labelled fields (type, TMDB ID, note). - Copy: "TMDB 已保存" spacing, API Key block no longer repeats the section title, whole-day intervals read "每 7 天", "最高级别:提示", "延后:已有计划在途", failed records show "未生成目标路径", upstream model column "默认模型". Co-Authored-By: Claude Opus 5.5 --- .../app/components/console/account-menu.tsx | 2 +- .../web/app/components/console/form-field.tsx | 3 +- apps/web/app/components/files/dialogs.tsx | 6 ++ apps/web/app/components/files/model.test.ts | 18 ++++++ apps/web/app/components/files/model.ts | 17 ++++++ apps/web/app/components/library/labels.ts | 2 +- .../library/subscriptions-policy.tsx | 4 +- apps/web/app/components/schedules/labels.ts | 2 + apps/web/app/components/settings/api-keys.tsx | 4 +- .../app/components/settings/pi-upstreams.tsx | 4 +- .../components/settings/resource-section.tsx | 2 + .../app/components/settings/settings-card.tsx | 4 +- .../subscriptions/subscription-form.tsx | 2 + .../workbench/release-detail-sheet.tsx | 2 +- apps/web/app/lib/form-errors.ts | 23 ++++++++ apps/web/app/routes/console/files.tsx | 3 +- apps/web/app/routes/console/inbox.tsx | 55 +++++++++++-------- apps/web/app/routes/console/organize.$id.tsx | 15 +++-- 18 files changed, 130 insertions(+), 38 deletions(-) create mode 100644 apps/web/app/lib/form-errors.ts diff --git a/apps/web/app/components/console/account-menu.tsx b/apps/web/app/components/console/account-menu.tsx index 2f5d6471..65d949b4 100644 --- a/apps/web/app/components/console/account-menu.tsx +++ b/apps/web/app/components/console/account-menu.tsx @@ -277,7 +277,7 @@ export function AccountMenu({ session }: { session: SessionInfo }) { {actor?.name ?? "账户"} - +

当前账户

{actor?.name ?? "—"}

diff --git a/apps/web/app/components/console/form-field.tsx b/apps/web/app/components/console/form-field.tsx index 06235624..872f2000 100644 --- a/apps/web/app/components/console/form-field.tsx +++ b/apps/web/app/components/console/form-field.tsx @@ -27,7 +27,8 @@ export function FormField({ className?: string; }) { return ( -
+ // pb-1:说明文字与下一个字段标签至少隔 8px(外层 gap-1 + 这里 4px;QA U5) +
) : null} diff --git a/apps/web/app/routes/console/inbox.tsx b/apps/web/app/routes/console/inbox.tsx index 1028ef59..8f3ebd58 100644 --- a/apps/web/app/routes/console/inbox.tsx +++ b/apps/web/app/routes/console/inbox.tsx @@ -1,13 +1,14 @@ import { useQueryClient } from "@tanstack/react-query"; import type { Decision, DecisionKind, DecisionOption, DecisionStatus } from "@umt/contracts"; import { BellOff, Bot, CheckCheck, ChevronRight, Inbox, Radio, RotateCw } from "lucide-react"; -import { type ReactNode, useMemo, useRef, useState } from "react"; +import { type ReactNode, useId, useMemo, useRef, useState } from "react"; import { Link, useSearchParams } from "react-router"; import { toast } from "sonner"; import { decisionKeys, useDecisionSummary, useDecisions, useResolveDecision } from "~/api/decisions.ts"; import { ConfirmDialog } from "~/components/console/confirm-dialog.tsx"; import { EmptyState, ErrorState, LoadingState } from "~/components/console/empty-state.tsx"; import { FilterBar, FilterSelect } from "~/components/console/filter-bar.tsx"; +import { FormField } from "~/components/console/form-field.tsx"; import { JsonView } from "~/components/console/json-view.tsx"; import { consolePath } from "~/components/console/nav.ts"; import { PageHeader } from "~/components/console/page-header.tsx"; @@ -18,6 +19,7 @@ import { DECISION_KIND, DECISION_STATUS, opts, SEVERITY } from "~/components/lib import { Chip, relTime, Tone } from "~/components/library/parts.tsx"; import { Button } from "~/components/ui/button.tsx"; import { Input } from "~/components/ui/input.tsx"; +import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "~/components/ui/select.tsx"; import { Textarea } from "~/components/ui/textarea.tsx"; import { errorMessage } from "~/lib/api.ts"; import { actorText } from "~/lib/labels.ts"; @@ -111,6 +113,7 @@ function requiresOf(option: DecisionOption): Requires { function OptionButton({ d, option }: { d: Decision; option: DecisionOption }) { const resolve = useResolveDecision(); + const uid = useId(); const [note, setNote] = useState(""); const requires = requiresOf(option); const [tmdbType, setTmdbType] = useState<"movie" | "tv">("movie"); @@ -161,28 +164,36 @@ function OptionButton({ d, option }: { d: Decision; option: DecisionOption }) { } > {requires === "tmdb" ? ( -
- - setTmdbId(e.target.value)} - placeholder="TMDB ID,如 872585" - /> +
+ + + + + setTmdbId(e.target.value)} + aria-invalid={tmdbId.trim() !== "" && !tmdbOk} + /> +
) : requires === "mediaEntityId" ? ( - + + + ) : null} -