diff --git a/packages/app/src/components/showcase/showcaseConfig.test.ts b/packages/app/src/components/showcase/showcaseConfig.test.ts index d35d96e..f2ff494 100644 --- a/packages/app/src/components/showcase/showcaseConfig.test.ts +++ b/packages/app/src/components/showcase/showcaseConfig.test.ts @@ -2,6 +2,7 @@ import { showcaseItems, filterShowcaseItems, countByCategory, + templateShowcaseLink, } from './showcaseConfig'; describe('showcaseConfig', () => { @@ -31,12 +32,40 @@ describe('showcaseConfig', () => { it('every item links to a live portal surface', () => { const allowed = ['/self-service', '/catalog', '/api-docs', '/search', '/docs', '/catalog-graph']; showcaseItems.forEach(item => { - expect(allowed).toContain(item.link); + const isTemplateLink = item.link.startsWith('/self-service/templates/default/'); + expect(allowed.includes(item.link) || isTemplateLink).toBe(true); expect(item.linkLabel.length).toBeGreaterThan(0); expect(item.description.length).toBeGreaterThan(20); }); }); + it('deep-links every template card to its real template entity', () => { + // Entity names from examples/templates/*/template.yaml (metadata.name) + const realTemplateNames = [ + 'ai-hub-service', + 'answer-engine-worker', + 'mcp-server', + 'github-blank-repo', + 'github-pull-request-docs', + 'docs-blank-repo', + 'docs-template-gitlab-merge-request', + ]; + const templates = showcaseItems.filter(i => i.category === 'templates'); + templates.forEach(item => { + expect(item.link.startsWith('/self-service/templates/default/')).toBe(true); + const templateName = item.link.replace('/self-service/templates/default/', ''); + expect(realTemplateNames).toContain(templateName); + }); + expect(templates.map(t => t.link).sort()).toEqual( + realTemplateNames.map(name => templateShowcaseLink(name)).sort(), + ); + const workerCard = showcaseItems.find(i => i.id === 'answer-engine-worker-card'); + expect(workerCard?.link).toBe(templateShowcaseLink('answer-engine-worker')); + expect(templateShowcaseLink('ai-hub-service')).toBe( + '/self-service/templates/default/ai-hub-service', + ); + }); + it('filters by category', () => { const github = filterShowcaseItems(showcaseItems, 'github', ''); expect(github.every(i => i.category === 'github')).toBe(true); diff --git a/packages/app/src/components/showcase/showcaseConfig.ts b/packages/app/src/components/showcase/showcaseConfig.ts index a5c4e69..88a7116 100644 --- a/packages/app/src/components/showcase/showcaseConfig.ts +++ b/packages/app/src/components/showcase/showcaseConfig.ts @@ -29,6 +29,10 @@ export const showcaseCategoryColors: Record = { platform: '#1a7f37', }; +export function templateShowcaseLink(templateName: string): string { + return `/self-service/templates/default/${templateName}`; +} + export const showcaseItems: ShowcaseItem[] = [ { id: 'template-ai-hub-service', @@ -36,7 +40,7 @@ export const showcaseItems: ShowcaseItem[] = [ description: 'Scaffold a provider-agnostic gateway in front of your organisation LLM providers, with auth, rate limiting, cost tracking and audit logging.', category: 'templates', - link: '/self-service', + link: templateShowcaseLink('ai-hub-service'), linkLabel: 'Use template', tags: ['recommended', 'ai', 'llm', 'github'], isRecommended: true, @@ -47,7 +51,7 @@ export const showcaseItems: ShowcaseItem[] = [ description: 'Scaffold a queue consumer that retrieves context from a document index and produces cited answers, with an indexer and query API.', category: 'templates', - link: '/self-service', + link: templateShowcaseLink('answer-engine-worker'), linkLabel: 'Use template', tags: ['recommended', 'ai', 'rag', 'github'], isRecommended: true, @@ -58,7 +62,7 @@ export const showcaseItems: ShowcaseItem[] = [ description: 'Scaffold a Model Context Protocol server that AI assistants connect to for domain-specific tools and context.', category: 'templates', - link: '/self-service', + link: templateShowcaseLink('mcp-server'), linkLabel: 'Use template', tags: ['recommended', 'ai', 'mcp', 'github'], isRecommended: true, @@ -69,7 +73,7 @@ export const showcaseItems: ShowcaseItem[] = [ description: 'Create a new blank repository in GitHub from a local skeleton and register it in the catalog.', category: 'templates', - link: '/self-service', + link: templateShowcaseLink('github-blank-repo'), linkLabel: 'Use template', tags: ['recommended', 'github', 'repo'], isRecommended: true, @@ -80,7 +84,7 @@ export const showcaseItems: ShowcaseItem[] = [ description: 'Create a documentation site in a GitHub repository and open it as a pull request for review.', category: 'templates', - link: '/self-service', + link: templateShowcaseLink('github-pull-request-docs'), linkLabel: 'Use template', tags: ['recommended', 'github', 'techdocs'], isRecommended: true, @@ -91,7 +95,7 @@ export const showcaseItems: ShowcaseItem[] = [ description: 'Create a new blank repository in GitLab from a local skeleton and register it in the catalog.', category: 'templates', - link: '/self-service', + link: templateShowcaseLink('docs-blank-repo'), linkLabel: 'Use template', tags: ['recommended', 'gitlab', 'repo'], isRecommended: true, @@ -102,7 +106,7 @@ export const showcaseItems: ShowcaseItem[] = [ description: 'Create a documentation site in a GitLab repository and open it as a merge request for review.', category: 'templates', - link: '/self-service', + link: templateShowcaseLink('docs-template-gitlab-merge-request'), linkLabel: 'Use template', tags: ['recommended', 'gitlab', 'techdocs'], isRecommended: true, @@ -154,7 +158,7 @@ export const showcaseItems: ShowcaseItem[] = [ description: 'Start your own answer engine worker with retrieval, citation handling and catalog registration built in.', category: 'answer-engine', - link: '/self-service', + link: templateShowcaseLink('answer-engine-worker'), linkLabel: 'Use template', tags: ['ai', 'rag', 'template'], isRecommended: true,