mirror of
https://github.com/Nezumi-2711/9router.git
synced 2026-09-22 13:38:31 +00:00
Fix
This commit is contained in:
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "9router-app",
|
||||
"version": "0.4.30",
|
||||
"version": "0.4.31",
|
||||
"description": "9Router web dashboard",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
|
||||
@@ -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 */}
|
||||
<Card>
|
||||
<div className="flex items-center gap-3 mb-4">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setOidcExpanded((v) => !v)}
|
||||
className="w-full flex items-center gap-3 text-left"
|
||||
>
|
||||
<div className="p-2 rounded-lg bg-indigo-500/10 text-indigo-500 shrink-0">
|
||||
<span className="material-symbols-outlined text-[20px]">lock_open</span>
|
||||
</div>
|
||||
<h3 className="text-base sm:text-lg font-semibold">OIDC Dashboard Login</h3>
|
||||
</div>
|
||||
<div className="flex flex-col gap-4">
|
||||
<div className="flex-1 min-w-0">
|
||||
<h3 className="text-base sm:text-lg font-semibold">OIDC Dashboard Login</h3>
|
||||
<p className="text-xs text-text-muted">
|
||||
{settings.authMode === "oidc" ? "OIDC active" : settings.authMode === "both" ? "Password + OIDC active" : "Optional SSO via Authentik/Keycloak/Google"}
|
||||
</p>
|
||||
</div>
|
||||
<span className="material-symbols-outlined text-text-muted shrink-0">
|
||||
{oidcExpanded ? "expand_less" : "expand_more"}
|
||||
</span>
|
||||
</button>
|
||||
{oidcExpanded && (
|
||||
<div className="flex flex-col gap-4 mt-4">
|
||||
<p className="text-xs sm:text-sm text-text-muted">
|
||||
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.
|
||||
</p>
|
||||
@@ -820,6 +835,7 @@ export default function ProfilePage() {
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</Card>
|
||||
|
||||
{/* Routing Preferences */}
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -294,15 +294,13 @@ export default function Header({ onMenuClick, showMenuButton = true }) {
|
||||
|
||||
{/* Right actions */}
|
||||
<div className="flex items-center gap-1 shrink-0">
|
||||
{displayName && (
|
||||
{displayName && loginMethod === "OIDC" && (
|
||||
<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>
|
||||
)}
|
||||
<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">
|
||||
OIDC
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
<HeaderSearch />
|
||||
|
||||
Reference in New Issue
Block a user