Skip to content
Draft
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
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
48 changes: 40 additions & 8 deletions src/frontend/src/components/ImageShowcase.astro
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,36 @@
import { Icon } from '@astrojs/starlight/components';
import { Image } from 'astro:assets';
import { Zoom } from 'starlight-image-zoom/components';
import ThemeImage from '@components/ThemeImage.astro';

interface Props {
type BaseProps = {
title: string;
description: string;
image: ImageMetadata;
imageAlt: string;
imagePosition?: 'left' | 'right';
cta?: { label: string; href: string };
}

const { title, description, image, imageAlt, imagePosition = 'right', cta } = Astro.props;
};

type Props = BaseProps &
(
| {
image: ImageMetadata;
lightImage?: never;
darkImage?: never;
}
| {
image?: never;
lightImage: ImageMetadata;
darkImage: ImageMetadata;
}
);

const { title, description, imageAlt, imagePosition = 'right', cta } = Astro.props;
const themedImages =
'lightImage' in Astro.props && 'darkImage' in Astro.props
? { light: Astro.props.lightImage, dark: Astro.props.darkImage }
: undefined;
const singleImage = 'image' in Astro.props ? Astro.props.image : undefined;
---

<section class:list={['image-showcase not-content', { reversed: imagePosition === 'left' }]}>
Expand All @@ -33,9 +52,22 @@ const { title, description, image, imageAlt, imagePosition = 'right', cta } = As
}
</div>
<div class="showcase-image">
<Zoom label={imageAlt}>
<Image src={image} alt={imageAlt} loading="lazy" />
</Zoom>
{
themedImages ? (
<ThemeImage
light={themedImages.light}
dark={themedImages.dark}
alt={imageAlt}
label={imageAlt}
/>
) : (
singleImage && (
<Zoom label={imageAlt}>
<Image src={singleImage} alt={imageAlt} loading="lazy" />
</Zoom>
)
)
}
</div>
</section>

Expand Down
22 changes: 12 additions & 10 deletions src/frontend/src/content/docs/dashboard/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ import projectsImage from '@assets/dashboard/explore/resources-filtered-containe
import tracesImage from '@assets/dashboard/explore/trace-span-details.png';
import metricsImage from '@assets/dashboard/explore/metrics-view.png';
import structuredLogsImage from '@assets/dashboard/explore/structured-logs-errors-view.png';
import mcpDialogImage from '@assets/dashboard/mcp-server/mcp-dialog.png';
import aiAgentsDialogDark from '@assets/dashboard/ai-coding-agents/ai-agents-dialog-dark.png';
import aiAgentsDialogLight from '@assets/dashboard/ai-coding-agents/ai-agents-dialog-light.png';

<TopicHero
icon="seti:happenings"
Expand Down Expand Up @@ -107,12 +108,13 @@ Open the dashboard URL, then point your apps' OTLP exporter to `http://localhost
## AI-powered debugging

<ImageShowcase
title="MCP server for AI agents"
description="Expose your app's telemetry, resources, and logs to AI coding agents via the Model Context Protocol. Give your coding assistants full observability context for smarter debugging."
image={mcpDialogImage}
imageAlt="Aspire Dashboard MCP server configuration dialog showing connection details for AI assistants."
title="AI agents with dashboard context"
description="Give AI coding agents deep observability into resource state, health checks, logs, traces, and relationships so they can diagnose issues and verify fixes with confidence."
lightImage={aiAgentsDialogLight}
darkImage={aiAgentsDialogDark}
imageAlt="Aspire Dashboard AI agents dialog explaining telemetry data available to coding agents."
imagePosition="left"
cta={{ label: 'Configure MCP server', href: '/get-started/aspire-mcp-server/' }}
cta={{ label: 'Use AI coding agents', href: '/dashboard/ai-coding-agents/' }}
/>

## Key capabilities
Expand Down Expand Up @@ -170,11 +172,11 @@ Open the dashboard URL, then point your apps' OTLP exporter to `http://localhost
features={[
{
icon: 'puzzle',
title: 'MCP server',
title: 'AI coding agents',
description:
'Expose dashboard data to AI agents and coding assistants via the Model Context Protocol. Your AI tools get full observability context.',
href: '/get-started/aspire-mcp-server/',
label: 'Configure MCP',
'Use the Aspire CLI and MCP server to give agents dashboard data for diagnosing and verifying app changes.',
href: '/dashboard/ai-coding-agents/',
label: 'Use agents',
accent: 'purple',
},
{
Expand Down
18 changes: 18 additions & 0 deletions src/frontend/tests/typecheck/component-props.contracts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,13 @@ const validImageShowcaseProps = {
imageAlt: 'Zoomed diagram',
cta: { label: 'Read the guide', href: '/docs/' },
} satisfies PropsOf<typeof ImageShowcase>;
const validThemedImageShowcaseProps = {
title: 'Debug with agents',
description: 'Give agents dashboard context.',
lightImage: heroImage,
darkImage: heroImage,
imageAlt: 'Themed dashboard dialog',
} satisfies PropsOf<typeof ImageShowcase>;
// @ts-expect-error ImageShowcase should reject unknown props.
const invalidImageShowcaseProps: PropsOf<typeof ImageShowcase> = {
title: 'Visualize your app',
Expand All @@ -333,6 +340,15 @@ const invalidImageShowcaseProps: PropsOf<typeof ImageShowcase> = {
imageAlt: 'Zoomed diagram',
unexpected: true,
};
// @ts-expect-error ImageShowcase should not mix single-image and theme-image props.
const invalidMixedImageShowcaseProps: PropsOf<typeof ImageShowcase> = {
title: 'Visualize your app',
description: 'See resources, traces and endpoints together.',
image: heroImage,
lightImage: heroImage,
darkImage: heroImage,
imageAlt: 'Zoomed diagram',
};

const validIncludeProps = {
relativePath: 'content/docs/get-started/install-cli.mdx',
Expand Down Expand Up @@ -742,7 +758,9 @@ void [
validIconLinkCardProps,
invalidIconLinkCardProps,
validImageShowcaseProps,
validThemedImageShowcaseProps,
invalidImageShowcaseProps,
invalidMixedImageShowcaseProps,
validIncludeProps,
invalidIncludeProps,
validInstallCliModalProps,
Expand Down
22 changes: 21 additions & 1 deletion src/frontend/tests/unit/custom-components.vitest.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,24 @@ const basicRenderCases: BasicRenderCase[] = [
},
includes: ['Visualize your app', 'Zoomed diagram', 'Read the guide'],
},
{
name: 'ImageShowcase renders theme-aware images',
Component: ImageShowcase,
props: {
title: 'Debug with agents',
description: 'Give agents dashboard context.',
lightImage: heroImage,
darkImage: heroImage,
imageAlt: 'Themed dashboard dialog',
},
includes: [
'Debug with agents',
'theme-image',
'data-light=',
'data-dark=',
'Themed dashboard dialog',
],
},
{
name: 'LoopingVideo renders sources and toggle button state',
Component: LoopingVideo,
Expand Down Expand Up @@ -968,7 +986,9 @@ describe('custom Astro component render coverage', () => {
// time in the README body and the count rises to 2.
const escaped = distinctiveSummarySentence.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
const summaryMatches = html.match(new RegExp(escaped, 'g')) ?? [];
expect(summaryMatches.length, 'summary sentence should appear exactly once (hero only)').toBe(1);
expect(summaryMatches.length, 'summary sentence should appear exactly once (hero only)').toBe(
1
);

// 2. The long emphasized label is gone from the body. Its image still
// surfaces in the gallery so the screenshot itself is preserved.
Expand Down
Loading