Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added .tmp/proof/issue-123-landing.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added .tmp/proof/issue-123-showcase.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified packages/app/public/portal-showcase.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 6 additions & 0 deletions packages/app/src/components/landing/LandingPage.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@ describe('LandingPage', () => {
expect(
screen.getByText(/Try it as a guest, no account needed/),
).toBeInTheDocument();
expect(
screen.getByText(/search across your catalog and docs/),
).toBeInTheDocument();
expect(
screen.queryByText(/an answer engine grounded in your own docs/),
).not.toBeInTheDocument();
});

it('links the primary call to action into the showcase', async () => {
Expand Down
2 changes: 1 addition & 1 deletion packages/app/src/components/landing/LandingPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ export const LandingPage = () => {
sx={{ fontWeight: 400, maxWidth: 640 }}
>
Software templates that publish to GitHub, a catalog that keeps
services findable, and an answer engine grounded in your own docs.
services findable, and search across your catalog and docs.
Try it as a guest, no account needed.
</Typography>
<Box sx={{ display: 'flex', gap: 2, flexWrap: 'wrap' }}>
Expand Down
5 changes: 5 additions & 0 deletions packages/app/src/components/showcase/ShowcaseCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,11 @@ export const ShowcaseCard = ({ item }: { item: ShowcaseItem }) => {
fontWeight: 500,
}}
/>
{item.availability && (
<Typography variant="body2" sx={{ mb: 1.5, fontWeight: 600 }}>
{item.availability}
</Typography>
)}
<Typography
variant="body2"
color="text.secondary"
Expand Down
34 changes: 33 additions & 1 deletion packages/app/src/components/showcase/ShowcasePage.test.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,41 @@
import { screen, fireEvent } from '@testing-library/react';
import { screen, fireEvent, within } from '@testing-library/react';
import { renderInTestApp } from '@backstage/test-utils';
import { ShowcasePage } from './ShowcasePage';
import { showcaseItems, countByCategory } from './showcaseConfig';

describe('ShowcasePage', () => {
it('distinguishes live keyword search from the answer-engine extension', async () => {
await renderInTestApp(<ShowcasePage />);

fireEvent.click(screen.getByText(/^Answer Engine \(/));

expect(screen.getByRole('alert')).toHaveTextContent(
'The demo does not generate answers.',
);
const search = within(
screen.getByTestId('showcase-card-answer-engine-search'),
);
expect(search.getByText('Built-in search')).toBeInTheDocument();
expect(search.getByText('Catalog and Docs Search')).toBeInTheDocument();
expect(
search.getByRole('link', { name: 'Search catalog and docs' }),
).toHaveAttribute('href', '/search');

const extension = within(
screen.getByTestId('showcase-card-answer-engine-worker-card'),
);
expect(extension.getByText('Extension template')).toBeInTheDocument();
expect(
extension.getByText(/your own document index and AI Hub/),
).toBeInTheDocument();
expect(extension.getByRole('link', { name: 'Use template' })).toHaveAttribute(
'href',
'/self-service/templates/default/answer-engine-worker',
);
expect(screen.queryByText('Answer Engine Search')).not.toBeInTheDocument();
expect(screen.getByText('2 items available')).toBeInTheDocument();
});

it('renders every item with the total count and category chips', async () => {
await renderInTestApp(<ShowcasePage />);
const counts = countByCategory(showcaseItems);
Expand Down
14 changes: 11 additions & 3 deletions packages/app/src/components/showcase/ShowcasePage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import TextField from '@mui/material/TextField';
import InputAdornment from '@mui/material/InputAdornment';
import Chip from '@mui/material/Chip';
import Grid from '@mui/material/Grid';
import Alert from '@mui/material/Alert';
import { Page, Header, Content } from '@backstage/core-components';
import SearchIcon from '@mui/icons-material/Search';
import {
Expand Down Expand Up @@ -39,7 +40,7 @@ export const ShowcasePage = () => {
<Page themeId="tool">
<Header
title="Plugin Showcase"
subtitle="Templates, GitHub integration and the answer engine, curated from what this portal already ships"
subtitle="Templates, GitHub integration and search, with an answer-engine extension to build on"
/>
<Content>
<Box sx={{ mb: 4 }}>
Expand All @@ -48,11 +49,18 @@ export const ShowcasePage = () => {
</Typography>
<Typography variant="body2" color="text.secondary">
Start a new service from a proven template, publish it to GitHub,
and make it findable through the catalog and answer engine. Pick a
card to jump straight to the live surface.
and make it findable through the catalog and docs search. Pick a
card to explore a portal feature or preview a software template.
</Typography>
</Box>

<Alert severity="info" sx={{ mb: 3 }}>
Catalog and TechDocs keyword search runs in this portal. Generated
answers are an extension you can build with the Answer Engine Worker
template, your own document index and AI Hub. The demo does not generate
answers.
</Alert>

<Box
sx={{
display: 'flex',
Expand Down
13 changes: 8 additions & 5 deletions packages/app/src/components/showcase/showcaseConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export interface ShowcaseItem {
linkLabel: string;
tags: string[];
isRecommended?: boolean;
availability?: 'Built-in search' | 'Extension template';
}

export const showcaseCategoryLabels: Record<ShowcaseCategory, string> = {
Expand Down Expand Up @@ -143,25 +144,27 @@ export const showcaseItems: ShowcaseItem[] = [
},
{
id: 'answer-engine-search',
name: 'Answer Engine Search',
name: 'Catalog and Docs Search',
description:
'Ask questions across the catalog and docs and get cited answers grounded in your own content.',
'Find services and documentation with keyword search across the catalog and TechDocs.',
category: 'answer-engine',
link: '/search',
linkLabel: 'Try search',
tags: ['ai', 'search', 'rag'],
linkLabel: 'Search catalog and docs',
tags: ['catalog', 'search', 'techdocs'],
isRecommended: true,
availability: 'Built-in search',
},
{
id: 'answer-engine-worker-card',
name: 'Answer Engine Worker Template',
description:
'Start your own answer engine worker with retrieval, citation handling and catalog registration built in.',
'Scaffold an answer engine worker to connect to your own document index and AI Hub for cited answers.',
category: 'answer-engine',
link: templateShowcaseLink('answer-engine-worker'),
linkLabel: 'Use template',
tags: ['ai', 'rag', 'template'],
isRecommended: true,
availability: 'Extension template',
},
{
id: 'platform-techdocs',
Expand Down
Loading