kopia lustrzana https://github.com/transitive-bullshit/chatgpt-api
pull/718/head
rodzic
4faadbf166
commit
a23fc97c56
|
@ -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()
|
||||
}
|
||||
}
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -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
25
todo.md
|
@ -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
|
||||
|
|
Ładowanie…
Reference in New Issue