Files
EvoBGP/apps/web/src/routes/_auth.tsx
T
Denozordec e0d695f2a4
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
refactor(web): unify settings navigation and update tab structure
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.
2026-08-18 16:30:10 +07:00

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 />
}