| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167 |
- import {
- BadgeCheck,
- BarChart3,
- Boxes,
- Cable,
- Cpu,
- CreditCard,
- Database,
- Fingerprint,
- KeyRound,
- Mail,
- MessageSquare,
- MousePointerClick,
- Package2,
- Plug,
- Server,
- ShieldCheck,
- Users,
- Webhook,
- Wrench,
- Zap,
- type LucideIcon,
- } from 'lucide-react'
- import type { ReactNode } from 'react'
- import { Badge, cn, IconPartners } from 'ui'
- import type {
- IntegrationDefinition,
- MarketplaceSource,
- } from '@/components/interfaces/Integrations/Landing/Integrations.constants'
- export type { MarketplaceSource } from '@/components/interfaces/Integrations/Landing/Integrations.constants'
- // Launch-partner pin list for the featured rail. Order here is the order
- // shown. Stripe is the only first-party template in the set (id matches the
- // static catalogue); the rest are marketplaceDB slugs and only render if the
- // listing is published.
- export const FEATURED_INTEGRATION_IDS = [
- 'grafana',
- 'stripe_sync_engine',
- 'aikido',
- 'aikido-security',
- 'doppler',
- 'cipherstash',
- ] as const
- export type MarketplaceIntegrationType = 'oauth' | 'postgres_extension' | 'template' | 'wrapper'
- export const INTEGRATION_TYPES: Array<{
- key: MarketplaceIntegrationType
- label: string
- icon: LucideIcon
- }> = [
- { key: 'oauth', label: 'OAuth App', icon: Plug },
- { key: 'postgres_extension', label: 'Postgres Module', icon: Database },
- { key: 'template', label: 'Template', icon: Package2 },
- { key: 'wrapper', label: 'Wrapper', icon: Cable },
- ]
- // Lucide icon per marketplace category slug. New categories fall back to a
- // neutral icon (Boxes) so nothing breaks when the marketplaceDB is updated.
- export const CATEGORY_ICONS: Record<string, LucideIcon> = {
- observability: BarChart3,
- security: ShieldCheck,
- billing: CreditCard,
- secrets: KeyRound,
- email: Mail,
- wrappers: Database,
- ai: Cpu,
- ai_vectors: Cpu,
- storage: Package2,
- postgres_extension: Database,
- wrapper: Cable,
- devtools: Wrench,
- auth: Fingerprint,
- 'low-code': MousePointerClick,
- 'data-platform': Server,
- api: Webhook,
- 'caching-offline-first': Zap,
- messaging: MessageSquare,
- }
- export const FEATURED_CATEGORIES: Array<{ slug: string; name: string }> = [
- { slug: 'observability', name: 'Observability' },
- { slug: 'security', name: 'Security' },
- { slug: 'billing', name: 'Billing' },
- { slug: 'devtools', name: 'DevTools' },
- { slug: 'ai_vectors', name: 'AI & Vectors' },
- { slug: 'storage', name: 'Storage' },
- ]
- // Categories excluded from the filter dropdown — they either overlap with
- // dedicated filter groups (type/source) or are unused in the current catalogue.
- export const EXCLUDED_CATEGORY_SLUGS = new Set([
- 'agencies',
- 'foreign-data-wrapper',
- 'app-templates',
- ])
- export const getCategoryIcon = (slug: string | null | undefined): LucideIcon => {
- if (!slug) return Boxes
- return CATEGORY_ICONS[slug] ?? Boxes
- }
- export const formatCategoryLabel = (
- slug: string | null | undefined,
- categoryOptions?: Array<{ slug: string; name: string }>
- ): string => {
- if (!slug) return ''
- const pinned = FEATURED_CATEGORIES.find((c) => c.slug === slug)
- if (pinned) return pinned.name
- const remote = categoryOptions?.find((c) => c.slug === slug)
- if (remote) return remote.name
- return slug
- .split(/[-_]/)
- .filter(Boolean)
- .map((w) => w.charAt(0).toUpperCase() + w.slice(1))
- .join(' ')
- }
- export const getMarketplaceType = (
- integration: IntegrationDefinition
- ): MarketplaceIntegrationType => {
- if (integration.type === 'wrapper') return 'wrapper'
- if (integration.type === 'postgres_extension') return 'postgres_extension'
- if (integration.id === 'stripe_sync_engine') return 'template'
- return 'oauth'
- }
- export const getMarketplaceTypeLabel = (type: MarketplaceIntegrationType): string =>
- INTEGRATION_TYPES.find((t) => t.key === type)?.label ?? type
- export const MARKETPLACE_SOURCES: Array<{
- key: MarketplaceSource
- label: string
- icon: LucideIcon | ((props: { className?: string }) => ReactNode)
- }> = [
- { key: 'Official', label: 'Official', icon: BadgeCheck },
- { key: 'Partner', label: 'Partner', icon: IconPartners },
- { key: 'Community', label: 'Community', icon: Users },
- ]
- export const getMarketplaceSource = (integration: IntegrationDefinition): MarketplaceSource => {
- if (integration.source) return integration.source
- return integration.listingId ? 'Partner' : 'Official'
- }
- export const MarketplaceSourceBadge = ({
- source,
- className,
- }: {
- source: MarketplaceSource
- className?: string
- }) => {
- switch (source) {
- case 'Partner':
- return (
- <Badge className={cn('border-foreground-lighter/50', className)}>
- <IconPartners size={10} /> Partner
- </Badge>
- )
- case 'Community':
- return <Badge className={className}>Community</Badge>
- case 'Official':
- return <Badge className={className}>Official</Badge>
- }
- }
|