mirror of
https://github.com/iflytek/skillhub.git
synced 2026-09-14 23:21:08 +00:00
fix(namespace): preserve review menu visibility
Signed-off-by: dongmucat <1127093059@qq.com>
This commit is contained in:
parent
35e9ca588a
commit
669d341d51
6 changed files with 86 additions and 9 deletions
|
|
@ -76,7 +76,7 @@ vi.mock('@/features/auth/use-auth', () => ({
|
|||
|
||||
const useMyNamespacesMock = vi.fn()
|
||||
vi.mock('@/shared/hooks/use-namespace-queries', () => ({
|
||||
useMyNamespaces: () => useMyNamespacesMock(),
|
||||
useMyNamespaces: (enabled?: boolean) => useMyNamespacesMock(enabled),
|
||||
}))
|
||||
|
||||
vi.mock('@/shared/components/dashboard-page-header', () => ({
|
||||
|
|
@ -194,4 +194,13 @@ describe('ReviewsPage', () => {
|
|||
expect(useReviewListMock).toHaveBeenCalled()
|
||||
expect(useReviewListMock.mock.calls.every((call) => call[5] === false)).toBe(true)
|
||||
})
|
||||
|
||||
it('skips namespace loading for super admins with global review access', () => {
|
||||
hasRoleMock.mockImplementation((role: string) => role === 'SKILL_ADMIN' || role === 'USER_ADMIN' || role === 'SUPER_ADMIN')
|
||||
userMock.platformRoles = ['SUPER_ADMIN']
|
||||
|
||||
renderToStaticMarkup(createElement(ReviewsPage))
|
||||
|
||||
expect(useMyNamespacesMock).toHaveBeenCalledWith(false)
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -40,7 +40,6 @@ export function ReviewsPage() {
|
|||
const navigate = useNavigate()
|
||||
const search = useSearch({ from: '/dashboard/reviews' })
|
||||
const { hasRole, user } = useAuth()
|
||||
const { data: myNamespaces, isLoading: isLoadingNamespaces } = useMyNamespaces()
|
||||
const [pages, setPages] = useState<Record<ReviewStatus, number>>({
|
||||
PENDING: 0,
|
||||
APPROVED: 0,
|
||||
|
|
@ -52,6 +51,7 @@ export function ReviewsPage() {
|
|||
const isSkillAdmin = hasRole('SKILL_ADMIN') || hasRole('SUPER_ADMIN')
|
||||
const isUserAdmin = hasRole('USER_ADMIN') || hasRole('SUPER_ADMIN')
|
||||
const hasGlobalReviewAccess = canAccessGlobalReviewCenter(user?.platformRoles)
|
||||
const { data: myNamespaces, isLoading: isLoadingNamespaces } = useMyNamespaces(!hasGlobalReviewAccess)
|
||||
const namespaceReviewEntry = getPreferredNamespaceReviewEntry(myNamespaces)
|
||||
const showTypeTabs = isSkillAdmin && isUserAdmin
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
import type { ReactNode } from 'react'
|
||||
import type { ManagedNamespace } from '@/api/types'
|
||||
import { renderToStaticMarkup } from 'react-dom/server'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import * as mod from './user-menu'
|
||||
import { UserMenu } from './user-menu'
|
||||
|
||||
const useMyNamespacesMock = vi.hoisted(() => vi.fn(() => ({ data: [] })))
|
||||
const useMyNamespacesMock = vi.hoisted(() => vi.fn(() => ({ data: [] as ManagedNamespace[] })))
|
||||
|
||||
vi.mock('react', async () => {
|
||||
const actual = await vi.importActual<typeof import('react')>('react')
|
||||
|
|
@ -112,7 +113,41 @@ describe('UserMenu security settings visibility', () => {
|
|||
expect(html).not.toContain('user.menu.security')
|
||||
})
|
||||
|
||||
it('does not fetch namespace memberships while rendering the global menu', () => {
|
||||
it('shows reviews for namespace admins without platform review roles', () => {
|
||||
useMyNamespacesMock.mockReturnValue({
|
||||
data: [
|
||||
{
|
||||
id: 10,
|
||||
slug: 'team-admin',
|
||||
displayName: 'Team Admin',
|
||||
type: 'TEAM',
|
||||
status: 'ACTIVE',
|
||||
immutable: false,
|
||||
canFreeze: false,
|
||||
canUnfreeze: false,
|
||||
canArchive: false,
|
||||
canRestore: false,
|
||||
canDelete: false,
|
||||
currentUserRole: 'ADMIN',
|
||||
createdAt: '',
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
const html = renderToStaticMarkup(
|
||||
<UserMenu
|
||||
user={{
|
||||
displayName: 'Namespace Admin',
|
||||
platformRoles: ['USER'],
|
||||
}}
|
||||
/>,
|
||||
)
|
||||
|
||||
expect(useMyNamespacesMock).toHaveBeenCalledWith(true)
|
||||
expect(html).toContain('user.menu.reviews')
|
||||
})
|
||||
|
||||
it('disables namespace membership loading while rendering the global menu for platform reviewers', () => {
|
||||
renderToStaticMarkup(
|
||||
<UserMenu
|
||||
user={{
|
||||
|
|
@ -122,6 +157,6 @@ describe('UserMenu security settings visibility', () => {
|
|||
/>,
|
||||
)
|
||||
|
||||
expect(useMyNamespacesMock).not.toHaveBeenCalled()
|
||||
expect(useMyNamespacesMock).toHaveBeenCalledWith(false)
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -3,7 +3,8 @@ import { useTranslation } from 'react-i18next'
|
|||
import { Link } from '@tanstack/react-router'
|
||||
import { useQueryClient } from '@tanstack/react-query'
|
||||
import { authApi } from '@/api/client'
|
||||
import { buildGlobalReviewsPath, canAccessGlobalReviewCenter } from '@/features/review/review-paths'
|
||||
import { useMyNamespaces } from '@/shared/hooks/use-namespace-queries'
|
||||
import { buildGlobalReviewsPath, canAccessGlobalReviewCenter, canAccessReviewCenter } from '@/features/review/review-paths'
|
||||
import { clearSessionScopedQueries } from '@/features/notification/notification-session'
|
||||
import { canViewGovernanceCenter } from '@/shared/lib/governance-access'
|
||||
import { cn } from '@/shared/lib/utils'
|
||||
|
|
@ -35,7 +36,9 @@ export function UserMenu({ user, triggerClassName }: UserMenuProps) {
|
|||
const isUserAdmin = hasRole('USER_ADMIN') || hasRole('SUPER_ADMIN')
|
||||
const isAuditor = hasRole('AUDITOR') || hasRole('SUPER_ADMIN')
|
||||
const isSuperAdmin = hasRole('SUPER_ADMIN')
|
||||
const reviewCenterVisible = canAccessGlobalReviewCenter(user.platformRoles)
|
||||
const hasGlobalReviewAccess = canAccessGlobalReviewCenter(user.platformRoles)
|
||||
const { data: myNamespaces } = useMyNamespaces(!hasGlobalReviewAccess)
|
||||
const reviewCenterVisible = canAccessReviewCenter(user.platformRoles, myNamespaces)
|
||||
const canChangePassword = user.canChangePassword === true
|
||||
const open = isHovered || isClickOpen
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,18 @@
|
|||
import { describe, expect, it } from 'vitest'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
|
||||
const useQueryMock = vi.hoisted(() => vi.fn())
|
||||
|
||||
vi.mock('@tanstack/react-query', () => ({
|
||||
useQuery: useQueryMock,
|
||||
useMutation: vi.fn(),
|
||||
useQueryClient: vi.fn(),
|
||||
}))
|
||||
|
||||
vi.mock('@/api/client', () => ({
|
||||
namespaceApi: {
|
||||
listMine: vi.fn(),
|
||||
},
|
||||
}))
|
||||
|
||||
/**
|
||||
* use-namespace-queries.ts exports React hooks that wrap @tanstack/react-query
|
||||
|
|
@ -10,6 +24,10 @@ import { describe, expect, it } from 'vitest'
|
|||
* Here we verify that all expected hooks are exported.
|
||||
*/
|
||||
describe('use-namespace-queries exports', () => {
|
||||
beforeEach(() => {
|
||||
useQueryMock.mockClear()
|
||||
})
|
||||
|
||||
it('exports all expected hook functions', async () => {
|
||||
const mod = await import('./use-namespace-queries')
|
||||
expect(typeof mod.useMyNamespaces).toBe('function')
|
||||
|
|
@ -25,4 +43,15 @@ describe('use-namespace-queries exports', () => {
|
|||
expect(typeof mod.useArchiveNamespace).toBe('function')
|
||||
expect(typeof mod.useRestoreNamespace).toBe('function')
|
||||
})
|
||||
|
||||
it('passes the enabled flag to the my namespaces query', async () => {
|
||||
const mod = await import('./use-namespace-queries')
|
||||
|
||||
mod.useMyNamespaces(false)
|
||||
|
||||
expect(useQueryMock).toHaveBeenCalledWith(expect.objectContaining({
|
||||
queryKey: ['namespaces', 'my'],
|
||||
enabled: false,
|
||||
}))
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -51,10 +51,11 @@ function invalidateNamespaceQueries(queryClient: ReturnType<typeof useQueryClien
|
|||
queryClient.invalidateQueries({ queryKey: ['reviews'] })
|
||||
}
|
||||
|
||||
export function useMyNamespaces() {
|
||||
export function useMyNamespaces(enabled = true) {
|
||||
return useQuery({
|
||||
queryKey: ['namespaces', 'my'],
|
||||
queryFn: getMyNamespaces,
|
||||
enabled,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue