ApiKeysIllustrations.tsx164 lines · main
1import { SupportCategories } from '@supabase/shared-types/out/constants'
2import { LOCAL_STORAGE_KEYS } from 'common'
3import { ExternalLink } from 'lucide-react'
4import {
5 Card,
6 CardContent,
7 Separator,
8 Table,
9 TableBody,
10 TableCell,
11 TableHead,
12 TableHeader,
13 TableRow,
14} from 'ui'
15
16import { SupportLink } from '../Support/SupportLink'
17import { ApiKeyPill } from './ApiKeyPill'
18import { CreateNewAPIKeysButton } from './CreateNewAPIKeysButton'
19import { FeatureBanner } from '@/components/ui/FeatureBanner'
20import { InlineLink, InlineLinkClassName } from '@/components/ui/InlineLink'
21import { APIKeysData } from '@/data/api-keys/api-keys-query'
22
23// Mock API Keys for demo
24const mockApiKeys = [
25 {
26 id: 'mock-id-2',
27 type: 'publishable',
28 api_key: 'sb_publishable_ltaNA7nnVozoSCOcZIjg',
29 name: 'web',
30 },
31 {
32 id: 'mock-id-3',
33 type: 'publishable',
34 api_key: 'sb_publishable_YpotEpinEWsC2dI7FIKI',
35 name: 'mobile',
36 },
37 {
38 id: 'mock-id-1',
39 type: 'secret',
40 api_key: 'sb_secret_8I4Se•••••••••••••',
41 name: 'backend_api',
42 },
43] as Extract<APIKeysData[number], { type: 'secret' | 'publishable' }>[]
44
45/**
46 * Reusable table illustration component
47 */
48const ApiKeysTableIllustration = () => {
49 return (
50 <Card className="w-full overflow-hidden opacity-60 pointer-events-none bg-surface-100">
51 <CardContent className="p-0">
52 <Table className="p-5">
53 <TableHeader>
54 <TableRow className="bg-200">
55 <TableHead
56 key=""
57 className="text-left font-mono uppercase text-xs text-foreground-lighter h-auto py-2 overflow-hidden w-[180px]"
58 >
59 Name
60 </TableHead>
61 <TableHead className="text-left font-mono uppercase text-xs text-foreground-lighter h-auto py-2 pr-0">
62 API Key
63 </TableHead>
64 <TableHead
65 className="text-right font-mono uppercase text-xs text-foreground-lighter h-auto py-2"
66 key="actions"
67 />
68 </TableRow>
69 </TableHeader>
70 <TableBody>
71 {mockApiKeys.map((apiKey) => (
72 <TableRow key={apiKey.id}>
73 <TableCell className="py-2 w-[180px]">{apiKey.name}</TableCell>
74 <TableCell className="py-2">
75 <div className="flex flex-row gap-2">
76 <ApiKeyPill apiKey={apiKey} />
77 </div>
78 </TableCell>
79 <TableCell />
80 </TableRow>
81 ))}
82 </TableBody>
83 </Table>
84 </CardContent>
85 </Card>
86 )
87}
88
89/**
90 * Reusable illustration with gradient overlay component
91 */
92const ApiKeysIllustrationWithOverlay = () => {
93 return (
94 <>
95 {/* Gradient overlay - horizontal on desktop, vertical on mobile */}
96 <div
97 className="absolute inset-x-0 bottom-0 h-1/2 xl:h-full xl:inset-x-auto xl:-right-16 xl:top-3 w-full xl:w-2/3
98 bg-linear-to-t xl:bg-linear-to-l
99 from-background-alternative via-background-alternative/90 via-5% to-transparent
100 z-3 pointer-events-none xl:max-w-[500px]"
101 />
102
103 <div className="absolute scale-100 left-10 -bottom-14 w-[720px] xl:w-[500px] xl:left-auto xl:right-[-200px] 2xl:-right-16 xl:top-[21px] xl:scale-75">
104 <ApiKeysTableIllustration />
105 </div>
106 </>
107 )
108}
109
110export const ApiKeysCreateCallout = () => {
111 return (
112 <FeatureBanner illustration={<ApiKeysIllustrationWithOverlay />} bgAlt>
113 <div className="flex flex-col gap-0 z-2">
114 <p className="text-sm text-foreground">Create API keys</p>
115 <p className="text-sm text-foreground-lighter lg:max-w-sm 2xl:max-w-none">
116 Use keys to authenticate requests to your app
117 </p>
118 <div className="mt-4">
119 <CreateNewAPIKeysButton />
120 </div>
121 </div>
122 </FeatureBanner>
123 )
124}
125
126export const ApiKeysFeedbackBanner = () => {
127 return (
128 <FeatureBanner
129 storageKey={LOCAL_STORAGE_KEYS.API_KEYS_FEEDBACK_DISMISSED}
130 className="p-0! flex flex-col gap-0"
131 dismissable
132 >
133 <div className="p-5">
134 <p className="text-sm text-foreground">Your new API keys are here</p>
135 <p className="text-sm text-foreground-lighter">
136 We've updated our API keys to better support your application needs.{' '}
137 <InlineLink
138 href="https://github.com/orgs/briven/discussions/29260"
139 className="inline-flex items-center gap-1"
140 >
141 Join the discussion on GitHub <ExternalLink aria-hidden size={14} strokeWidth={1.5} />
142 </InlineLink>
143 </p>
144 </div>
145
146 <Separator className="w-full" />
147
148 <div className="px-5 py-2 bg-surface-200/30">
149 <p className="text-sm text-foreground-lighter">
150 Having trouble with the new API keys?{' '}
151 <SupportLink
152 className={InlineLinkClassName}
153 queryParams={{
154 category: SupportCategories.PROBLEM,
155 subject: 'Help with API keys',
156 }}
157 >
158 Contact support
159 </SupportLink>
160 </p>
161 </div>
162 </FeatureBanner>
163 )
164}