| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152 |
- import { type RefObject } from 'react'
- import { Admonition } from 'ui-patterns/admonition'
- import CopyButton from '@/components/ui/CopyButton'
- import { BASE_PATH } from '@/lib/constants'
- interface CopyPromptAdmonitionProps {
- stepsContainerRef: RefObject<HTMLDivElement | null>
- }
- export function CopyPromptAdmonition({ stepsContainerRef }: CopyPromptAdmonitionProps) {
- const normalizeTextLines = (value: string) => {
- return value
- .split('\n')
- .map((line) => line.trim())
- .filter(Boolean)
- .join('\n')
- }
- const getStepTextContent = (contentElement: HTMLElement) => {
- const clone = contentElement.cloneNode(true) as HTMLElement
- clone
- .querySelectorAll('pre, button, svg, input, textarea, select, [aria-hidden="true"]')
- .forEach((element) => {
- element.remove()
- })
- clone.querySelectorAll('p, div').forEach((el) => {
- el.appendChild(document.createTextNode('\n'))
- })
- const text = clone.textContent ?? ''
- return normalizeTextLines(text)
- }
- const getStepCodeSnippets = (contentElement: HTMLElement) => {
- const snippets: Array<{ label: string; snippet: string }> = []
- const seen = new Set<string>()
- const addSnippet = (label: string, snippet: string) => {
- if (!snippet || seen.has(snippet)) return
- seen.add(snippet)
- snippets.push({ label, snippet })
- }
- const tabContents = Array.from(
- contentElement.querySelectorAll('[data-connect-tab-content]')
- ) as HTMLElement[]
- tabContents.forEach((tabContent) => {
- const label = tabContent.getAttribute('data-tab-label') || 'Code'
- const tabSnippets = Array.from(tabContent.querySelectorAll('pre'))
- .map((pre) => pre.textContent?.trim())
- .filter((snippet): snippet is string => Boolean(snippet))
- if (tabSnippets.length === 0) {
- const inlineSnippets = Array.from(tabContent.querySelectorAll('code'))
- .filter((code) => !code.closest('pre') && code.closest('.font-mono'))
- .map((code) => code.textContent?.trim())
- .filter((snippet): snippet is string => Boolean(snippet))
- inlineSnippets.forEach((snippet, index) => {
- const inlineLabel = inlineSnippets.length > 1 ? `${label} (part ${index + 1})` : label
- addSnippet(inlineLabel, snippet)
- })
- return
- }
- tabSnippets.forEach((snippet, index) => {
- const tabLabel = tabSnippets.length > 1 ? `${label} (part ${index + 1})` : label
- addSnippet(tabLabel, snippet)
- })
- })
- contentElement.querySelectorAll('pre').forEach((pre) => {
- if (pre.closest('[data-connect-tab-content]')) return
- const snippet = pre.textContent?.trim()
- if (snippet) addSnippet('Code', snippet)
- })
- contentElement.querySelectorAll('code').forEach((code) => {
- if (code.closest('pre')) return
- if (code.closest('[data-connect-tab-content]')) return
- if (!code.closest('.font-mono')) return
- const snippet = code.textContent?.trim()
- if (snippet) addSnippet('Code', snippet)
- })
- return snippets
- }
- const handleCopyPrompt = () => {
- const stepElements = stepsContainerRef.current?.querySelectorAll('[data-connect-step]')
- if (!stepElements?.length) return ''
- const promptContent = Array.from(stepElements)
- .map((stepElement, index) => {
- const title = stepElement.getAttribute('data-step-title') ?? `Step ${index + 1}`
- const description = stepElement.getAttribute('data-step-description') ?? ''
- const contentElement = stepElement.querySelector(
- '[data-step-content]'
- ) as HTMLElement | null
- const details = contentElement ? getStepTextContent(contentElement) : ''
- const codeSnippets = contentElement ? getStepCodeSnippets(contentElement) : []
- const sections = [
- `${index + 1}. ${title}`,
- description,
- details ? `Details:\n${details}` : null,
- codeSnippets.length
- ? `Code:\n${codeSnippets
- .map(({ label, snippet }) => `File: ${label}\n\`\`\`\n${snippet}\n\`\`\``)
- .join('\n\n')}`
- : null,
- ].filter(Boolean)
- return sections.join('\n')
- })
- .join('\n\n')
- return promptContent
- }
- return (
- <Admonition
- type="tip"
- showIcon={false}
- layout="horizontal"
- actions={<CopyButton type="default" copyLabel="Copy prompt" asyncText={handleCopyPrompt} />}
- >
- <div className="absolute -inset-16 z-0 opacity-50">
- <img
- src={`${BASE_PATH}/img/reports/bg-grafana-dark.svg`}
- alt="Briven Grafana"
- className="w-full h-full object-cover object-right hidden dark:block"
- />
- <img
- src={`${BASE_PATH}/img/reports/bg-grafana-light.svg`}
- alt="Briven Grafana"
- className="w-full h-full object-cover object-right dark:hidden"
- />
- <div className="absolute inset-0 bg-linear-to-r from-background-alternative to-transparent" />
- </div>
- <div className="relative flex flex-col md:flex-row md:items-center gap-y-2 md:gap-x-8 justify-between">
- <div className="flex flex-col gap-y-0.5">
- <p className="heading-default">Give your agent everything it needs</p>
- </div>
- </div>
- </Admonition>
- )
- }
|