start working on the frontend side

This commit is contained in:
Warp Agent
2025-12-24 19:53:45 +00:00
parent 3aa0169af0
commit c962a223c6
84 changed files with 14761 additions and 58 deletions

View File

@@ -0,0 +1,101 @@
import { Outlet, Link, useNavigate } from 'react-router-dom'
import { useAuthStore } from '@/store/auth'
import { LogOut, Menu } from 'lucide-react'
import { useState } from 'react'
export default function Layout() {
const { user, clearAuth } = useAuthStore()
const navigate = useNavigate()
const [sidebarOpen, setSidebarOpen] = useState(true)
const handleLogout = () => {
clearAuth()
navigate('/login')
}
const navigation = [
{ name: 'Dashboard', href: '/', icon: '📊' },
{ name: 'Storage', href: '/storage', icon: '💾' },
{ name: 'Tape Libraries', href: '/tape', icon: '📼' },
{ name: 'iSCSI Targets', href: '/iscsi', icon: '🔌' },
{ name: 'Tasks', href: '/tasks', icon: '⚙️' },
{ name: 'Alerts', href: '/alerts', icon: '🔔' },
{ name: 'System', href: '/system', icon: '🖥️' },
]
if (user?.roles.includes('admin')) {
navigation.push({ name: 'IAM', href: '/iam', icon: '👥' })
}
return (
<div className="min-h-screen bg-gray-50">
{/* Sidebar */}
<div
className={`fixed inset-y-0 left-0 z-50 w-64 bg-gray-900 text-white transition-transform duration-300 ${
sidebarOpen ? 'translate-x-0' : '-translate-x-full'
}`}
>
<div className="flex flex-col h-full">
<div className="flex items-center justify-between p-4 border-b border-gray-800">
<h1 className="text-xl font-bold">Calypso</h1>
<button
onClick={() => setSidebarOpen(false)}
className="lg:hidden text-gray-400 hover:text-white"
>
<Menu className="h-6 w-6" />
</button>
</div>
<nav className="flex-1 p-4 space-y-2">
{navigation.map((item) => (
<Link
key={item.name}
to={item.href}
className="flex items-center space-x-3 px-4 py-2 rounded-lg hover:bg-gray-800 transition-colors"
>
<span>{item.icon}</span>
<span>{item.name}</span>
</Link>
))}
</nav>
<div className="p-4 border-t border-gray-800">
<div className="flex items-center justify-between mb-4">
<div>
<p className="text-sm font-medium">{user?.username}</p>
<p className="text-xs text-gray-400">{user?.roles.join(', ')}</p>
</div>
</div>
<button
onClick={handleLogout}
className="w-full flex items-center space-x-2 px-4 py-2 rounded-lg hover:bg-gray-800 transition-colors"
>
<LogOut className="h-4 w-4" />
<span>Logout</span>
</button>
</div>
</div>
</div>
{/* Main content */}
<div className={`transition-all duration-300 ${sidebarOpen ? 'lg:ml-64' : 'ml-0'}`}>
{/* Top bar */}
<div className="bg-white shadow-sm border-b border-gray-200">
<div className="flex items-center justify-between px-6 py-4">
<button
onClick={() => setSidebarOpen(!sidebarOpen)}
className="lg:hidden text-gray-600 hover:text-gray-900"
>
<Menu className="h-6 w-6" />
</button>
<div className="flex-1" />
</div>
</div>
{/* Page content */}
<main className="p-6">
<Outlet />
</main>
</div>
</div>
)
}

View File

@@ -0,0 +1,39 @@
import * as React from "react"
import { cn } from "@/lib/utils"
export interface ButtonProps
extends React.ButtonHTMLAttributes<HTMLButtonElement> {
variant?: "default" | "destructive" | "outline" | "secondary" | "ghost" | "link"
size?: "default" | "sm" | "lg" | "icon"
}
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
({ className, variant = "default", size = "default", ...props }, ref) => {
return (
<button
className={cn(
"inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
{
"bg-primary text-primary-foreground hover:bg-primary/90": variant === "default",
"bg-destructive text-destructive-foreground hover:bg-destructive/90": variant === "destructive",
"border border-input bg-background hover:bg-accent hover:text-accent-foreground": variant === "outline",
"bg-secondary text-secondary-foreground hover:bg-secondary/80": variant === "secondary",
"hover:bg-accent hover:text-accent-foreground": variant === "ghost",
"text-primary underline-offset-4 hover:underline": variant === "link",
"h-10 px-4 py-2": size === "default",
"h-9 rounded-md px-3": size === "sm",
"h-11 rounded-md px-8": size === "lg",
"h-10 w-10": size === "icon",
},
className
)}
ref={ref}
{...props}
/>
)
}
)
Button.displayName = "Button"
export { Button }

View File

@@ -0,0 +1,79 @@
import * as React from "react"
import { cn } from "@/lib/utils"
const Card = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => (
<div
ref={ref}
className={cn(
"rounded-lg border bg-card text-card-foreground shadow-sm",
className
)}
{...props}
/>
))
Card.displayName = "Card"
const CardHeader = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => (
<div
ref={ref}
className={cn("flex flex-col space-y-1.5 p-6", className)}
{...props}
/>
))
CardHeader.displayName = "CardHeader"
const CardTitle = React.forwardRef<
HTMLParagraphElement,
React.HTMLAttributes<HTMLHeadingElement>
>(({ className, ...props }, ref) => (
<h3
ref={ref}
className={cn(
"text-2xl font-semibold leading-none tracking-tight",
className
)}
{...props}
/>
))
CardTitle.displayName = "CardTitle"
const CardDescription = React.forwardRef<
HTMLParagraphElement,
React.HTMLAttributes<HTMLParagraphElement>
>(({ className, ...props }, ref) => (
<p
ref={ref}
className={cn("text-sm text-muted-foreground", className)}
{...props}
/>
))
CardDescription.displayName = "CardDescription"
const CardContent = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => (
<div ref={ref} className={cn("p-6 pt-0", className)} {...props} />
))
CardContent.displayName = "CardContent"
const CardFooter = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => (
<div
ref={ref}
className={cn("flex items-center p-6 pt-0", className)}
{...props}
/>
))
CardFooter.displayName = "CardFooter"
export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent }

View File

@@ -0,0 +1,6 @@
// Placeholder for toast notifications
// Will be implemented with shadcn/ui toast component
export function Toaster() {
return null
}