Add OIDC dashboard auth (#1020)

This commit is contained in:
Walter Cheng 2026-05-11 22:43:42 -04:00 committed by GitHub
parent a48fa4eb21
commit c3d91b019b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
14 changed files with 1016 additions and 67 deletions

View file

@ -1,7 +1,7 @@
"use client";
import { useEffect, useMemo, useState } from "react";
import { usePathname, useRouter } from "next/navigation";
import { useMemo } from "react";
import Link from "next/link";
import PropTypes from "prop-types";
import ProviderIcon from "@/shared/components/ProviderIcon";
@ -172,11 +172,39 @@ const getPageInfo = (pathname) => {
export default function Header({ onMenuClick, showMenuButton = true }) {
const pathname = usePathname();
const router = useRouter();
const [displayName, setDisplayName] = useState("");
const [loginMethod, setLoginMethod] = useState("");
// Memoize page info to prevent unnecessary recalculations
const pageInfo = useMemo(() => getPageInfo(pathname), [pathname]);
const { title, description, icon, breadcrumbs } = pageInfo;
useEffect(() => {
let cancelled = false;
async function loadAuthStatus() {
try {
const res = await fetch("/api/auth/status", { cache: "no-store" });
if (!res.ok) return;
const data = await res.json();
if (!cancelled) {
setDisplayName(data?.displayName || data?.oidcName || data?.oidcEmail || "");
setLoginMethod(data?.loginMethod || "");
}
} catch {
if (!cancelled) {
setDisplayName("");
setLoginMethod("");
}
}
}
loadAuthStatus();
return () => {
cancelled = true;
};
}, []);
const handleLogout = async () => {
try {
const res = await fetch("/api/auth/logout", { method: "POST" });
@ -266,6 +294,17 @@ export default function Header({ onMenuClick, showMenuButton = true }) {
{/* Right actions */}
<div className="flex items-center gap-1 shrink-0">
{displayName && (
<div className="hidden sm:flex items-center max-w-[220px] px-3 py-1.5 rounded-full border border-border bg-surface/70 text-xs text-text-muted truncate">
<span className="material-symbols-outlined text-[14px] mr-1.5 text-primary">person</span>
<span className="truncate">{displayName}</span>
{loginMethod && (
<span className="ml-2 shrink-0 rounded-full bg-primary/10 px-2 py-0.5 text-[10px] font-semibold uppercase tracking-wide text-primary">
{loginMethod}
</span>
)}
</div>
)}
<HeaderSearch />
<ThemeToggle />
<HeaderMenu onLogout={handleLogout} />