CI / changes (push) Successful in 8s
CI / commitlint (push) Skipped
CI / openapi (push) Successful in 40s
CI / web (push) Successful in 55s
CI / go (push) Successful in 1m9s
CI / bird2 (push) Successful in 16s
CI / release (push) Successful in 4m6s
Refactored the settings components to unify navigation between UI and BIRD settings. Updated tab structures to streamline access and improve user experience. Adjusted routing and search parameters to reflect the new tab organization, ensuring a cohesive interface. Removed legacy tenant settings references and enhanced the settings page layout for clarity and usability.
75 lines
2.0 KiB
TypeScript
75 lines
2.0 KiB
TypeScript
import { createFileRoute, Outlet, redirect } from '@tanstack/react-router'
|
|
|
|
import { normalizeApiToken, TOKEN_STORAGE_KEY } from '@/lib/api-client'
|
|
import {
|
|
can,
|
|
ensureAuthConfig,
|
|
firstAllowedPath,
|
|
getClaims,
|
|
getPortalToken,
|
|
permissionForPath,
|
|
redirectToPortalLogin,
|
|
} from '@/lib/auth'
|
|
|
|
/**
|
|
* Two-mode gate:
|
|
* - VITE_AUTH_ENABLED / API `/v1/auth/config { required: true }`
|
|
* → require auth-portal JWT (SSO) + section permission via `can()`.
|
|
* - Off → keep legacy `evobgp_api_token` gate (redirect to /settings if empty).
|
|
*/
|
|
export const Route = createFileRoute('/_auth')({
|
|
beforeLoad: async ({ location }) => {
|
|
const cfg = await ensureAuthConfig()
|
|
|
|
if (cfg.required) {
|
|
const token = getPortalToken()
|
|
const claims = getClaims()
|
|
if (!token || !claims) {
|
|
const ok = redirectToPortalLogin(
|
|
`${window.location.origin}/auth/callback`,
|
|
)
|
|
if (!ok) {
|
|
throw redirect({
|
|
to: '/auth/callback',
|
|
search: { error: 'sso_loop' },
|
|
})
|
|
}
|
|
await new Promise(() => {})
|
|
return
|
|
}
|
|
if (!claims.apps.includes('bgp')) {
|
|
throw redirect({
|
|
to: '/auth/callback',
|
|
search: { error: 'sso_loop' },
|
|
})
|
|
}
|
|
const perm = permissionForPath(location.pathname)
|
|
if (perm && !can(perm)) {
|
|
const fallback = firstAllowedPath()
|
|
if (fallback !== location.pathname) {
|
|
throw redirect({ to: fallback as '/dashboard' })
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
// Settings available without token — first-run onboarding (incl. `dev`).
|
|
if (location.pathname === '/settings') return
|
|
const raw =
|
|
typeof window !== 'undefined'
|
|
? window.localStorage.getItem(TOKEN_STORAGE_KEY)
|
|
: null
|
|
if (!raw || !normalizeApiToken(raw)) {
|
|
throw redirect({
|
|
to: '/settings',
|
|
search: { tab: 'ui', reason: 'token-required' },
|
|
})
|
|
}
|
|
},
|
|
component: AuthLayout,
|
|
})
|
|
|
|
function AuthLayout() {
|
|
return <Outlet />
|
|
}
|