TerminalInstructions.tsx 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. import { PermissionAction } from '@supabase/shared-types/out/constants'
  2. import { useParams } from 'common'
  3. import { ExternalLink, Maximize2, Minimize2, Terminal } from 'lucide-react'
  4. import { useRouter } from 'next/router'
  5. import { ComponentPropsWithoutRef, ElementRef, forwardRef, useState } from 'react'
  6. import { Button, Collapsible, CollapsibleContent, CollapsibleTrigger } from 'ui'
  7. import type { Commands } from './Functions.types'
  8. import CommandRender from '@/components/interfaces/Functions/CommandRender'
  9. import { DocsButton } from '@/components/ui/DocsButton'
  10. import { useAccessTokensQuery } from '@/data/access-tokens/access-tokens-query'
  11. import { getKeys, useAPIKeysQuery } from '@/data/api-keys/api-keys-query'
  12. import { useProjectApiUrl } from '@/data/config/project-endpoint-query'
  13. import { useAsyncCheckPermissions } from '@/hooks/misc/useCheckPermissions'
  14. import { DOCS_URL } from '@/lib/constants'
  15. interface TerminalInstructionsProps extends ComponentPropsWithoutRef<typeof Collapsible> {
  16. closable?: boolean
  17. removeBorder?: boolean
  18. }
  19. export const TerminalInstructions = forwardRef<
  20. ElementRef<typeof Collapsible>,
  21. TerminalInstructionsProps
  22. >(({ closable = false, removeBorder = false, ...props }, ref) => {
  23. const router = useRouter()
  24. const { ref: projectRef } = useParams()
  25. const [showInstructions, setShowInstructions] = useState(!closable)
  26. const { data: tokens } = useAccessTokensQuery()
  27. const { can: canReadAPIKeys } = useAsyncCheckPermissions(PermissionAction.SECRETS_READ, '*')
  28. const { data: apiKeys } = useAPIKeysQuery({ projectRef }, { enabled: canReadAPIKeys })
  29. const { data: endpoint } = useProjectApiUrl({ projectRef })
  30. const functionsEndpoint = `${endpoint}/functions/v1`
  31. const { anonKey, publishableKey } = getKeys(apiKeys)
  32. const apiKey = publishableKey?.api_key ?? anonKey?.api_key ?? '[YOUR ANON KEY]'
  33. // get the .co or .net TLD from the restUrl
  34. const restUrl = `https://${endpoint}`
  35. const restUrlTld = !!endpoint ? new URL(restUrl).hostname.split('.').pop() : 'co'
  36. const commands: Commands[] = [
  37. {
  38. command: 'briven functions new hello-world',
  39. description: ' creates a function stub at ./functions/hello-world/index.ts',
  40. jsx: () => {
  41. return (
  42. <>
  43. <span className="text-brand-600">briven</span> functions new hello-world
  44. </>
  45. )
  46. },
  47. comment: 'Create a function',
  48. },
  49. {
  50. command: `briven functions deploy hello-world --project-ref ${projectRef}`,
  51. description: 'Deploys function at ./functions/hello-world/index.ts',
  52. jsx: () => {
  53. return (
  54. <>
  55. <span className="text-brand-600">briven</span> functions deploy hello-world
  56. --project-ref {projectRef}
  57. </>
  58. )
  59. },
  60. comment: 'Deploy your function',
  61. },
  62. {
  63. command: `curl -L -X POST 'https://${projectRef}.briven.${restUrlTld}/functions/v1/hello-world' -H 'Authorization: Bearer ${apiKey}'${anonKey?.type === 'publishable' ? ` -H 'apikey: ${apiKey}'` : ''} --data '{"name":"Functions"}'`,
  64. description: 'Invokes the hello-world function',
  65. jsx: () => {
  66. return (
  67. <>
  68. <span className="text-brand-600">curl</span> -L -X POST '{functionsEndpoint}
  69. /hello-world' -H 'Authorization: Bearer [YOUR ANON KEY]'
  70. {anonKey?.type === 'publishable' ? " -H 'apikey: [YOUR ANON KEY]' " : ''}
  71. {`--data '{"name":"Functions"}'`}
  72. </>
  73. )
  74. },
  75. comment: 'Invoke your function',
  76. },
  77. ]
  78. return (
  79. <Collapsible
  80. ref={ref}
  81. open={showInstructions}
  82. className="w-full"
  83. onOpenChange={() => setShowInstructions(!showInstructions)}
  84. {...props}
  85. >
  86. <CollapsibleTrigger className="flex w-full justify-between" disabled={!closable}>
  87. <div className="flex items-center gap-x-3">
  88. <div className="flex items-center justify-center w-8 h-8 p-2 border rounded-sm bg-alternative">
  89. <Terminal strokeWidth={2} />
  90. </div>
  91. <h4>Create your first Edge Function via the CLI</h4>
  92. </div>
  93. {closable && (
  94. <div className="cursor-pointer" onClick={() => setShowInstructions(!showInstructions)}>
  95. {showInstructions ? (
  96. <Minimize2 size={16} strokeWidth={1.5} />
  97. ) : (
  98. <Maximize2 size={16} strokeWidth={1.5} />
  99. )}
  100. </div>
  101. )}
  102. </CollapsibleTrigger>
  103. <CollapsibleContent className="w-full transition-all data-closed:animate-collapsible-up data-open:animate-collapsible-down">
  104. <CommandRender commands={commands} className="my-4" />
  105. {tokens && tokens.length === 0 ? (
  106. <div className="py-4 space-y-3 border-t">
  107. <div>
  108. <p className="text-sm text-foreground">You may need to create an access token</p>
  109. <p className="text-sm text-foreground-light">
  110. You can create a secure access token in your account section
  111. </p>
  112. </div>
  113. <Button type="default" onClick={() => router.push('/account/tokens')}>
  114. Access tokens
  115. </Button>
  116. </div>
  117. ) : (
  118. <div className="py-4 space-y-3 border-t">
  119. <div>
  120. <h3 className="text-base text-foreground">Need help?</h3>
  121. <p className="text-sm text-foreground-light">
  122. Read the documentation, or browse some sample code.
  123. </p>
  124. </div>
  125. <div className="flex gap-2">
  126. <DocsButton href={`${DOCS_URL}/guides/functions`} />
  127. <Button asChild type="default" icon={<ExternalLink />}>
  128. <a
  129. target="_blank"
  130. rel="noreferrer"
  131. href="https://github.com/briven/briven/tree/master/examples/edge-functions/briven/functions"
  132. >
  133. Examples
  134. </a>
  135. </Button>
  136. </div>
  137. </div>
  138. )}
  139. </CollapsibleContent>
  140. </Collapsible>
  141. )
  142. })
  143. TerminalInstructions.displayName = 'TerminalInstructions'