Toast action results and confirm destructive actions in one dialog
Inline banners and per-row status text reported action results all over the app; they are replaced by a small toast stack (bottom-right, Level 3 floating well styling) that only speaks for actions: successes fade, errors stay until dismissed, and form-field validation stays inline. Destructive actions no longer use bespoke inline confirm steps (the library detail's Confirm delete button) or fire immediately (duplicate copies/items, delete page selections, temp cleanup, upload discard, job cancellation): they all go through one promise-based confirm dialog (confirmAction) with a danger variant, Escape/backdrop to cancel.
This commit is contained in:
@@ -8,6 +8,7 @@ import { cn } from "@/lib/cn";
|
||||
import { formatBytes } from "@/lib/format";
|
||||
import type { StatJob, SystemStats } from "@/lib/types";
|
||||
import { useAuth } from "@/store/auth";
|
||||
import { toast } from "@/store/toasts";
|
||||
|
||||
const REFRESH_MS = 2000;
|
||||
|
||||
@@ -82,13 +83,11 @@ function JobRow({
|
||||
showSummary,
|
||||
onCancel,
|
||||
cancelling,
|
||||
cancelError,
|
||||
}: {
|
||||
job: StatJob;
|
||||
showSummary?: boolean;
|
||||
onCancel?: () => void;
|
||||
cancelling?: boolean;
|
||||
cancelError?: string | null;
|
||||
}) {
|
||||
const Icon = job.kind === "download" ? Download : ScanSearch;
|
||||
return (
|
||||
@@ -111,9 +110,6 @@ function JobRow({
|
||||
</button>
|
||||
) : null}
|
||||
</div>
|
||||
{cancelError ? (
|
||||
<p className="pl-5 text-[11px] text-ctp-red">{cancelError}</p>
|
||||
) : null}
|
||||
{showSummary ? (
|
||||
<p className="truncate pl-5 text-[11px] text-ctp-overlay0" title={job.summary ?? job.detail}>
|
||||
{job.summary ?? job.detail}
|
||||
@@ -159,10 +155,13 @@ export default function StatsPage() {
|
||||
: `/api/matches/${job.id}/cancel/`,
|
||||
{ method: "POST" },
|
||||
),
|
||||
onSuccess: () => {
|
||||
onSuccess: (_data, job) => {
|
||||
void queryClient.invalidateQueries({ queryKey: ["stats"] });
|
||||
void queryClient.invalidateQueries({ queryKey: ["status"] });
|
||||
toast.ok(`Cancelled ${job.label}.`);
|
||||
},
|
||||
onError: (error, job) =>
|
||||
toast.error(`Could not cancel ${job.label}: ${errorMessage(error)}`),
|
||||
});
|
||||
const [autoScroll, setAutoScroll] = useState(true);
|
||||
const logRef = useRef<HTMLDivElement>(null);
|
||||
@@ -369,12 +368,6 @@ export default function StatsPage() {
|
||||
cancelMutation.isPending &&
|
||||
cancelMutation.variables?.id === job.id
|
||||
}
|
||||
cancelError={
|
||||
cancelMutation.isError &&
|
||||
cancelMutation.variables?.id === job.id
|
||||
? errorMessage(cancelMutation.error)
|
||||
: null
|
||||
}
|
||||
/>
|
||||
))}
|
||||
</ul>
|
||||
|
||||
Reference in New Issue
Block a user