EdgeFunctionBlock.tsx 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. import { Code } from 'lucide-react'
  2. import Link from 'next/link'
  3. import type { DragEvent, ReactNode } from 'react'
  4. import { Button, cn } from 'ui'
  5. import { Admonition } from 'ui-patterns/admonition'
  6. import { CodeBlock, type CodeBlockLang } from 'ui-patterns/CodeBlock'
  7. import { ReportBlockContainer } from '@/components/interfaces/Reports/ReportBlock/ReportBlockContainer'
  8. interface EdgeFunctionBlockProps {
  9. /** Title of the EdgeFunctionBlock */
  10. label: string
  11. /** Function code to display */
  12. code: string
  13. /** Function name/slug */
  14. functionName: string
  15. /** Any other actions specific to the parent to be rendered in the header */
  16. actions?: ReactNode
  17. /** Toggle visiblity of code on render */
  18. showCode?: boolean
  19. /** Whether function block is draggable */
  20. draggable?: boolean
  21. /** Tooltip when hovering over the header of the block */
  22. tooltip?: ReactNode
  23. /** Optional callback on drag start */
  24. onDragStart?: (e: DragEvent) => void
  25. /** Hide the header deploy button (used when an external confirm footer is shown) */
  26. hideDeployButton?: boolean
  27. /** Disable interactive actions */
  28. disabled?: boolean
  29. /** Whether a deploy action is currently running */
  30. isDeploying?: boolean
  31. /** Whether a deploy action has completed */
  32. isDeployed?: boolean
  33. /** Optional message to show when deployment fails */
  34. errorText?: string
  35. /** URL to the deployed function */
  36. functionUrl?: string
  37. /** Link to the function details page */
  38. deploymentDetailsUrl?: string
  39. /** CLI command to download the function */
  40. downloadCommand?: string
  41. /** Show warning UI when replacing an existing function */
  42. showReplaceWarning?: boolean
  43. /** Cancel handler when replacing an existing function */
  44. onCancelReplace?: () => void
  45. /** Confirm handler when replacing an existing function */
  46. onConfirmReplace?: () => void
  47. /** Handler for triggering a deploy */
  48. onDeploy?: () => void
  49. }
  50. export const EdgeFunctionBlock = ({
  51. label,
  52. code,
  53. functionName,
  54. actions,
  55. tooltip,
  56. hideDeployButton = false,
  57. disabled = false,
  58. isDeploying = false,
  59. isDeployed = false,
  60. errorText,
  61. functionUrl,
  62. deploymentDetailsUrl,
  63. downloadCommand,
  64. showReplaceWarning = false,
  65. onCancelReplace,
  66. onConfirmReplace,
  67. onDeploy,
  68. draggable = false,
  69. onDragStart,
  70. }: EdgeFunctionBlockProps) => {
  71. const resolvedFunctionUrl = functionUrl ?? 'Function URL will be available after deployment'
  72. const resolvedDownloadCommand = downloadCommand ?? `briven functions download ${functionName}`
  73. const hasStatusMessage = isDeploying || isDeployed || !!errorText
  74. return (
  75. <ReportBlockContainer
  76. tooltip={tooltip}
  77. icon={<Code size={16} strokeWidth={1.5} className="text-foreground-muted" />}
  78. label={label}
  79. loading={isDeploying}
  80. draggable={draggable}
  81. onDragStart={onDragStart}
  82. actions={
  83. hideDeployButton || !onDeploy ? (
  84. (actions ?? null)
  85. ) : (
  86. <>
  87. <Button
  88. type="outline"
  89. size="tiny"
  90. loading={isDeploying}
  91. disabled={disabled || isDeploying}
  92. onClick={onDeploy}
  93. >
  94. {isDeploying ? 'Deploying...' : 'Deploy'}
  95. </Button>
  96. {actions}
  97. </>
  98. )
  99. }
  100. >
  101. {showReplaceWarning && (
  102. <Admonition
  103. type="warning"
  104. className="rounded-none border-0 border-b shrink-0 bg-background-100"
  105. >
  106. <p>An edge function with the name "{functionName}" already exists.</p>
  107. <p className="text-foreground-light">
  108. Deploying will replace the existing function. Are you sure you want to proceed?
  109. </p>
  110. <div className="flex justify-stretch mt-2 gap-2">
  111. <Button
  112. type="outline"
  113. size="tiny"
  114. className="w-full flex-1"
  115. disabled={isDeploying}
  116. onClick={onCancelReplace}
  117. >
  118. Cancel
  119. </Button>
  120. <Button
  121. type="danger"
  122. size="tiny"
  123. className="w-full flex-1"
  124. loading={isDeploying}
  125. disabled={isDeploying}
  126. onClick={onConfirmReplace}
  127. >
  128. Replace function
  129. </Button>
  130. </div>
  131. </Admonition>
  132. )}
  133. <div className="shrink-0 w-full max-h-96 overflow-y-auto">
  134. <CodeBlock
  135. hideLineNumbers
  136. wrapLines={false}
  137. value={code}
  138. language={'typescript' as CodeBlockLang}
  139. className={cn(
  140. 'max-w-none block bg-transparent! py-3! px-3.5! prose dark:prose-dark border-0 text-foreground rounded-none! w-full',
  141. '[&>code]:m-0 [&>code>span]:text-foreground'
  142. )}
  143. />
  144. </div>
  145. {hasStatusMessage && (
  146. <div className="p-4 w-full border-t bg-surface-75 text-xs">
  147. {isDeploying ? (
  148. <p className="text-foreground-light">Deploying function...</p>
  149. ) : errorText ? (
  150. <p className="text-danger">{errorText}</p>
  151. ) : (
  152. <>
  153. <p className="text-foreground-light mb-2">
  154. The{' '}
  155. {deploymentDetailsUrl ? (
  156. <Link className="text-foreground" href={deploymentDetailsUrl}>
  157. new function
  158. </Link>
  159. ) : (
  160. <span className="text-foreground">new function</span>
  161. )}{' '}
  162. is now live at:
  163. </p>
  164. <CodeBlock
  165. language="bash"
  166. hideLineNumbers
  167. value={resolvedFunctionUrl}
  168. className="text-xs p-2"
  169. />
  170. <p className="text-foreground-light mt-4 mb-2">
  171. To download and work on this function locally, use the CLI command:
  172. </p>
  173. <CodeBlock
  174. hideLineNumbers
  175. language="bash"
  176. value={resolvedDownloadCommand}
  177. className="text-xs p-2"
  178. />
  179. </>
  180. )}
  181. </div>
  182. )}
  183. </ReportBlockContainer>
  184. )
  185. }