feat: integrate sonner for toast notifications and enhance UI feedback
Added the sonner library for toast notifications across various components, improving user feedback for actions such as saving settings, syncing rules, and handling errors. Updated the layout to include a Toaster component for consistent notification display. Refactored alert messages in the backups, gre, and filters pages to utilize the new notification system, enhancing overall user experience.
This commit is contained in:
1 parent
84ecd4f061
commit
11ad94f67d
33 files changed
+12350
-252
No files matched your search
@@ -5,9 +5,10 @@ import { PageHeader } from "@/components/page-header"
|
||||
import { Card, CardContent } from "@/components/ui/card"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Separator } from "@/components/ui/separator"
|
||||
import { toast } from "sonner"
|
||||
import {
|
||||
RefreshCwIcon, WandSparklesIcon, SaveIcon, GripVerticalIcon,
|
||||
CheckIcon, NetworkIcon, RouteIcon, ShieldIcon, ActivityIcon, XIcon,
|
||||
NetworkIcon, RouteIcon, ShieldIcon, ActivityIcon, XIcon,
|
||||
} from "lucide-react"
|
||||
import { cn } from "@/lib/utils"
|
||||
import { useDataSource } from "@/lib/data-source"
|
||||
@@ -664,7 +665,6 @@ function InterfacesTab({
|
||||
const [items, setItems] = useState<OspfItem[]>(initialItems)
|
||||
const [dragging, setDragging] = useState<string | null>(null)
|
||||
const [dragOver, setDragOver] = useState<string | null>(null)
|
||||
const [toast, setToast] = useState<string | null>(null)
|
||||
const [optimizing, setOptimizing] = useState(false)
|
||||
const [liveOptimalCost, setLiveOptimalCost] = useState<Record<string, number>>({})
|
||||
|
||||
@@ -673,8 +673,6 @@ function InterfacesTab({
|
||||
queueMicrotask(() => setItems(initialItems))
|
||||
}, [initialItems])
|
||||
|
||||
function showToast(msg: string) { setToast(msg); setTimeout(() => setToast(null), 2500) }
|
||||
|
||||
const grouped = useMemo(() => {
|
||||
const byRouter: Record<string, { routerKey: string; routerLabel: string; areas: Record<string, OspfItem[]> }> = {}
|
||||
items.forEach(item => {
|
||||
@@ -732,7 +730,7 @@ function InterfacesTab({
|
||||
|
||||
async function handleLiveOptimize() {
|
||||
if (!canOptimizeLive) {
|
||||
showToast("Выберите конкретный сервер для оптимизации OSPF")
|
||||
toast.info("Выберите конкретный сервер для оптимизации OSPF")
|
||||
return
|
||||
}
|
||||
const ra = readStoredRouteOptimizerSettings()
|
||||
@@ -750,10 +748,10 @@ function InterfacesTab({
|
||||
byKey[`${data.serverId}-${row.id}`] = row.optimalCost
|
||||
})
|
||||
setLiveOptimalCost(byKey)
|
||||
showToast(`OSPF оптимизация применена: ${data.optimizedCount} интерфейсов`)
|
||||
toast.success(`OSPF оптимизация применена: ${data.optimizedCount} интерфейсов`)
|
||||
onLiveDataRefresh()
|
||||
} catch (err) {
|
||||
showToast(`Ошибка оптимизации OSPF: ${err instanceof Error ? err.message : String(err)}`)
|
||||
toast.error(`Ошибка оптимизации OSPF: ${err instanceof Error ? err.message : String(err)}`)
|
||||
} finally {
|
||||
setOptimizing(false)
|
||||
}
|
||||
@@ -777,7 +775,7 @@ function InterfacesTab({
|
||||
const h = hints[item.key]
|
||||
return h && item.cost !== h.optimalCost ? { ...item, cost: h.optimalCost } : item
|
||||
}))
|
||||
showToast("Costs оптимизированы по рекомендациям оптимизатора")
|
||||
toast.success("Costs оптимизированы по рекомендациям оптимизатора")
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -798,19 +796,12 @@ function InterfacesTab({
|
||||
</Button>
|
||||
)}
|
||||
{!isLive && (
|
||||
<Button size="sm" onClick={() => showToast("OSPF Interface Templates применены")}>
|
||||
<Button size="sm" onClick={() => toast.success("OSPF Interface Templates применены")}>
|
||||
<SaveIcon className="size-4" />Сохранить
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{toast && (
|
||||
<div className="flex items-center gap-2 rounded-lg border border-current/20 px-4 py-2.5 text-sm"
|
||||
style={{ background: "var(--status-online-bg)", color: "var(--status-online-fg)" }}>
|
||||
<CheckIcon className="size-4 shrink-0" />{toast}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{grouped.length === 0 && (
|
||||
<div className="rounded-md border border-border bg-muted/30 px-4 py-6 text-center text-sm text-muted-foreground">
|
||||
OSPF интерфейсы не настроены ни на одном сервере
|
||||
|
||||
Reference in new issue
Block a user