api.ts + useAuthConfig kept the old wizard-era localStorage path for the backend URL, which is why fresh browsers saw blank pages on MonitorPage and any other api-using page after the v0.4.0 wizard removal — without the wizard pre-seeding localStorage, getApiBase() returned undefined and axios called same-origin (frontend nginx, 404). App.tsx getApiBase() partially worked because I had only refactored that one path; api.ts (used by everything else) still had its own duplicate getApiBase that I missed. This commit removes the localStorage path entirely from all 3 read sites (api.ts / App.tsx / useAuthConfig.ts) — single source of truth is now the build-time env baked in by the Dockerfile ARG. - src/services/api.ts: const API_BASE = import.meta.env.VITE_HF_BACKEND_BASE_URL - src/App.tsx: const API_BASE = ... (replaces getApiBase()) - src/hooks/useAuthConfig.ts: const BACKEND_BASE = ... - src/test/setup.ts: stub import.meta.env instead of localStorage key Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
77 lines
1.8 KiB
TypeScript
77 lines
1.8 KiB
TypeScript
import { useState, useEffect } from 'react'
|
|
import api from '@/services/api'
|
|
|
|
export interface AuthConfig {
|
|
oidcEnabled: boolean
|
|
oidcOnly: boolean
|
|
passwordLogin: boolean
|
|
oidcLoginUrl: string
|
|
}
|
|
|
|
const DEFAULT: AuthConfig = {
|
|
oidcEnabled: false,
|
|
oidcOnly: false,
|
|
passwordLogin: true,
|
|
oidcLoginUrl: '/auth/oidc/login',
|
|
}
|
|
|
|
let cache: AuthConfig | null = null
|
|
let inflight: Promise<AuthConfig> | null = null
|
|
|
|
async function load(): Promise<AuthConfig> {
|
|
if (cache) return cache
|
|
if (inflight) return inflight
|
|
inflight = api
|
|
.get('/auth/config')
|
|
.then(({ data }) => {
|
|
cache = {
|
|
oidcEnabled: !!data.oidc_enabled,
|
|
oidcOnly: !!data.oidc_only,
|
|
passwordLogin: data.password_login !== false,
|
|
oidcLoginUrl: data.oidc_login_url || '/auth/oidc/login',
|
|
}
|
|
return cache
|
|
})
|
|
.catch(() => {
|
|
// Backend unreachable / old backend without /auth/config:
|
|
// fall back to password-only so login is never fully blocked.
|
|
cache = { ...DEFAULT }
|
|
return cache
|
|
})
|
|
.finally(() => {
|
|
inflight = null
|
|
})
|
|
return inflight
|
|
}
|
|
|
|
/** Absolute backend URL for full-page OIDC redirects. */
|
|
const BACKEND_BASE = import.meta.env.VITE_HF_BACKEND_BASE_URL || ''
|
|
|
|
export function oidcLoginHref(cfg: AuthConfig): string {
|
|
return `${BACKEND_BASE}${cfg.oidcLoginUrl}`
|
|
}
|
|
|
|
export function oidcLinkHref(): string {
|
|
return `${BACKEND_BASE}/auth/oidc/link`
|
|
}
|
|
|
|
export function useAuthConfig() {
|
|
const [config, setConfig] = useState<AuthConfig | null>(cache)
|
|
const [loading, setLoading] = useState(!cache)
|
|
|
|
useEffect(() => {
|
|
let alive = true
|
|
load().then((c) => {
|
|
if (alive) {
|
|
setConfig(c)
|
|
setLoading(false)
|
|
}
|
|
})
|
|
return () => {
|
|
alive = false
|
|
}
|
|
}, [])
|
|
|
|
return { config: config ?? DEFAULT, loading }
|
|
}
|