mirror of
https://github.com/GlueOps/autoglue.git
synced 2026-02-13 12:50:05 +01:00
feat: cluster page ui
Signed-off-by: allanice001 <allanice001@gmail.com>
This commit is contained in:
119
ui/src/pages/login.tsx
Normal file
119
ui/src/pages/login.tsx
Normal file
@@ -0,0 +1,119 @@
|
||||
import { useEffect, useMemo } from "react"
|
||||
import { authStore, type TokenPair } from "@/auth/store.ts"
|
||||
import { API_BASE } from "@/sdkClient.ts"
|
||||
import { useLocation, useNavigate } from "react-router-dom"
|
||||
|
||||
import { cn } from "@/lib/utils.ts"
|
||||
import { Button } from "@/components/ui/button.tsx"
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card.tsx"
|
||||
|
||||
function openPopup(url: string, name = "gsot-auth", w = 520, h = 640) {
|
||||
const y = window.top!.outerHeight / 2 + window.top!.screenY - h / 2
|
||||
const x = window.top!.outerWidth / 2 + window.top!.screenX - w / 2
|
||||
return window.open(
|
||||
url,
|
||||
name,
|
||||
`toolbar=no,location=no,status=no,menubar=no,scrollbars=yes,resizable=yes,width=${w},height=${h},top=${y},left=${x}`
|
||||
)
|
||||
}
|
||||
|
||||
async function startAuth(provider: "google" | "github") {
|
||||
const params = new URLSearchParams({
|
||||
mode: "spa",
|
||||
origin: window.location.origin,
|
||||
})
|
||||
const res = await fetch(`${API_BASE}/auth/${provider}/start?` + params, {
|
||||
method: "POST",
|
||||
})
|
||||
if (!res.ok) throw new Error("Failed to start auth")
|
||||
const data = await res.json()
|
||||
return data.auth_url as string
|
||||
}
|
||||
|
||||
export const Login = () => {
|
||||
const navigate = useNavigate()
|
||||
const loc = useLocation()
|
||||
|
||||
const to = useMemo(() => {
|
||||
const p = new URLSearchParams(loc.search).get("to") || "/me"
|
||||
try {
|
||||
// prevent absolute URLs & open redirects
|
||||
const url = new URL(p, window.location.origin)
|
||||
return url.origin === window.location.origin ? url.pathname + url.search : "/me"
|
||||
} catch {
|
||||
return "/me"
|
||||
}
|
||||
}, [loc.search])
|
||||
|
||||
useEffect(() => {
|
||||
if (authStore.get()?.access_token) {
|
||||
navigate(to, { replace: true })
|
||||
}
|
||||
}, [navigate, to])
|
||||
|
||||
useEffect(() => {
|
||||
const onMsg = (ev: MessageEvent) => {
|
||||
const okType = typeof ev.data === "object" && ev.data?.type === "autoglue:auth"
|
||||
if (!okType) return
|
||||
const tokens: TokenPair = ev.data.payload
|
||||
authStore.set(tokens)
|
||||
navigate(to, { replace: true })
|
||||
}
|
||||
window.addEventListener("message", onMsg)
|
||||
return () => window.removeEventListener("message", onMsg)
|
||||
}, [navigate, to])
|
||||
|
||||
const login = async (provider: "google" | "github") => {
|
||||
const url = await startAuth(provider)
|
||||
const win = openPopup(url)
|
||||
if (!win) alert("Please allow popups to sign in.")
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="mx-auto flex items-center justify-center p-4">
|
||||
<Card className="w-full max-w-md">
|
||||
<CardHeader>
|
||||
<CardTitle className="text-lg md:text-xl">Sign In</CardTitle>
|
||||
<CardDescription className="text-xs md:text-sm">
|
||||
Continue with a provider below to access your account.
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
|
||||
<CardContent>
|
||||
<div className="grid gap-4">
|
||||
<div className={cn("flex w-full items-center gap-2", "flex-col justify-between")}>
|
||||
<Button variant="outline" className="w-full gap-2" onClick={() => login("google")}>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="0.98em"
|
||||
height="1em"
|
||||
viewBox="0 0 256 262"
|
||||
aria-hidden="true"
|
||||
focusable="false"
|
||||
>
|
||||
<path
|
||||
fill="#4285F4"
|
||||
d="M255.878 133.451c0-10.734-.871-18.567-2.756-26.69H130.55v48.448h71.947c-1.45 12.04-9.283 30.172-26.69 42.356l-.244 1.622l38.755 30.023l2.685.268c24.659-22.774 38.875-56.282 38.875-96.027"
|
||||
></path>
|
||||
<path
|
||||
fill="#34A853"
|
||||
d="M130.55 261.1c35.248 0 64.839-11.605 86.453-31.622l-41.196-31.913c-11.024 7.688-25.82 13.055-45.257 13.055c-34.523 0-63.824-22.773-74.269-54.25l-1.531.13l-40.298 31.187l-.527 1.465C35.393 231.798 79.49 261.1 130.55 261.1"
|
||||
></path>
|
||||
<path
|
||||
fill="#FBBC05"
|
||||
d="M56.281 156.37c-2.756-8.123-4.351-16.827-4.351-25.82c0-8.994 1.595-17.697 4.206-25.82l-.073-1.73L15.26 71.312l-1.335.635C5.077 89.644 0 109.517 0 130.55s5.077 40.905 13.925 58.602z"
|
||||
></path>
|
||||
<path
|
||||
fill="#EB4335"
|
||||
d="M130.55 50.479c24.514 0 41.05 10.589 50.479 19.438l36.844-35.974C195.245 12.91 165.798 0 130.55 0C79.49 0 35.393 29.301 13.925 71.947l42.211 32.783c10.59-31.477 39.891-54.251 74.414-54.251"
|
||||
></path>
|
||||
</svg>
|
||||
Sign in with Google
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user