fix(public): keep original GitHub links visible

(cherry picked from commit 7c93552697c9c35b77df35e117900ff8e9b62994)
This commit is contained in:
fawney19
2026-05-16 09:17:37 +08:00
parent 1a50c5e112
commit 74abb50bdc
14 changed files with 25 additions and 77 deletions

View File

@@ -14,21 +14,19 @@ describe('useSiteInfo', () => {
apiClientMocks.get.mockReset()
})
it('loads github link display setting from public site info', async () => {
it('loads public site info', async () => {
apiClientMocks.get.mockResolvedValue({
data: {
site_name: 'Custom Aether',
site_subtitle: 'Gateway',
show_github_link: false,
},
})
const { useSiteInfo } = await import('../useSiteInfo')
const { siteName, siteSubtitle, showGithubLink, refreshSiteInfo } = useSiteInfo()
const { siteName, siteSubtitle, refreshSiteInfo } = useSiteInfo()
await refreshSiteInfo()
expect(siteName.value).toBe('Custom Aether')
expect(siteSubtitle.value).toBe('Gateway')
expect(showGithubLink.value).toBe(false)
})
})

View File

@@ -4,13 +4,11 @@ import apiClient from '@/api/client'
interface SiteInfo {
site_name: string
site_subtitle: string
show_github_link?: boolean
}
// 模块级缓存,所有组件共享同一份数据
const siteName = ref('Aether')
const siteSubtitle = ref('AI Gateway')
const showGithubLink = ref(true)
const loaded = ref(false)
let fetchPromise: Promise<void> | null = null
@@ -19,7 +17,6 @@ async function fetchSiteInfo() {
const response = await apiClient.get<SiteInfo>('/api/public/site-info')
siteName.value = response.data.site_name
siteSubtitle.value = response.data.site_subtitle
showGithubLink.value = response.data.show_github_link !== false
loaded.value = true
} catch {
// 加载失败时保持默认值,允许后续重试
@@ -38,7 +35,7 @@ export function useSiteInfo() {
if (!loaded.value && !fetchPromise) {
fetchPromise = fetchSiteInfo()
}
return { siteName, siteSubtitle, showGithubLink, refreshSiteInfo }
return { siteName, siteSubtitle, refreshSiteInfo }
}
// 站点名称变化时同步更新 document.title

View File

@@ -325,7 +325,6 @@
</button>
<!-- GitHub Link -->
<a
v-if="showGithubLink"
href="https://github.com/fawney19/Aether"
target="_blank"
rel="noopener noreferrer"
@@ -413,7 +412,7 @@ const route = useRoute()
const authStore = useAuthStore()
const moduleStore = useModuleStore()
const { themeMode, toggleDarkMode } = useDarkMode()
const { siteName, siteSubtitle, showGithubLink } = useSiteInfo()
const { siteName, siteSubtitle } = useSiteInfo()
const isDemo = computed(() => isDemoMode())
const isAdmin = computed(() => authStore.user?.role === 'admin')

View File

@@ -14,13 +14,11 @@
id="section-site-info"
:site-name="systemConfig.site_name"
:site-subtitle="systemConfig.site_subtitle"
:show-github-link="systemConfig.show_github_link"
:loading="siteInfoLoading"
:has-changes="hasSiteInfoChanges"
@save="saveSiteInfo"
@update:site-name="systemConfig.site_name = $event"
@update:site-subtitle="systemConfig.site_subtitle = $event"
@update:show-github-link="systemConfig.show_github_link = $event"
/>
<!-- 配置导出/导入 -->

View File

@@ -51,21 +51,6 @@
显示在导航栏品牌名称下方
</p>
</div>
<div class="md:col-span-2 flex items-center justify-between gap-4 rounded-lg border border-border/60 bg-muted/20 p-4">
<div>
<Label class="block text-sm font-medium">
GitHub 仓库入口
</Label>
<p class="mt-1 text-xs text-muted-foreground">
控制首页指南页和控制台顶部的 GitHub 链接是否展示
</p>
</div>
<Switch
:model-value="showGithubLink"
:disabled="loading"
@update:model-value="$emit('update:showGithubLink', $event)"
/>
</div>
</div>
</CardSection>
</template>
@@ -74,13 +59,11 @@
import Button from '@/components/ui/button.vue'
import Input from '@/components/ui/input.vue'
import Label from '@/components/ui/label.vue'
import Switch from '@/components/ui/switch.vue'
import { CardSection } from '@/components/layout'
defineProps<{
siteName: string
siteSubtitle: string
showGithubLink: boolean
loading: boolean
hasChanges: boolean
}>()
@@ -89,6 +72,5 @@ defineEmits<{
save: []
'update:siteName': [value: string]
'update:siteSubtitle': [value: string]
'update:showGithubLink': [value: boolean]
}>()
</script>

View File

@@ -35,23 +35,21 @@ vi.mock('@/components/ui/button.vue', () => ({
const mountedApps: Array<{ app: App, root: HTMLElement }> = []
function mountSection(onUpdateShowGithubLink = vi.fn()) {
function mountSection() {
const root = document.createElement('div')
document.body.appendChild(root)
const app = createApp(SiteInfoSection, {
siteName: 'Aether',
siteSubtitle: 'AI Gateway',
showGithubLink: false,
loading: false,
hasChanges: true,
onSave: vi.fn(),
'onUpdate:siteName': vi.fn(),
'onUpdate:siteSubtitle': vi.fn(),
'onUpdate:showGithubLink': onUpdateShowGithubLink,
})
app.mount(root)
mountedApps.push({ app, root })
return { root, onUpdateShowGithubLink }
return { root }
}
afterEach(() => {
@@ -63,15 +61,11 @@ afterEach(() => {
})
describe('SiteInfoSection', () => {
it('renders and emits the github link display switch', async () => {
const { root, onUpdateShowGithubLink } = mountSection()
it('renders site name and subtitle fields', async () => {
const { root } = mountSection()
await nextTick()
expect(root.textContent).toContain('GitHub 仓库入口')
const switchButton = root.querySelector('[role="switch"]') as HTMLButtonElement | null
expect(switchButton?.getAttribute('aria-checked')).toBe('false')
switchButton?.click()
expect(onUpdateShowGithubLink).toHaveBeenCalledWith(true)
expect(root.textContent).toContain('站点名称')
expect(root.textContent).toContain('站点副标题')
})
})

View File

@@ -8,7 +8,6 @@ export interface SystemConfig {
// 站点信息
site_name: string
site_subtitle: string
show_github_link: boolean
// 网络代理
system_proxy_node_id: string | null
// 基础配置
@@ -55,7 +54,6 @@ const CONFIG_KEYS = [
// 站点信息
'site_name',
'site_subtitle',
'show_github_link',
// 网络代理
'system_proxy_node_id',
// 基础配置
@@ -102,7 +100,6 @@ function createDefaultConfig(): SystemConfig {
// 站点信息
site_name: 'Aether',
site_subtitle: 'AI Gateway',
show_github_link: true,
// 网络代理
system_proxy_node_id: null,
// 基础配置
@@ -166,8 +163,7 @@ export function useSystemConfig() {
if (!originalConfig.value) return false
return (
systemConfig.value.site_name !== originalConfig.value.site_name ||
systemConfig.value.site_subtitle !== originalConfig.value.site_subtitle ||
systemConfig.value.show_github_link !== originalConfig.value.show_github_link
systemConfig.value.site_subtitle !== originalConfig.value.site_subtitle
)
})
@@ -311,11 +307,6 @@ export function useSystemConfig() {
value: systemConfig.value.site_subtitle,
description: '站点副标题',
},
{
key: 'show_github_link',
value: systemConfig.value.show_github_link,
description: '是否显示 GitHub 仓库入口',
},
]
await Promise.all(
configItems.map((item) =>
@@ -325,7 +316,6 @@ export function useSystemConfig() {
if (originalConfig.value) {
originalConfig.value.site_name = systemConfig.value.site_name
originalConfig.value.site_subtitle = systemConfig.value.site_subtitle
originalConfig.value.show_github_link = systemConfig.value.show_github_link
}
await refreshSiteInfo()
success('站点信息已保存')

View File

@@ -75,7 +75,6 @@
/>
</button>
<a
v-if="showGithubLink"
href="https://github.com/fawney19/Aether"
target="_blank"
rel="noopener noreferrer"
@@ -90,10 +89,7 @@
<!-- Desktop layout (>= md): Centered nav with balanced spacing -->
<div class="h-16 hidden md:flex items-center justify-between px-8">
<!-- Left spacer for balance (matches right icons width) -->
<div
class="shrink-0"
:class="showGithubLink ? 'w-[76px]' : 'w-9'"
/>
<div class="w-[76px] shrink-0" />
<!-- Center: Logo + Nav + Login Button -->
<div class="flex items-center">
@@ -190,7 +186,6 @@
/>
</button>
<a
v-if="showGithubLink"
href="https://github.com/fawney19/Aether"
target="_blank"
rel="noopener noreferrer"
@@ -500,7 +495,7 @@ import {
const authStore = useAuthStore()
const { isDark, themeMode, toggleDarkMode } = useDarkMode()
const { copyToClipboard } = useClipboard()
const { siteName, siteSubtitle, showGithubLink } = useSiteInfo()
const { siteName, siteSubtitle } = useSiteInfo()
const dashboardPath = computed(() =>
authStore.canAccessAdmin ? '/admin/dashboard' : '/dashboard'

View File

@@ -261,7 +261,6 @@
/>
</button>
<a
v-if="showGithubLink"
href="https://github.com/fawney19/Aether"
target="_blank"
rel="noopener noreferrer"
@@ -341,7 +340,7 @@ import { guideNavItems } from './guide-config'
const route = useRoute()
const { themeMode, toggleDarkMode } = useDarkMode()
const { siteName, siteSubtitle, showGithubLink } = useSiteInfo()
const { siteName, siteSubtitle } = useSiteInfo()
const mobileMenuOpen = ref(false)
const baseUrl = ref(typeof window !== 'undefined' ? window.location.origin : 'https://your-aether.com')

View File

@@ -12,12 +12,10 @@ import {
Zap,
} from 'lucide-vue-next'
import { panelClasses } from './guide-config'
import { useSiteInfo } from '@/composables/useSiteInfo'
// 部署步骤数据
const activeDeployTab = ref(0)
const copiedStep = ref<string | null>(null)
const { showGithubLink } = useSiteInfo()
const productionSteps = [
{
@@ -399,7 +397,6 @@ function copyStep(stepId: string, code: string) {
<h3>1. Aether-Proxy</h3>
<p>Rust实现, 超小资源占有, 适合性能低的VPS直接使用。</p>
<a
v-if="showGithubLink"
href="https://github.com/fawney19/Aether/tree/main/aether-proxy"
target="_blank"
rel="noopener noreferrer"

View File

@@ -790,6 +790,7 @@
<script setup lang="ts">
import { ref, onMounted, computed, onBeforeUnmount, nextTick, watch, markRaw } from 'vue'
import type { Component } from 'vue'
import { useAuthStore } from '@/stores/auth'
import { dashboardApi, type DashboardStat, type DailyStat, type ProviderSummary } from '@/api/dashboard'
import { getDateRangeFromPeriod } from '@/features/usage/composables'
@@ -838,6 +839,10 @@ import type { ChartData, ChartOptions, ChartDataset, TooltipItem } from 'chart.j
const authStore = useAuthStore()
type DashboardStatCard = Omit<DashboardStat, 'icon'> & {
icon: Component
}
const statsPanelRef = ref<HTMLElement | null>(null)
const announcementsHeight = ref<number | null>(null)
const announcementsTimelineRef = ref<HTMLElement | null>(null)
@@ -941,7 +946,7 @@ const getStatIconColor = (_index: number): string => {
}
// 统计数据
const stats = ref<DashboardStat[]>([])
const stats = ref<DashboardStatCard[]>([])
const todayStats = ref<{
requests: number
tokens: number
@@ -1006,7 +1011,7 @@ const loadingAnnouncements = ref(false)
const selectedAnnouncement = ref<Announcement | null>(null)
const detailDialogOpen = ref(false)
const iconMap: Record<string, unknown> = {
const iconMap: Record<string, Component> = {
Users, Activity, TrendingUp, DollarSign, Key, Hash, Zap, Database
}