Merge pull request #5708 from yan9651688/fix/issue-5524-model-plaza-home

fix(frontend): show model plaza entry on /home
This commit is contained in:
Wesley Liddick
2026-08-21 21:53:17 +08:00
committed by GitHub
2 changed files with 90 additions and 0 deletions
+28
View File
@@ -40,6 +40,15 @@
>
<Icon name="book" size="md" />
</a>
<router-link
v-if="showModelPlazaEntry"
to="/model-plaza"
class="flex h-10 shrink-0 items-center gap-1.5 rounded-lg px-2.5 text-sm font-medium text-gray-500 hover:bg-gray-100 hover:text-gray-700 dark:text-dark-400 dark:hover:bg-dark-800 dark:hover:text-white"
:title="t('nav.modelPlaza')"
>
<Icon name="grid" size="md" />
<span class="hidden sm:inline">{{ t('nav.modelPlaza') }}</span>
</router-link>
<button
class="flex h-10 w-10 shrink-0 items-center justify-center rounded-lg text-gray-500 hover:bg-gray-100 dark:text-dark-400 dark:hover:bg-dark-800"
:title="isDark ? t('home.switchToLight') : t('home.switchToDark')"
@@ -132,6 +141,17 @@
<Icon name="book" size="md" />
</a>
<!-- Model Plaza Link -->
<router-link
v-if="showModelPlazaEntry"
to="/model-plaza"
class="inline-flex items-center gap-1.5 rounded-lg p-2 text-sm text-gray-500 transition-colors hover:bg-gray-100 hover:text-gray-700 dark:text-dark-400 dark:hover:bg-dark-800 dark:hover:text-white"
:title="t('nav.modelPlaza')"
>
<Icon name="grid" size="md" />
<span class="hidden sm:inline">{{ t('nav.modelPlaza') }}</span>
</router-link>
<!-- Theme Toggle -->
<button
@click="toggleTheme"
@@ -480,6 +500,7 @@ import { useAuthStore, useAppStore } from '@/stores'
import LocaleSwitcher from '@/components/common/LocaleSwitcher.vue'
import Icon from '@/components/icons/Icon.vue'
import { sanitizeUrl } from '@/utils/url'
import { FeatureFlags, isFeatureFlagEnabled } from '@/utils/featureFlags'
const { t } = useI18n()
@@ -494,6 +515,7 @@ const docUrl = computed(() => sanitizeUrl(appStore.cachedPublicSettings?.doc_url
const homeContent = computed(() => appStore.cachedPublicSettings?.home_content || '')
const hasHomeContent = computed(() => homeContent.value.trim().length > 0)
const compactHomeEnabled = computed(() => appStore.cachedPublicSettings?.compact_home_enabled === true)
const modelPlazaEnabled = computed(() => isFeatureFlagEnabled(FeatureFlags.modelPlaza))
// Check if homeContent is a URL (for iframe display)
const isHomeContentUrl = computed(() => {
@@ -509,6 +531,12 @@ const githubUrl = 'https://github.com/Wei-Shaw/sub2api'
// Auth state
const isAuthenticated = computed(() => authStore.isAuthenticated)
const modelPlazaRequiresAuth = computed(
() => appStore.cachedPublicSettings?.model_plaza_require_auth === true,
)
const showModelPlazaEntry = computed(
() => modelPlazaEnabled.value && (isAuthenticated.value || !modelPlazaRequiresAuth.value),
)
const isAdmin = computed(() => authStore.isAdmin)
const dashboardPath = computed(() => isAdmin.value ? '/admin/dashboard' : '/dashboard')
const userInitial = computed(() => {
@@ -25,6 +25,10 @@ vi.mock('@/stores', () => ({
useAuthStore: () => authStore,
}))
vi.mock('@/stores/app', () => ({
useAppStore: () => appStore,
}))
vi.mock('vue-i18n', async (importOriginal) => {
const actual = await importOriginal<typeof import('vue-i18n')>()
return {
@@ -55,6 +59,13 @@ function compactDestination(wrapper: ReturnType<typeof mountHome>) {
return wrapper.get('[data-testid="compact-home"]').findComponent(RouterLinkStub).props('to')
}
function modelPlazaDestination(wrapper: ReturnType<typeof mountHome>) {
return wrapper
.findAllComponents(RouterLinkStub)
.find((link) => link.props('to') === '/model-plaza')
?.props('to')
}
describe('HomeView compact mode', () => {
beforeEach(() => {
authStore.isAuthenticated = false
@@ -119,4 +130,55 @@ describe('HomeView compact mode', () => {
expect(authStore.checkAuth).toHaveBeenCalledOnce()
expect(appStore.fetchPublicSettings).not.toHaveBeenCalled()
})
it('shows the model plaza link to anonymous visitors when public access is enabled', () => {
const wrapper = mountHome({
compact_home_enabled: true,
model_plaza_enabled: true,
model_plaza_require_auth: false,
})
expect(modelPlazaDestination(wrapper)).toBe('/model-plaza')
})
it('hides the model plaza link from anonymous visitors when sign-in is required', () => {
const wrapper = mountHome({
compact_home_enabled: true,
model_plaza_enabled: true,
model_plaza_require_auth: true,
})
expect(modelPlazaDestination(wrapper)).toBeUndefined()
})
it('shows the model plaza link to authenticated visitors when sign-in is required', () => {
authStore.isAuthenticated = true
const wrapper = mountHome({
compact_home_enabled: true,
model_plaza_enabled: true,
model_plaza_require_auth: true,
})
expect(modelPlazaDestination(wrapper)).toBe('/model-plaza')
})
it('shows the model plaza link in the default home header', () => {
const wrapper = mountHome({
model_plaza_enabled: true,
model_plaza_require_auth: false,
})
expect(modelPlazaDestination(wrapper)).toBe('/model-plaza')
})
it('hides the model plaza link when the feature is disabled', () => {
const wrapper = mountHome({
compact_home_enabled: true,
model_plaza_enabled: false,
model_plaza_require_auth: false,
})
expect(modelPlazaDestination(wrapper)).toBeUndefined()
})
})