diff --git a/web/src/app/router.tsx b/web/src/app/router.tsx index 0ec2a676..6b693318 100644 --- a/web/src/app/router.tsx +++ b/web/src/app/router.tsx @@ -96,13 +96,13 @@ const searchRoute = createRoute({ const namespaceRoute = createRoute({ getParentRoute: () => rootRoute, - path: '@$namespace', + path: '/$namespace', component: NamespacePage, }) const skillDetailRoute = createRoute({ getParentRoute: () => rootRoute, - path: '@$namespace/$slug', + path: '/$namespace/$slug', component: SkillDetailPage, }) diff --git a/web/src/pages/namespace.tsx b/web/src/pages/namespace.tsx index 62f47eaa..e78e3957 100644 --- a/web/src/pages/namespace.tsx +++ b/web/src/pages/namespace.tsx @@ -7,7 +7,7 @@ import { useNamespaceDetail, useSearchSkills } from '@/shared/hooks/use-skill-qu export function NamespacePage() { const navigate = useNavigate() - const { namespace } = useParams({ from: '/@$namespace' }) + const { namespace } = useParams({ from: '/$namespace' }) const { data: namespaceData, isLoading: isLoadingNamespace } = useNamespaceDetail(namespace) const { data: skillsData, isLoading: isLoadingSkills } = useSearchSkills({ diff --git a/web/src/pages/skill-detail.tsx b/web/src/pages/skill-detail.tsx index 1dc4b995..a574082f 100644 --- a/web/src/pages/skill-detail.tsx +++ b/web/src/pages/skill-detail.tsx @@ -22,7 +22,7 @@ export function SkillDetailPage() { const navigate = useNavigate() const location = useRouterState({ select: (s) => s.location }) const queryClient = useQueryClient() - const { namespace, slug } = useParams({ from: '/@$namespace/$slug' }) + const { namespace, slug } = useParams({ from: '/$namespace/$slug' }) const { user, hasRole } = useAuth() const { data: skill, isLoading: isLoadingSkill } = useSkillDetail(namespace, slug) diff --git a/web/src/shared/hooks/use-skill-queries.ts b/web/src/shared/hooks/use-skill-queries.ts index a5124c6b..e3b77692 100644 --- a/web/src/shared/hooks/use-skill-queries.ts +++ b/web/src/shared/hooks/use-skill-queries.ts @@ -5,7 +5,10 @@ import { fetchJson, fetchText, getCsrfHeaders, meApi } from '@/api/client' async function searchSkills(params: SearchParams): Promise> { const queryParams = new URLSearchParams() if (params.q) queryParams.append('q', params.q) - if (params.namespace) queryParams.append('namespace', params.namespace) + if (params.namespace) { + const cleanNamespace = params.namespace.startsWith('@') ? params.namespace.slice(1) : params.namespace + queryParams.append('namespace', cleanNamespace) + } if (params.sort) queryParams.append('sort', params.sort) if (params.page !== undefined) queryParams.append('page', String(params.page)) if (params.size !== undefined) queryParams.append('size', String(params.size)) @@ -14,21 +17,25 @@ async function searchSkills(params: SearchParams): Promise { - return fetchJson(`/api/v1/skills/${namespace}/${slug}`) + const cleanNamespace = namespace.startsWith('@') ? namespace.slice(1) : namespace + return fetchJson(`/api/v1/skills/${cleanNamespace}/${slug}`) } async function getSkillVersions(namespace: string, slug: string): Promise { - const page = await fetchJson>(`/api/v1/skills/${namespace}/${slug}/versions`) + const cleanNamespace = namespace.startsWith('@') ? namespace.slice(1) : namespace + const page = await fetchJson>(`/api/v1/skills/${cleanNamespace}/${slug}/versions`) return page.items } async function getSkillFiles(namespace: string, slug: string, version: string): Promise { - return fetchJson(`/api/v1/skills/${namespace}/${slug}/versions/${version}/files`) + const cleanNamespace = namespace.startsWith('@') ? namespace.slice(1) : namespace + return fetchJson(`/api/v1/skills/${cleanNamespace}/${slug}/versions/${version}/files`) } async function getSkillReadme(namespace: string, slug: string, version: string): Promise { + const cleanNamespace = namespace.startsWith('@') ? namespace.slice(1) : namespace try { - return await fetchText(`/api/v1/skills/${namespace}/${slug}/versions/${version}/file?path=SKILL.md`) + return await fetchText(`/api/v1/skills/${cleanNamespace}/${slug}/versions/${version}/file?path=SKILL.md`) } catch { return '' } @@ -48,20 +55,23 @@ async function getMyNamespaces(): Promise { } async function getNamespaceDetail(slug: string): Promise { - return fetchJson(`/api/v1/namespaces/${slug}`) + const cleanSlug = slug.startsWith('@') ? slug.slice(1) : slug + return fetchJson(`/api/v1/namespaces/${cleanSlug}`) } async function getNamespaceMembers(slug: string): Promise { - const page = await fetchJson>(`/api/v1/namespaces/${slug}/members`) + const cleanSlug = slug.startsWith('@') ? slug.slice(1) : slug + const page = await fetchJson>(`/api/v1/namespaces/${cleanSlug}/members`) return page.items } async function publishSkill(params: { namespace: string; file: File; visibility: string }): Promise { + const cleanNamespace = params.namespace.startsWith('@') ? params.namespace.slice(1) : params.namespace const formData = new FormData() formData.append('file', params.file) formData.append('visibility', params.visibility) - return fetchJson(`/api/v1/skills/${params.namespace}/publish`, { + return fetchJson(`/api/v1/skills/${cleanNamespace}/publish`, { method: 'POST', headers: getCsrfHeaders(), body: formData,