mirror of
https://github.com/MacRimi/ProxMenux.git
synced 2025-11-18 19:46:18 +00:00
Update AppImage
This commit is contained in:
@@ -176,6 +176,13 @@ export function OnboardingCarousel() {
|
|||||||
setOpen(false)
|
setOpen(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleClose = () => {
|
||||||
|
if (dontShowAgain) {
|
||||||
|
localStorage.setItem("proxmenux-onboarding-seen", "true")
|
||||||
|
}
|
||||||
|
setOpen(false)
|
||||||
|
}
|
||||||
|
|
||||||
const handleDotClick = (index: number) => {
|
const handleDotClick = (index: number) => {
|
||||||
setDirection(index > currentSlide ? "next" : "prev")
|
setDirection(index > currentSlide ? "next" : "prev")
|
||||||
setCurrentSlide(index)
|
setCurrentSlide(index)
|
||||||
@@ -184,7 +191,7 @@ export function OnboardingCarousel() {
|
|||||||
const slide = slides[currentSlide]
|
const slide = slides[currentSlide]
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dialog open={open} onOpenChange={setOpen}>
|
<Dialog open={open} onOpenChange={handleClose}>
|
||||||
<DialogContent className="max-w-4xl p-0 gap-0 overflow-hidden border-0 bg-transparent">
|
<DialogContent className="max-w-4xl p-0 gap-0 overflow-hidden border-0 bg-transparent">
|
||||||
<div className="relative bg-card rounded-lg overflow-hidden shadow-2xl">
|
<div className="relative bg-card rounded-lg overflow-hidden shadow-2xl">
|
||||||
{/* Close button */}
|
{/* Close button */}
|
||||||
@@ -192,7 +199,7 @@ export function OnboardingCarousel() {
|
|||||||
variant="ghost"
|
variant="ghost"
|
||||||
size="icon"
|
size="icon"
|
||||||
className="absolute top-4 right-4 z-50 h-8 w-8 rounded-full bg-background/80 backdrop-blur-sm hover:bg-background"
|
className="absolute top-4 right-4 z-50 h-8 w-8 rounded-full bg-background/80 backdrop-blur-sm hover:bg-background"
|
||||||
onClick={handleSkip}
|
onClick={handleClose}
|
||||||
>
|
>
|
||||||
<X className="h-4 w-4" />
|
<X className="h-4 w-4" />
|
||||||
</Button>
|
</Button>
|
||||||
@@ -234,23 +241,23 @@ export function OnboardingCarousel() {
|
|||||||
<div className="absolute bottom-10 right-10 w-32 h-32 bg-white/10 rounded-full blur-3xl" />
|
<div className="absolute bottom-10 right-10 w-32 h-32 bg-white/10 rounded-full blur-3xl" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="p-4 md:p-8 space-y-4 md:space-y-6">
|
<div className="p-4 md:p-8 space-y-3 md:space-y-6 max-h-[60vh] md:max-h-none overflow-y-auto">
|
||||||
<div className="space-y-2 md:space-y-3">
|
<div className="space-y-2 md:space-y-3">
|
||||||
<h2 className="text-2xl md:text-3xl font-bold text-foreground text-balance">{slide.title}</h2>
|
<h2 className="text-xl md:text-3xl font-bold text-foreground text-balance">{slide.title}</h2>
|
||||||
<p className="text-base md:text-lg text-muted-foreground leading-relaxed text-pretty">
|
<p className="text-sm md:text-lg text-muted-foreground leading-relaxed text-pretty">
|
||||||
{slide.description}
|
{slide.description}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{slide.features && (
|
{slide.features && (
|
||||||
<div className="space-y-3 py-2">
|
<div className="space-y-2 md:space-y-3 py-2">
|
||||||
{slide.features.map((feature, index) => (
|
{slide.features.map((feature, index) => (
|
||||||
<div
|
<div
|
||||||
key={index}
|
key={index}
|
||||||
className="flex items-start gap-3 p-3 rounded-lg bg-muted/50 border border-border/50"
|
className="flex items-start gap-2 md:gap-3 p-2 md:p-3 rounded-lg bg-muted/50 border border-border/50"
|
||||||
>
|
>
|
||||||
<div className="text-blue-500 mt-0.5">{feature.icon}</div>
|
<div className="text-blue-500 mt-0.5 flex-shrink-0">{feature.icon}</div>
|
||||||
<p className="text-sm text-foreground leading-relaxed">{feature.text}</p>
|
<p className="text-xs md:text-sm text-foreground leading-relaxed">{feature.text}</p>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
@@ -272,12 +279,12 @@ export function OnboardingCarousel() {
|
|||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex flex-col sm:flex-row items-center justify-between gap-3 md:gap-4">
|
<div className="flex flex-col sm:flex-row items-center justify-between gap-2 md:gap-4">
|
||||||
<Button
|
<Button
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
onClick={handlePrev}
|
onClick={handlePrev}
|
||||||
disabled={currentSlide === 0}
|
disabled={currentSlide === 0}
|
||||||
className="gap-2 w-full sm:w-auto"
|
className="gap-2 w-full sm:w-auto text-sm"
|
||||||
>
|
>
|
||||||
<ChevronLeft className="h-4 w-4" />
|
<ChevronLeft className="h-4 w-4" />
|
||||||
Previous
|
Previous
|
||||||
@@ -286,10 +293,17 @@ export function OnboardingCarousel() {
|
|||||||
<div className="flex gap-2 w-full sm:w-auto">
|
<div className="flex gap-2 w-full sm:w-auto">
|
||||||
{currentSlide < slides.length - 1 ? (
|
{currentSlide < slides.length - 1 ? (
|
||||||
<>
|
<>
|
||||||
<Button variant="outline" onClick={handleSkip} className="flex-1 sm:flex-none bg-transparent">
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
onClick={handleSkip}
|
||||||
|
className="flex-1 sm:flex-none bg-transparent text-sm"
|
||||||
|
>
|
||||||
Skip
|
Skip
|
||||||
</Button>
|
</Button>
|
||||||
<Button onClick={handleNext} className="gap-2 bg-blue-500 hover:bg-blue-600 flex-1 sm:flex-none">
|
<Button
|
||||||
|
onClick={handleNext}
|
||||||
|
className="gap-2 bg-blue-500 hover:bg-blue-600 flex-1 sm:flex-none text-sm"
|
||||||
|
>
|
||||||
Next
|
Next
|
||||||
<ChevronRight className="h-4 w-4" />
|
<ChevronRight className="h-4 w-4" />
|
||||||
</Button>
|
</Button>
|
||||||
@@ -297,7 +311,7 @@ export function OnboardingCarousel() {
|
|||||||
) : (
|
) : (
|
||||||
<Button
|
<Button
|
||||||
onClick={handleNext}
|
onClick={handleNext}
|
||||||
className="gap-2 bg-gradient-to-r from-blue-500 to-purple-500 hover:from-blue-600 hover:to-purple-600 w-full sm:w-auto"
|
className="gap-2 bg-gradient-to-r from-blue-500 to-purple-500 hover:from-blue-600 hover:to-purple-600 w-full sm:w-auto text-sm"
|
||||||
>
|
>
|
||||||
Get Started!
|
Get Started!
|
||||||
<Sparkles className="h-4 w-4" />
|
<Sparkles className="h-4 w-4" />
|
||||||
@@ -306,7 +320,7 @@ export function OnboardingCarousel() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex items-center justify-center gap-2 pt-2">
|
<div className="flex items-center justify-center gap-2 pt-2 pb-1">
|
||||||
<Checkbox
|
<Checkbox
|
||||||
id="dont-show-again"
|
id="dont-show-again"
|
||||||
checked={dontShowAgain}
|
checked={dontShowAgain}
|
||||||
@@ -314,7 +328,7 @@ export function OnboardingCarousel() {
|
|||||||
/>
|
/>
|
||||||
<label
|
<label
|
||||||
htmlFor="dont-show-again"
|
htmlFor="dont-show-again"
|
||||||
className="text-sm text-muted-foreground hover:text-foreground transition-colors cursor-pointer"
|
className="text-xs md:text-sm text-muted-foreground hover:text-foreground transition-colors cursor-pointer select-none"
|
||||||
>
|
>
|
||||||
Don't show this again
|
Don't show this again
|
||||||
</label>
|
</label>
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ export function ProxmoxDashboard() {
|
|||||||
const [authChecked, setAuthChecked] = useState(false)
|
const [authChecked, setAuthChecked] = useState(false)
|
||||||
const [authRequired, setAuthRequired] = useState(false)
|
const [authRequired, setAuthRequired] = useState(false)
|
||||||
const [isAuthenticated, setIsAuthenticated] = useState(false)
|
const [isAuthenticated, setIsAuthenticated] = useState(false)
|
||||||
const [authSetupComplete, setAuthSetupComplete] = useState(false)
|
const [authDeclined, setAuthDeclined] = useState(false)
|
||||||
|
|
||||||
const fetchSystemData = useCallback(async () => {
|
const fetchSystemData = useCallback(async () => {
|
||||||
console.log("[v0] Fetching system data from Flask server...")
|
console.log("[v0] Fetching system data from Flask server...")
|
||||||
@@ -278,7 +278,7 @@ export function ProxmoxDashboard() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const handleAuthSetupComplete = () => {
|
const handleAuthSetupComplete = () => {
|
||||||
setAuthSetupComplete(true)
|
setAuthDeclined(true)
|
||||||
setIsAuthenticated(true)
|
setIsAuthenticated(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -292,6 +292,8 @@ export function ProxmoxDashboard() {
|
|||||||
console.log("[v0] Checking authentication status...")
|
console.log("[v0] Checking authentication status...")
|
||||||
try {
|
try {
|
||||||
const token = localStorage.getItem("proxmenux-auth-token")
|
const token = localStorage.getItem("proxmenux-auth-token")
|
||||||
|
const hasDeclined = localStorage.getItem("proxmenux-auth-declined") === "true"
|
||||||
|
|
||||||
const headers: HeadersInit = { "Content-Type": "application/json" }
|
const headers: HeadersInit = { "Content-Type": "application/json" }
|
||||||
|
|
||||||
if (token) {
|
if (token) {
|
||||||
@@ -311,17 +313,15 @@ export function ProxmoxDashboard() {
|
|||||||
const data = await response.json()
|
const data = await response.json()
|
||||||
console.log("[v0] Auth status response:", data)
|
console.log("[v0] Auth status response:", data)
|
||||||
|
|
||||||
const authConfigured = data.auth_enabled || data.authenticated
|
|
||||||
|
|
||||||
setAuthRequired(data.auth_enabled)
|
setAuthRequired(data.auth_enabled)
|
||||||
setIsAuthenticated(data.authenticated)
|
setIsAuthenticated(data.authenticated)
|
||||||
setAuthSetupComplete(authConfigured)
|
setAuthDeclined(hasDeclined || !data.auth_enabled)
|
||||||
setAuthChecked(true)
|
setAuthChecked(true)
|
||||||
|
|
||||||
console.log("[v0] Auth state:", {
|
console.log("[v0] Auth state:", {
|
||||||
authRequired: data.auth_enabled,
|
authRequired: data.auth_enabled,
|
||||||
isAuthenticated: data.authenticated,
|
isAuthenticated: data.authenticated,
|
||||||
authSetupComplete: authConfigured,
|
authDeclined: hasDeclined || !data.auth_enabled,
|
||||||
})
|
})
|
||||||
|
|
||||||
if (data.authenticated && token) {
|
if (data.authenticated && token) {
|
||||||
@@ -329,7 +329,7 @@ export function ProxmoxDashboard() {
|
|||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("[v0] Failed to check auth status:", error)
|
console.error("[v0] Failed to check auth status:", error)
|
||||||
setAuthSetupComplete(false)
|
setAuthDeclined(false)
|
||||||
setAuthChecked(true)
|
setAuthChecked(true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -356,7 +356,7 @@ export function ProxmoxDashboard() {
|
|||||||
<div className="min-h-screen bg-background">
|
<div className="min-h-screen bg-background">
|
||||||
<OnboardingCarousel />
|
<OnboardingCarousel />
|
||||||
|
|
||||||
{!authSetupComplete && <AuthSetup onComplete={handleAuthSetupComplete} />}
|
{!authDeclined && !authRequired && <AuthSetup onComplete={handleAuthSetupComplete} />}
|
||||||
|
|
||||||
{!isServerConnected && (
|
{!isServerConnected && (
|
||||||
<div className="bg-red-500/10 border-b border-red-500/20 px-6 py-3">
|
<div className="bg-red-500/10 border-b border-red-500/20 px-6 py-3">
|
||||||
|
|||||||
Reference in New Issue
Block a user