d5b87028c5
- datasets/page.tsx: neuer Tab 'Shares & Config' mit vollem Inhalt aus shares/page.tsx (Samba, NFS, Samba Config mit MacOS-Toggle + Raw-Editor) - shares/page.tsx: redirect -> /datasets - Header.tsx: 'Shares'-Link zeigt auf /datasets Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
268 lines
9.3 KiB
TypeScript
268 lines
9.3 KiB
TypeScript
"use client"
|
|
|
|
import Link from "next/link"
|
|
import { usePathname, useRouter } from "next/navigation"
|
|
import { Button } from "@/components/ui/button"
|
|
import { HardDrive, Menu, LogOut } from "lucide-react"
|
|
import { useState, useEffect } from "react"
|
|
import { api } from "@/lib/api"
|
|
|
|
export function Header() {
|
|
const pathname = usePathname()
|
|
const router = useRouter()
|
|
const [isMenuOpen, setIsMenuOpen] = useState(false)
|
|
const [zfsAvailable, setZfsAvailable] = useState(false)
|
|
|
|
useEffect(() => {
|
|
const checkZfsAvailability = async () => {
|
|
const status = await api.getSystemStatus()
|
|
setZfsAvailable(status.zfs_available)
|
|
}
|
|
checkZfsAvailability()
|
|
}, [])
|
|
|
|
const handleLogout = async () => {
|
|
await api.logout()
|
|
router.push("/login")
|
|
}
|
|
|
|
const isActive = (path: string) => pathname === path
|
|
|
|
return (
|
|
<header className="sticky top-0 z-50 w-full border-b border-border bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60">
|
|
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
|
<div className="flex items-center justify-between h-16">
|
|
{/* Logo */}
|
|
<Link href="/" className="flex items-center gap-2 font-bold text-lg">
|
|
<HardDrive className="w-6 h-6" />
|
|
<span>ZMB Webui</span>
|
|
</Link>
|
|
|
|
{/* Desktop Navigation */}
|
|
<nav className="hidden md:flex items-center gap-1">
|
|
<Link
|
|
href="/"
|
|
className={`px-3 py-2 rounded-md text-sm font-medium transition-colors ${
|
|
isActive("/")
|
|
? "bg-accent text-accent-foreground"
|
|
: "text-muted-foreground hover:text-foreground"
|
|
}`}
|
|
>
|
|
Dashboard
|
|
</Link>
|
|
{zfsAvailable && (
|
|
<>
|
|
<Link
|
|
href="/snapshots"
|
|
className={`px-3 py-2 rounded-md text-sm font-medium transition-colors ${
|
|
isActive("/snapshots")
|
|
? "bg-accent text-accent-foreground"
|
|
: "text-muted-foreground hover:text-foreground"
|
|
}`}
|
|
>
|
|
Snapshots
|
|
</Link>
|
|
<Link
|
|
href="/datasets"
|
|
className={`px-3 py-2 rounded-md text-sm font-medium transition-colors ${
|
|
isActive("/datasets")
|
|
? "bg-accent text-accent-foreground"
|
|
: "text-muted-foreground hover:text-foreground"
|
|
}`}
|
|
>
|
|
Datasets
|
|
</Link>
|
|
</>
|
|
)}
|
|
<Link
|
|
href="/navigator"
|
|
className={`px-3 py-2 rounded-md text-sm font-medium transition-colors ${
|
|
isActive("/navigator")
|
|
? "bg-accent text-accent-foreground"
|
|
: "text-muted-foreground hover:text-foreground"
|
|
}`}
|
|
>
|
|
Navigator
|
|
</Link>
|
|
<Link
|
|
href="/datasets"
|
|
className={`px-3 py-2 rounded-md text-sm font-medium transition-colors ${
|
|
isActive("/datasets")
|
|
? "bg-accent text-accent-foreground"
|
|
: "text-muted-foreground hover:text-foreground"
|
|
}`}
|
|
>
|
|
Shares
|
|
</Link>
|
|
<Link
|
|
href="/file-sharing"
|
|
className={`px-3 py-2 rounded-md text-sm font-medium transition-colors ${
|
|
isActive("/file-sharing")
|
|
? "bg-accent text-accent-foreground"
|
|
: "text-muted-foreground hover:text-foreground"
|
|
}`}
|
|
>
|
|
File Sharing
|
|
</Link>
|
|
<Link
|
|
href="/identities"
|
|
className={`px-3 py-2 rounded-md text-sm font-medium transition-colors ${
|
|
isActive("/identities")
|
|
? "bg-accent text-accent-foreground"
|
|
: "text-muted-foreground hover:text-foreground"
|
|
}`}
|
|
>
|
|
Identities
|
|
</Link>
|
|
<Link
|
|
href="/logs"
|
|
className={`px-3 py-2 rounded-md text-sm font-medium transition-colors ${
|
|
isActive("/logs")
|
|
? "bg-accent text-accent-foreground"
|
|
: "text-muted-foreground hover:text-foreground"
|
|
}`}
|
|
>
|
|
Logs
|
|
</Link>
|
|
<Link
|
|
href="/services"
|
|
className={`px-3 py-2 rounded-md text-sm font-medium transition-colors ${
|
|
isActive("/services")
|
|
? "bg-accent text-accent-foreground"
|
|
: "text-muted-foreground hover:text-foreground"
|
|
}`}
|
|
>
|
|
Services
|
|
</Link>
|
|
</nav>
|
|
|
|
{/* Logout Button */}
|
|
<div className="flex items-center gap-2">
|
|
<Button variant="ghost" size="sm" onClick={handleLogout}>
|
|
<LogOut className="w-4 h-4 mr-2" />
|
|
<span className="hidden sm:inline">Logout</span>
|
|
</Button>
|
|
|
|
{/* Mobile Menu Button */}
|
|
<button
|
|
className="md:hidden p-2"
|
|
onClick={() => setIsMenuOpen(!isMenuOpen)}
|
|
>
|
|
<Menu className="w-6 h-6" />
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Mobile Navigation */}
|
|
{isMenuOpen && (
|
|
<nav className="md:hidden pb-4 space-y-1">
|
|
<Link
|
|
href="/"
|
|
className={`block px-3 py-2 rounded-md text-sm font-medium ${
|
|
isActive("/")
|
|
? "bg-accent text-accent-foreground"
|
|
: "text-muted-foreground hover:text-foreground"
|
|
}`}
|
|
onClick={() => setIsMenuOpen(false)}
|
|
>
|
|
Dashboard
|
|
</Link>
|
|
{zfsAvailable && (
|
|
<>
|
|
<Link
|
|
href="/snapshots"
|
|
className={`block px-3 py-2 rounded-md text-sm font-medium ${
|
|
isActive("/snapshots")
|
|
? "bg-accent text-accent-foreground"
|
|
: "text-muted-foreground hover:text-foreground"
|
|
}`}
|
|
onClick={() => setIsMenuOpen(false)}
|
|
>
|
|
Snapshots
|
|
</Link>
|
|
<Link
|
|
href="/datasets"
|
|
className={`block px-3 py-2 rounded-md text-sm font-medium ${
|
|
isActive("/datasets")
|
|
? "bg-accent text-accent-foreground"
|
|
: "text-muted-foreground hover:text-foreground"
|
|
}`}
|
|
onClick={() => setIsMenuOpen(false)}
|
|
>
|
|
Datasets
|
|
</Link>
|
|
</>
|
|
)}
|
|
<Link
|
|
href="/files"
|
|
className={`block px-3 py-2 rounded-md text-sm font-medium ${
|
|
isActive("/files")
|
|
? "bg-accent text-accent-foreground"
|
|
: "text-muted-foreground hover:text-foreground"
|
|
}`}
|
|
onClick={() => setIsMenuOpen(false)}
|
|
>
|
|
Files
|
|
</Link>
|
|
<Link
|
|
href="/datasets"
|
|
className={`block px-3 py-2 rounded-md text-sm font-medium ${
|
|
isActive("/datasets")
|
|
? "bg-accent text-accent-foreground"
|
|
: "text-muted-foreground hover:text-foreground"
|
|
}`}
|
|
onClick={() => setIsMenuOpen(false)}
|
|
>
|
|
Shares
|
|
</Link>
|
|
<Link
|
|
href="/file-sharing"
|
|
className={`block px-3 py-2 rounded-md text-sm font-medium ${
|
|
isActive("/file-sharing")
|
|
? "bg-accent text-accent-foreground"
|
|
: "text-muted-foreground hover:text-foreground"
|
|
}`}
|
|
onClick={() => setIsMenuOpen(false)}
|
|
>
|
|
File Sharing
|
|
</Link>
|
|
<Link
|
|
href="/identities"
|
|
className={`block px-3 py-2 rounded-md text-sm font-medium ${
|
|
isActive("/identities")
|
|
? "bg-accent text-accent-foreground"
|
|
: "text-muted-foreground hover:text-foreground"
|
|
}`}
|
|
onClick={() => setIsMenuOpen(false)}
|
|
>
|
|
Identities
|
|
</Link>
|
|
<Link
|
|
href="/logs"
|
|
className={`block px-3 py-2 rounded-md text-sm font-medium ${
|
|
isActive("/logs")
|
|
? "bg-accent text-accent-foreground"
|
|
: "text-muted-foreground hover:text-foreground"
|
|
}`}
|
|
onClick={() => setIsMenuOpen(false)}
|
|
>
|
|
Logs
|
|
</Link>
|
|
<Link
|
|
href="/services"
|
|
className={`block px-3 py-2 rounded-md text-sm font-medium ${
|
|
isActive("/services")
|
|
? "bg-accent text-accent-foreground"
|
|
: "text-muted-foreground hover:text-foreground"
|
|
}`}
|
|
onClick={() => setIsMenuOpen(false)}
|
|
>
|
|
Services
|
|
</Link>
|
|
</nav>
|
|
)}
|
|
</div>
|
|
</header>
|
|
)
|
|
}
|