pull/718/head
Travis Fischer 2025-07-01 14:45:34 -05:00
rodzic 4faadbf166
commit a23fc97c56
4 zmienionych plików z 55 dodań i 90 usunięć

Wyświetl plik

@ -1,51 +0,0 @@
import { parseProjectIdentifier } from '@agentic/platform-validators'
import { notFound } from 'next/navigation'
import { toastError } from '@/lib/notifications'
import { MarketplacePublicProjectDetail } from '../marketplace-public-project-detail'
import {
type MarketplacePublicProjectDetailTab,
marketplacePublicProjectDetailTabsSet
} from '../utils'
export default async function PublicProjectDetailPageTabPage({
params
}: {
params: Promise<{
namespace: string
'project-slug': string
tab: string
}>
}) {
const {
namespace: rawNamespace,
'project-slug': rawProjectSlug,
tab
} = await params
if (!marketplacePublicProjectDetailTabsSet.has(tab)) {
return notFound()
}
try {
const namespace = decodeURIComponent(rawNamespace)
const projectSlug = decodeURIComponent(rawProjectSlug)
const { projectIdentifier } = parseProjectIdentifier(
`${namespace}/${projectSlug}`,
{ strict: true }
)
return (
<MarketplacePublicProjectDetail
projectIdentifier={projectIdentifier}
tab={tab as MarketplacePublicProjectDetailTab}
/>
)
} catch (err: any) {
void toastError(err, { label: 'Invalid project identifier' })
return notFound()
}
}

Wyświetl plik

@ -8,8 +8,8 @@ import { useRouter, useSearchParams } from 'next/navigation'
import plur from 'plur'
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
import { ActiveLink } from '@/components/active-link'
import { useAgentic } from '@/components/agentic-provider'
import { CodeBlock } from '@/components/code-block'
import { ExampleUsage } from '@/components/example-usage'
import { HeroButton } from '@/components/hero-button'
import { LoadingIndicator } from '@/components/loading-indicator'
@ -29,15 +29,14 @@ import { useQuery } from '@/lib/query-client'
import {
type MarketplacePublicProjectDetailTab,
marketplacePublicProjectDetailTabsSet,
MAX_TOOLS_TO_SHOW
} from './utils'
export function MarketplacePublicProjectDetail({
projectIdentifier,
tab = 'overview'
projectIdentifier
}: {
projectIdentifier: string
tab?: MarketplacePublicProjectDetailTab
}) {
const ctx = useAgentic()
const searchParams = useSearchParams()
@ -177,13 +176,18 @@ export function MarketplacePublicProjectDetail({
)
}, [deployment])
const inferredTab = useMemo(() => {
const tab = useMemo<MarketplacePublicProjectDetailTab>(() => {
const tab = searchParams.get('tab')?.toLowerCase()
if (!tab || !marketplacePublicProjectDetailTabsSet.has(tab)) {
return 'overview'
}
if (tab === 'readme' && !deployment?.readme?.trim()) {
return 'overview'
}
return tab
}, [tab, deployment])
return tab as MarketplacePublicProjectDetailTab
}, [searchParams, deployment])
return (
<PageContainer>
@ -196,16 +200,16 @@ export function MarketplacePublicProjectDetail({
<p>Project "{projectIdentifier}" not found</p>
) : (
<div className='flex flex-col gap-4 w-full'>
<ProjectHeader project={project} tab={inferredTab} />
<ProjectHeader project={project} tab={tab} />
<Tabs
value={inferredTab}
value={tab}
onValueChange={(value) => {
if (value === 'overview') {
router.push(`/marketplace/projects/${projectIdentifier}`)
} else {
router.push(
`/marketplace/projects/${projectIdentifier}/${value}`
`/marketplace/projects/${projectIdentifier}?tab=${value}`
)
}
}}
@ -243,7 +247,7 @@ export function MarketplacePublicProjectDetail({
</TabsList>
<div className='bg-card p-4 border rounded-lg shadow-sm color-card-foreground'>
{inferredTab === 'overview' && (
{tab === 'overview' && (
<TabsContent value='overview' className='flex flex-col gap-4'>
<h2 className='text-balance leading-snug md:leading-none text-xl font-semibold'>
Overview
@ -292,7 +296,7 @@ export function MarketplacePublicProjectDetail({
variant='outline'
>
<Link
href={`/marketplace/projects/${projectIdentifier}/tools`}
href={`/marketplace/projects/${projectIdentifier}?tab=tools`}
>
View{' '}
{deployment.tools.length -
@ -328,7 +332,7 @@ export function MarketplacePublicProjectDetail({
</TabsContent>
)}
{deployment?.readme?.trim() && inferredTab === 'readme' && (
{deployment?.readme?.trim() && tab === 'readme' && (
<TabsContent value='readme' className='flex flex-col gap-4'>
<SSRMarkdown
markdown={deployment.readme}
@ -337,7 +341,7 @@ export function MarketplacePublicProjectDetail({
</TabsContent>
)}
{inferredTab === 'tools' && (
{tab === 'tools' && (
<TabsContent value='tools' className='flex flex-col gap-4'>
<h2 className='text-balance leading-snug md:leading-none text-xl font-semibold'>
Tools
@ -370,9 +374,15 @@ export function MarketplacePublicProjectDetail({
</CollapsibleTrigger>
<CollapsibleContent>
<pre className='max-w-full overflow-x-auto border p-4 rounded-sm'>
{JSON.stringify(tool.inputSchema, null, 2)}
</pre>
<CodeBlock
lang='json'
code={JSON.stringify(
tool.inputSchema,
null,
2
)}
className='border rounded-sm'
/>
</CollapsibleContent>
</Collapsible>
@ -389,9 +399,15 @@ export function MarketplacePublicProjectDetail({
</CollapsibleTrigger>
<CollapsibleContent>
<pre className='max-w-full overflow-x-auto border p-4 rounded-sm'>
{JSON.stringify(tool.outputSchema, null, 2)}
</pre>
<CodeBlock
lang='json'
code={JSON.stringify(
tool.outputSchema,
null,
2
)}
className='border rounded-sm'
/>
</CollapsibleContent>
</Collapsible>
)}
@ -402,7 +418,7 @@ export function MarketplacePublicProjectDetail({
</TabsContent>
)}
{inferredTab === 'pricing' && (
{tab === 'pricing' && (
<TabsContent value='pricing' className='flex flex-col gap-4'>
<h2 className='text-balance leading-snug md:leading-none text-xl font-semibold'>
Pricing
@ -419,7 +435,7 @@ export function MarketplacePublicProjectDetail({
</TabsContent>
)}
{inferredTab === 'debug' && (
{tab === 'debug' && (
<TabsContent value='debug' className='flex flex-col gap-4'>
<h2 className='text-balance leading-snug md:leading-none text-xl font-semibold'>
Debug
@ -476,11 +492,11 @@ function ProjectHeader({
className='justify-self-end'
disabled={tab === 'pricing'}
>
<ActiveLink
href={`/marketplace/projects/${project.identifier}/pricing`}
<Link
href={`/marketplace/projects/${project.identifier}?tab=pricing`}
>
Subscribe to {project.identifier}
</ActiveLink>
</Link>
</HeroButton>
</div>

Wyświetl plik

@ -15,12 +15,13 @@ export function ProjectPricingPlans({
onSubscribe: (planSlug: string) => void
className?: string
}) {
// TODO: add support for different pricing intervals
const numPricingPlans =
project.lastPublishedDeployment?.pricingPlans.length || 1
return (
<div
className={`grid grid-cols grid-cols-1 gap-8 sm:grid-cols-${Math.min(
className={`grid grid-cols grid-cols-1 gap-4 sm:grid-cols-${Math.min(
2,
numPricingPlans
)} xl:grid-cols-${Math.min(3, numPricingPlans)}`}

25
todo.md
Wyświetl plik

@ -12,30 +12,24 @@
- example usage
- double check example usage for all TS sdks now that real examples are working
- fix mcp examples
- import react example usage component into docs
- replace json pricing plans and consumers with actual designs
- **replace json pricing plans and consumers with actual designs**
- double-check free-tier rate-limits for `@agentic/search`
- add feature about optimized context to docs
- add ts sdk examples to e2e tests
- submit to awesome mcp, mcp discord, etc
- add scroll appearance motion to hero animation
- replace how-it-works diagram with better version
- docs: add notes about constraints on mcp origin servers (static tools)
- improve public project detail page
- mcp inspector
- **add support to example-usage for api keys**
- **api keys should go beyond 1:1 consumers**
- replace JSON schemas (tool input/output schemas) with `json` code blocks
- improve upgrade flow UX
- **currently not obvious how to get api key**
- improve upgrade flow UX
- marketplace project page
- replace tabs with links
- too much of a delay on individual pages and makes no sense to have these imports on the other tab pages
- add last published date to
- break out into a few subcomponents; some can be server components
- add last published date somewhere
- add breadcrumb nav: marketplace > @agentic > search
- add a basic page + docs on pricing
- [react query prefetching for public pages](https://tanstack.com/query/latest/docs/framework/react/guides/advanced-ssr#prefetching-and-dehydrating-data)
- add [ping](https://modelcontextprotocol.io/specification/2025-03-26/basic/utilities/ping) support to mcp servers
- tool input/output schemas; move `$schema` to top
- add a basic page + docs on pricing => contact
- [**react query prefetching for public pages**](https://tanstack.com/query/latest/docs/framework/react/guides/advanced-ssr#prefetching-and-dehydrating-data)
- add ability to point at remote readmes, icons, files, urls, etc and upload to our own blob storage at deploy time
- **create agentic products for select legacy tools**
@ -131,3 +125,8 @@
- add support for [`@google/genai`](https://github.com/googleapis/js-genai) tools adapter
- currently difficult due to their use of non-standard json schemas
- validate example args against the tool's input schema during config validation
- add scroll appearance motion to hero animation
- add ts sdk examples to e2e tests
- add feature about optimized context to docs
- import react example usage component into docs
- add [ping](https://modelcontextprotocol.io/specification/2025-03-26/basic/utilities/ping) support to mcp servers