Files
7548fd1850 feat: Conversational AI for the SQL Editor (#21388)
* Add a API endpoint for generating queries for the SQL editor.

* Merge all multiline props.

* Add a new component for diff actions.

* Copy components for the AI panel.

* Add useChat hook.

* Add a feature preview for the this feature. The preview is dependent on the feature flag.

* Reorder the nesting in the SQL editor to accomodate the AI assistant.

* Try to fit both AI assistants in the SQL editor, available via a feature preview.

* Refactor the SQL editor to make the diff work correctly in all cases.

* Minor fixes for the old AI feature.

* Fix the debug functionality to work with both assistants.

* Fix some copy-paste leftovers.

* Remove unneeded code.

* Make the icons softer.

* Fix the name of the panel component.

* Fix console.logs.

* Add overflow to the AI assistant.

* surface opt in config in ai settings button

* Skip diffing if editor is empty

* Add selected state when selecting a message to insert/replace code

* Add sample prompts

* Add SQL ai dislaimer when replacing code

* Light mode action bar nudges

* Add text for the feature preview.

* lang nudges

* Hide the command suggestions for now.

* Set the discussion url to undefined.

* Don't add the disclaimer twice.

---------

Co-authored-by: Joshen Lim <joshenlimek@gmail.com>
Co-authored-by: Terry Sutton <saltcod@gmail.com>
2024-03-05 17:26:11 +01:00

150 lines
4.6 KiB
TypeScript

import { useTelemetryProps } from 'common'
import { InsertCode, ReplaceCode } from 'icons'
import { Check, Copy } from 'lucide-react'
import { useRouter } from 'next/router'
import { useEffect, useState } from 'react'
import { format } from 'sql-formatter'
import {
Button,
CodeBlock,
TooltipContent_Shadcn_,
TooltipTrigger_Shadcn_,
Tooltip_Shadcn_,
cn,
} from 'ui'
import Telemetry from 'lib/telemetry'
import { DiffType } from '../SQLEditor.types'
interface AiMessagePreProps {
onDiff: (type: DiffType, s: string) => void
children: string[]
className?: string
}
export const AiMessagePre = ({ onDiff, children, className }: AiMessagePreProps) => {
const [copied, setCopied] = useState(false)
const router = useRouter()
const telemetryProps = useTelemetryProps()
useEffect(() => {
if (!copied) return
const timer = setTimeout(() => setCopied(false), 2000)
return () => clearTimeout(timer)
}, [copied])
let formatted = (children || [''])[0]
try {
formatted = format(formatted, { language: 'postgresql', keywordCase: 'upper' })
} catch {}
if (formatted.length === 0) {
return null
}
function handleCopy(formatted: string) {
navigator.clipboard.writeText(formatted).then()
setCopied(true)
}
return (
<pre className={cn('rounded-md relative group', className)}>
<CodeBlock
value={formatted}
language="sql"
className={cn(
'!bg-transparent !py-3 !px-3.5 prose dark:prose-dark',
// change the look of the code block. The flex hack is so that the code is wrapping since
// every word is a separate span
'[&>code]:m-0 [&>code>span]:flex [&>code>span]:flex-wrap'
)}
hideCopy
hideLineNumbers
/>
<div className="absolute top-5 right-2 bg-surface-100 border-muted border rounded-lg h-[28px] hidden group-hover:block">
<Tooltip_Shadcn_>
<TooltipTrigger_Shadcn_ asChild>
<Button
type="text"
size="tiny"
onClick={() => {
onDiff(DiffType.Addition, formatted)
Telemetry.sendEvent(
{
category: 'sql_editor_ai_assistant',
action: 'ai_suggestion_inserted',
label: 'sql-editor-ai-assistant',
},
telemetryProps,
router
)
}}
>
<InsertCode className="h-4 w-4 text-foreground-light" strokeWidth={1.5} />
</Button>
</TooltipTrigger_Shadcn_>
<TooltipContent_Shadcn_ side="bottom" className="font-sans">
Insert code
</TooltipContent_Shadcn_>
</Tooltip_Shadcn_>
<Tooltip_Shadcn_>
<TooltipTrigger_Shadcn_ asChild>
<Button
type="text"
size="tiny"
onClick={() => {
onDiff(DiffType.Modification, formatted)
Telemetry.sendEvent(
{
category: 'sql_editor_ai_assistant',
action: 'ai_suggestion_replaced',
label: 'sql-editor-ai-assistant',
},
telemetryProps,
router
)
}}
>
<ReplaceCode className="h-4 w-4 text-foreground-light" strokeWidth={1.5} />
</Button>
</TooltipTrigger_Shadcn_>
<TooltipContent_Shadcn_ side="bottom" className="font-sans">
Replace code
</TooltipContent_Shadcn_>
</Tooltip_Shadcn_>
<Tooltip_Shadcn_>
<TooltipTrigger_Shadcn_ asChild>
<Button
type="text"
size="tiny"
onClick={() => {
handleCopy(formatted)
Telemetry.sendEvent(
{
category: 'sql_editor_ai_assistant',
action: 'ai_suggestion_copied',
label: 'sql-editor-ai-assistant',
},
telemetryProps,
router
)
}}
>
{copied ? (
<Check size={16} className="text-brand-600" />
) : (
<Copy size={16} className="text-foreground-light" strokeWidth={1.5} />
)}
</Button>
</TooltipTrigger_Shadcn_>
<TooltipContent_Shadcn_ side="bottom" className="font-sans">
Copy code
</TooltipContent_Shadcn_>
</Tooltip_Shadcn_>
</div>
</pre>
)
}