diff --git a/package.json b/package.json index 96bff70c..174d72a7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "9router-app", - "version": "0.4.30", + "version": "0.4.31", "description": "9Router web dashboard", "private": true, "scripts": { diff --git a/src/app/(dashboard)/dashboard/profile/page.js b/src/app/(dashboard)/dashboard/profile/page.js index fde05916..5ec301e3 100644 --- a/src/app/(dashboard)/dashboard/profile/page.js +++ b/src/app/(dashboard)/dashboard/profile/page.js @@ -28,6 +28,7 @@ export default function ProfilePage() { const [oidcTestLoading, setOidcTestLoading] = useState(false); const [oidcTestStatus, setOidcTestStatus] = useState({ type: "", message: "" }); const [oidcRedirectUri, setOidcRedirectUri] = useState("/api/auth/oidc/callback"); + const [oidcExpanded, setOidcExpanded] = useState(false); const importFileRef = useRef(null); const [proxyForm, setProxyForm] = useState({ outboundProxyEnabled: false, @@ -51,6 +52,7 @@ export default function ProfilePage() { oidcLoginLabel: data?.oidcLoginLabel || "Sign in with OIDC", }); setOidcClientSecret(""); + if (data?.authMode === "oidc" || data?.authMode === "both") setOidcExpanded(true); setProxyForm({ outboundProxyEnabled: data?.outboundProxyEnabled === true, outboundProxyUrl: data?.outboundProxyUrl || "", @@ -675,13 +677,26 @@ export default function ProfilePage() { {/* OIDC */} -
+
-
+
+

OIDC Dashboard Login

+

+ {settings.authMode === "oidc" ? "OIDC active" : settings.authMode === "both" ? "Password + OIDC active" : "Optional SSO via Authentik/Keycloak/Google"} +

+
+ + {oidcExpanded ? "expand_less" : "expand_more"} + + + {oidcExpanded && ( +

Use Authentik or any OIDC provider to sign in to the dashboard. You can enable password-only, OIDC-only, or both for the dashboard; model API access still uses API keys.

@@ -820,6 +835,7 @@ export default function ProfilePage() {

)}
+ )} {/* Routing Preferences */} diff --git a/src/app/(dashboard)/dashboard/providers/page.js b/src/app/(dashboard)/dashboard/providers/page.js index 24eb93be..43d4e30b 100644 --- a/src/app/(dashboard)/dashboard/providers/page.js +++ b/src/app/(dashboard)/dashboard/providers/page.js @@ -252,46 +252,35 @@ export default function ProvidersPage() { } }; - const compatibleProviders = sortItemsByPriority( - providerNodes - .filter((node) => node.type === "openai-compatible") - .map((node) => ({ - id: node.id, - name: node.name || "OpenAI Compatible", - color: "#10A37F", - textIcon: "OC", - apiType: node.apiType, - })) - .filter((p) => matchSearch(p.name)), - "apikey", - ); + const compatibleProviders = providerNodes + .filter((node) => node.type === "openai-compatible") + .map((node) => ({ + id: node.id, + name: node.name || "OpenAI Compatible", + color: "#10A37F", + textIcon: "OC", + apiType: node.apiType, + })) + .filter((p) => matchSearch(p.name)); - const anthropicCompatibleProviders = sortItemsByPriority( - providerNodes - .filter((node) => node.type === "anthropic-compatible") - .map((node) => ({ - id: node.id, - name: node.name || "Anthropic Compatible", - color: "#D97757", - textIcon: "AC", - })) - .filter((p) => matchSearch(p.name)), - "apikey", - ); + const anthropicCompatibleProviders = providerNodes + .filter((node) => node.type === "anthropic-compatible") + .map((node) => ({ + id: node.id, + name: node.name || "Anthropic Compatible", + color: "#D97757", + textIcon: "AC", + })) + .filter((p) => matchSearch(p.name)); - const oauthEntries = sortByPriority( - Object.entries(OAUTH_PROVIDERS).filter(([, info]) => matchSearch(info.name)), - "oauth", + const oauthEntries = Object.entries(OAUTH_PROVIDERS).filter(([, info]) => + matchSearch(info.name), ); - const freeEntries = sortByPriority( - Object.entries(FREE_PROVIDERS).filter(([, info]) => matchSearch(info.name)), - "oauth", + const freeEntries = Object.entries(FREE_PROVIDERS).filter(([, info]) => + matchSearch(info.name), ); - const freeTierEntries = sortByPriority( - Object.entries(FREE_TIER_PROVIDERS).filter(([, info]) => - matchSearch(info.name), - ), - "apikey", + const freeTierEntries = Object.entries(FREE_TIER_PROVIDERS).filter( + ([, info]) => matchSearch(info.name), ); const apikeyEntries = sortByPriority( Object.entries(APIKEY_PROVIDERS).filter( diff --git a/src/shared/components/Header.js b/src/shared/components/Header.js index 4d003611..f236be02 100644 --- a/src/shared/components/Header.js +++ b/src/shared/components/Header.js @@ -294,15 +294,13 @@ export default function Header({ onMenuClick, showMenuButton = true }) { {/* Right actions */}
- {displayName && ( + {displayName && loginMethod === "OIDC" && (
person {displayName} - {loginMethod && ( - - {loginMethod} - - )} + + OIDC +
)}