From 798872f09ac2062d75255da1af1393a2b49da699 Mon Sep 17 00:00:00 2001 From: wowo-zZ Date: Sat, 14 Mar 2026 12:01:21 +0800 Subject: [PATCH] fix(web): improve anonymous user experience on skill detail page - Add proper error handling for skill detail API errors - Show friendly login prompt when anonymous users access private skills - Show access denied message when authenticated users lack permission - Add i18n translations for new error messages (en/zh) This allows anonymous users to view PUBLIC skills while providing clear guidance when they encounter private or restricted content. --- web/src/i18n/locales/en.json | 4 ++++ web/src/i18n/locales/zh.json | 4 ++++ web/src/pages/skill-detail.tsx | 23 ++++++++++++++++++++++- 3 files changed, 30 insertions(+), 1 deletion(-) diff --git a/web/src/i18n/locales/en.json b/web/src/i18n/locales/en.json index 892b8648..c788fbb8 100644 --- a/web/src/i18n/locales/en.json +++ b/web/src/i18n/locales/en.json @@ -323,6 +323,10 @@ "skillDetail": { "notFound": "Skill not found", "notFoundDesc": "This skill may have been deleted or never existed", + "loginRequired": "Login Required", + "loginRequiredDesc": "This skill is private. Please login to view details.", + "accessDenied": "Access Denied", + "accessDeniedDesc": "You don't have permission to view this skill", "tabReadme": "README", "tabFiles": "Files", "tabVersions": "Versions", diff --git a/web/src/i18n/locales/zh.json b/web/src/i18n/locales/zh.json index cbca5da5..5a2b47cb 100644 --- a/web/src/i18n/locales/zh.json +++ b/web/src/i18n/locales/zh.json @@ -323,6 +323,10 @@ "skillDetail": { "notFound": "技能不存在", "notFoundDesc": "该技能可能已被删除或从未存在", + "loginRequired": "需要登录", + "loginRequiredDesc": "该技能为私有技能,请登录后查看详情", + "accessDenied": "访问被拒绝", + "accessDeniedDesc": "您没有权限查看该技能", "tabReadme": "README", "tabFiles": "文件", "tabVersions": "版本", diff --git a/web/src/pages/skill-detail.tsx b/web/src/pages/skill-detail.tsx index ec2a7523..7e3df7d5 100644 --- a/web/src/pages/skill-detail.tsx +++ b/web/src/pages/skill-detail.tsx @@ -27,7 +27,7 @@ export function SkillDetailPage() { const { namespace, slug } = useParams({ from: '/space/$namespace/$slug' }) const { user, hasRole } = useAuth() - const { data: skill, isLoading: isLoadingSkill } = useSkillDetail(namespace, slug) + const { data: skill, isLoading: isLoadingSkill, error: skillError } = useSkillDetail(namespace, slug) const { data: versions } = useSkillVersions(namespace, slug) const latestVersion = versions?.[0] const { data: files } = useSkillFiles(namespace, slug, latestVersion?.version) @@ -83,6 +83,27 @@ export function SkillDetailPage() { ) } + if (skillError) { + const isForbidden = skillError instanceof Error && skillError.message.includes('403') + + if (isForbidden && !user) { + return ( +
+

{t('skillDetail.loginRequired')}

+

{t('skillDetail.loginRequiredDesc')}

+ +
+ ) + } + + return ( +
+

{t('skillDetail.accessDenied')}

+

{t('skillDetail.accessDeniedDesc')}

+
+ ) + } + if (!skill) { return (