feat: Studio bulk ops, perf fixes, bug fixes, confirm dialog visibility
CI / runtime-diagnostics (push) Skipped
CI / check (push) Successful in 34s
CI / release (push) Skipped
CI / deploy (push) Successful in 1m3s

Confirm Dialog:
- Overlay opacity 80% -> 95% (solid black)
- Card uses bg-surface with glow shadow ring-primary/40
- Added AlertTriangle icon for danger variant
- Removed backdrop-blur for maximum opacity

Studio features:
- Bulk delete: select imported items and delete in batch
- Bulk nitro regen: select items missing .nitro and regenerate all
- Added Trash2 and RefreshCw toolbar buttons for bulk actions

Performance:
- BatchProgress: React.memo + useMemo for entries/total/completed/percent
- BatchProgress: ETA interval uses useRef to avoid re-creation per completed
- CatalogRail: React.memo + useCallback for toggle
- Removed redundant double setBatchProgress calls
- Removed redundant new Map(initial) wrapping

Bug fixes:
- importBatch: stale batchDone closure always cleared progress panel (use ref)
- importBatch: added missing toast.error on HTTP failure
- bulkRegenNitro: now checks per-item results instead of marking all as succeeded
- single deleteItem: now removes classname from selected set
- retryFailed: clears progress panel on HTTP error and stream error
- Removed unused 'done' variable (2x) from cloneAllMissing/retryFailed

Lint:
- biome format fixes for selectedMissingNitro and setItems
This commit is contained in:
openhands committed 2026-09-01 19:07:20 +02:00
1 parent 4863f78795
commit 93601e58e0
4 files changed
+214 -45

No files matched your search

+16 -8
View File
@@ -1,5 +1,6 @@
"use client";
import { AlertTriangle } from "lucide-react";
import { AnimatePresence, motion } from "motion/react";
import { useCallback, useEffect, useRef, useState } from "react";
import { createPortal } from "react-dom";
@@ -77,7 +78,7 @@ export function ConfirmDialog({
<button
type="button"
aria-label="Dismiss"
className="absolute inset-0 bg-black/80 backdrop-blur-sm"
className="absolute inset-0 bg-black/95"
disabled={isLoading}
onClick={() => {
if (!isLoading) onOpenChange(false);
@@ -89,19 +90,26 @@ export function ConfirmDialog({
aria-modal="true"
aria-labelledby="confirm-dialog-title"
aria-describedby="confirm-dialog-desc"
className="relative z-10 w-full max-w-md rounded-lg border border-border bg-background/100 p-6 text-card-foreground shadow-2xl ring-1 ring-black/10 backdrop-blur-none"
className="relative z-10 w-full max-w-md rounded-xl border-2 border-primary/40 bg-surface p-6 text-card-foreground shadow-[0_0_60px_-10px_rgba(245,158,11,0.3)]"
variants={modalContentVariants}
initial="hidden"
animate="visible"
exit="exit"
>
<div className="flex flex-col gap-2 text-left">
<h2
id="confirm-dialog-title"
className="text-lg font-semibold leading-none"
>
{title}
</h2>
<div className="flex items-center gap-3">
{variant === "danger" && (
<div className="flex h-10 w-10 shrink-0 items-center justify-center rounded-full bg-destructive/15">
<AlertTriangle className="h-5 w-5 text-destructive" />
</div>
)}
<h2
id="confirm-dialog-title"
className="text-lg font-semibold leading-none"
>
{title}
</h2>
</div>
<p
id="confirm-dialog-desc"
className="text-sm text-muted-foreground"