mirror of
https://github.com/iflytek/skillhub.git
synced 2026-10-09 03:17:52 +00:00
fix(web): navigate back after hiding skill detail
This commit is contained in:
parent
cbc1ef25f7
commit
2119bb221b
2 changed files with 45 additions and 4 deletions
|
|
@ -252,6 +252,20 @@ describe('SkillDetailPage', () => {
|
|||
expect(html).not.toContain('__RATING_WIDGET__')
|
||||
})
|
||||
|
||||
it('does not render access denied content for logged-in forbidden responses', () => {
|
||||
useSkillDetailMock.mockReturnValue({
|
||||
data: undefined,
|
||||
isLoading: false,
|
||||
isFetching: false,
|
||||
error: new Error('HTTP 403'),
|
||||
})
|
||||
|
||||
const html = renderToStaticMarkup(<SkillDetailPage />)
|
||||
|
||||
expect(html).toBe('')
|
||||
expect(html).not.toContain('skillDetail.accessDenied')
|
||||
})
|
||||
|
||||
it('renders rejected owner preview without pending-review copy', () => {
|
||||
useSkillDetailMock.mockReturnValue({
|
||||
data: createSkill({
|
||||
|
|
|
|||
|
|
@ -240,7 +240,17 @@ export function SkillDetailPage() {
|
|||
|
||||
const hideMutation = useMutation({
|
||||
mutationFn: () => adminApi.hideSkill(skill!.id),
|
||||
onSuccess: refreshSkill,
|
||||
onSuccess: () => {
|
||||
// After hiding, this detail route can become inaccessible for current viewer context.
|
||||
// Navigate away immediately to avoid landing on an access-denied state.
|
||||
queryClient.invalidateQueries({ queryKey: ['skills'] })
|
||||
const returnTo = normalizeSkillDetailReturnTo(search.returnTo)
|
||||
if (returnTo) {
|
||||
void navigate({ to: returnTo, replace: true })
|
||||
return
|
||||
}
|
||||
void navigate({ to: '/search', search: getSkillSquareSearch(), replace: true })
|
||||
},
|
||||
})
|
||||
|
||||
const unhideMutation = useMutation({
|
||||
|
|
@ -392,6 +402,9 @@ export function SkillDetailPage() {
|
|||
const isLastVersion = versions?.length === 1
|
||||
const canWithdrawVersion = (status?: string) => status === 'PENDING_REVIEW'
|
||||
const canRereleaseVersion = (status?: string) => status === 'PUBLISHED'
|
||||
const isForbiddenError = skillError instanceof ApiError
|
||||
? skillError.status === 403
|
||||
: skillError instanceof Error && skillError.message.includes('403')
|
||||
const isNotFoundError = skillError instanceof ApiError
|
||||
? skillError.status === 400 || skillError.status === 404 || skillError.serverMessageKey === 'skill.not_found'
|
||||
: false
|
||||
|
|
@ -403,6 +416,18 @@ export function SkillDetailPage() {
|
|||
clearDeletedSkillQueries(queryClient, namespace, slug, skill?.id)
|
||||
}, [isNotFoundError, namespace, queryClient, skill?.id, slug])
|
||||
|
||||
useEffect(() => {
|
||||
if (!isForbiddenError || !user) {
|
||||
return
|
||||
}
|
||||
const returnTo = normalizeSkillDetailReturnTo(search.returnTo)
|
||||
if (returnTo) {
|
||||
void navigate({ to: returnTo, replace: true })
|
||||
return
|
||||
}
|
||||
void navigate({ to: '/search', search: getSkillSquareSearch(), replace: true })
|
||||
}, [isForbiddenError, navigate, search.returnTo, user])
|
||||
|
||||
const metadataDiffEntries = (() => {
|
||||
const source = parseMetadataJson(diffSourceDetail?.parsedMetadataJson)
|
||||
const compare = parseMetadataJson(diffCompareDetail?.parsedMetadataJson)
|
||||
|
|
@ -610,9 +635,7 @@ export function SkillDetailPage() {
|
|||
}
|
||||
|
||||
if (skillError) {
|
||||
const isForbidden = skillError instanceof Error && skillError.message.includes('403')
|
||||
|
||||
if (isForbidden && !user) {
|
||||
if (isForbiddenError && !user) {
|
||||
return (
|
||||
<div className="text-center py-20 animate-fade-up">
|
||||
<h2 className="text-2xl font-bold font-heading mb-2">{t('skillDetail.loginRequired')}</h2>
|
||||
|
|
@ -622,6 +645,10 @@ export function SkillDetailPage() {
|
|||
)
|
||||
}
|
||||
|
||||
if (isForbiddenError) {
|
||||
return null
|
||||
}
|
||||
|
||||
if (isNotFoundError) {
|
||||
return (
|
||||
<div className="text-center py-20 animate-fade-up">
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue