feat(header): Display active S2A profile information in header

- Add Server icon import from lucide-react for profile display
- Import useConfig hook and S2AProfile type for configuration access
- Implement activeProfile state to track currently selected S2A profile
- Add useEffect hook to fetch and match S2A profiles against current API base configuration
- Replace spacer div with active profile information display component
- Show profile name and API base URL when profile is matched
- Display API base URL directly when configured but profile not found
- Add responsive styling with dark mode support for profile info badge
- Use truncation and flex-shrink to prevent layout overflow on smaller screens
- Provides users with clear visibility of which S2A profile is currently active
This commit is contained in:
2026-02-07 14:29:55 +08:00
parent 060d21eb4f
commit 0ad5881259

View File

@@ -1,6 +1,8 @@
import { Menu, Moon, Sun, Database, UserPlus } from 'lucide-react' import { Menu, Moon, Sun, Database, UserPlus, Server } from 'lucide-react'
import { useState, useEffect } from 'react' import { useState, useEffect } from 'react'
import { useTeamStatus } from '../../hooks/useTeamStatus' import { useTeamStatus } from '../../hooks/useTeamStatus'
import { useConfig } from '../../hooks/useConfig'
import type { S2AProfile } from '../../types'
interface HeaderProps { interface HeaderProps {
onMenuClick: () => void onMenuClick: () => void
@@ -10,6 +12,25 @@ interface HeaderProps {
export default function Header({ onMenuClick, isConnected = false }: HeaderProps) { export default function Header({ onMenuClick, isConnected = false }: HeaderProps) {
const [isDark, setIsDark] = useState(false) const [isDark, setIsDark] = useState(false)
const teamStatus = useTeamStatus() const teamStatus = useTeamStatus()
const { config } = useConfig()
const [activeProfile, setActiveProfile] = useState<S2AProfile | null>(null)
// 匹配当前活动配置对应的 profile 名称
useEffect(() => {
if (!config.s2a.apiBase) {
setActiveProfile(null)
return
}
fetch('/api/s2a/profiles')
.then(res => res.json())
.then(data => {
if (data.code === 0 && data.data) {
const match = (data.data as S2AProfile[]).find(p => p.api_base === config.s2a.apiBase)
setActiveProfile(match || null)
}
})
.catch(() => setActiveProfile(null))
}, [config.s2a.apiBase])
useEffect(() => { useEffect(() => {
// Check for saved theme preference or system preference // Check for saved theme preference or system preference
@@ -54,8 +75,21 @@ export default function Header({ onMenuClick, isConnected = false }: HeaderProps
</span> </span>
</div> </div>
{/* Spacer */} {/* Active S2A Profile Info */}
<div className="flex-1" /> <div className="flex-1 flex items-center justify-start min-w-0">
{activeProfile ? (
<div className="flex items-center gap-2 min-w-0 px-2.5 py-1 rounded-lg bg-slate-50 dark:bg-slate-800/50 border border-slate-200/50 dark:border-slate-700/50">
<Server className="h-3.5 w-3.5 text-blue-500 flex-shrink-0" />
<span className="text-sm font-medium text-slate-700 dark:text-slate-300 truncate">{activeProfile.name}</span>
<span className="hidden md:inline text-xs text-slate-400 dark:text-slate-500 truncate">{activeProfile.api_base}</span>
</div>
) : config.s2a.apiBase ? (
<div className="flex items-center gap-2 min-w-0 px-2.5 py-1 rounded-lg bg-slate-50 dark:bg-slate-800/50 border border-slate-200/50 dark:border-slate-700/50">
<Server className="h-3.5 w-3.5 text-slate-400 flex-shrink-0" />
<span className="hidden md:inline text-xs text-slate-400 dark:text-slate-500 truncate">{config.s2a.apiBase}</span>
</div>
) : null}
</div>
{/* Team Status Indicators */} {/* Team Status Indicators */}
{teamStatus.isProcessing && ( {teamStatus.isProcessing && (