mirror of
https://github.com/supabase/supabase.git
synced 2026-10-13 21:29:08 +03:00
onboarding
This commit is contained in:
1 parent
32a634be11
commit
dc4deabcbb
2 files changed
+142
-128
No files matched your search
@@ -312,7 +312,6 @@ export const AIAssistant = ({ className }: AIAssistantProps) => {
|
||||
)
|
||||
|
||||
const hasMessages = chatMessages.length > 0
|
||||
const isShowingOnboarding = !hasMessages && isApiKeySet
|
||||
|
||||
const sendMessageToAssistant = (finalContent: string) => {
|
||||
if (editingMessageId) {
|
||||
@@ -404,18 +403,17 @@ export const AIAssistant = ({ className }: AIAssistantProps) => {
|
||||
]}
|
||||
>
|
||||
<div className={cn('flex flex-col h-full', className)}>
|
||||
<Conversation className={cn('flex-1')}>
|
||||
<AIAssistantHeader
|
||||
isChatLoading={isChatLoading}
|
||||
onNewChat={snap.newChat}
|
||||
onCloseAssistant={snap.closeAssistant}
|
||||
showMetadataWarning={showMetadataWarning}
|
||||
updatedOptInSinceMCP={updatedOptInSinceMCP}
|
||||
isHipaaProjectDisallowed={isHipaaProjectDisallowed as boolean}
|
||||
aiOptInLevel={aiOptInLevel}
|
||||
/>
|
||||
|
||||
{hasMessages ? (
|
||||
<AIAssistantHeader
|
||||
isChatLoading={isChatLoading}
|
||||
onNewChat={snap.newChat}
|
||||
onCloseAssistant={snap.closeAssistant}
|
||||
showMetadataWarning={showMetadataWarning}
|
||||
updatedOptInSinceMCP={updatedOptInSinceMCP}
|
||||
isHipaaProjectDisallowed={isHipaaProjectDisallowed as boolean}
|
||||
aiOptInLevel={aiOptInLevel}
|
||||
/>
|
||||
{hasMessages ? (
|
||||
<Conversation className={cn('flex-1')}>
|
||||
<ConversationContent className="w-full px-7 py-8 mb-10">
|
||||
{renderedMessages}
|
||||
{error && (
|
||||
@@ -459,21 +457,20 @@ export const AIAssistant = ({ className }: AIAssistantProps) => {
|
||||
/>
|
||||
)}
|
||||
</ConversationContent>
|
||||
) : (
|
||||
<AIOnboarding
|
||||
sqlSnippets={snap.sqlSnippets as SqlSnippet[] | undefined}
|
||||
suggestions={
|
||||
snap.suggestions as
|
||||
| { title?: string; prompts?: { label: string; description: string }[] }
|
||||
| undefined
|
||||
}
|
||||
onValueChange={(val) => setValue(val)}
|
||||
onFocusInput={() => inputRef.current?.focus()}
|
||||
/>
|
||||
)}
|
||||
|
||||
<ConversationScrollButton />
|
||||
</Conversation>
|
||||
<ConversationScrollButton />
|
||||
</Conversation>
|
||||
) : (
|
||||
<AIOnboarding
|
||||
sqlSnippets={snap.sqlSnippets as SqlSnippet[] | undefined}
|
||||
suggestions={
|
||||
snap.suggestions as
|
||||
| { title?: string; prompts?: { label: string; description: string }[] }
|
||||
| undefined
|
||||
}
|
||||
onValueChange={(val) => setValue(val)}
|
||||
onFocusInput={() => inputRef.current?.focus()}
|
||||
/>
|
||||
)}
|
||||
|
||||
<AnimatePresence>
|
||||
{editingMessageId && (
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { motion } from 'framer-motion'
|
||||
import { BarChart, FileText, Shield } from 'lucide-react'
|
||||
|
||||
import { Button } from 'ui'
|
||||
import { Button, Skeleton } from 'ui'
|
||||
import { useParams } from 'common'
|
||||
import { LINTER_LEVELS } from 'components/interfaces/Linter/Linter.constants'
|
||||
import { createLintSummaryPrompt, lintInfoMap } from 'components/interfaces/Linter/Linter.utils'
|
||||
@@ -36,7 +36,12 @@ export const AIOnboarding = ({
|
||||
: defaultPrompts
|
||||
|
||||
const { ref: projectRef } = useParams()
|
||||
const { data: lints } = useProjectLintsQuery({ projectRef })
|
||||
const {
|
||||
data: lints,
|
||||
isLoading: isLoadingLints,
|
||||
isFetching: isFetchingLints,
|
||||
} = useProjectLintsQuery({ projectRef })
|
||||
const isLintsLoading = isLoadingLints || isFetchingLints
|
||||
|
||||
const errorLints: Lint[] = (lints?.filter((lint) => lint.level === LINTER_LEVELS.ERROR) ??
|
||||
[]) as Lint[]
|
||||
@@ -44,114 +49,126 @@ export const AIOnboarding = ({
|
||||
const performanceErrorLints = errorLints.filter((lint) => lint.categories?.[0] !== 'SECURITY')
|
||||
|
||||
return (
|
||||
<div className="w-full space-y-6 flex-1 overflow-auto py-8 px-4 justify-end flex flex-col gap-0">
|
||||
<h2 className="heading-section text-foreground mx-4">How can I assist you?</h2>
|
||||
{suggestions?.prompts?.length ? (
|
||||
<div>
|
||||
<h3 className="heading-meta text-foreground-light mb-3 mx-4">Suggestions</h3>
|
||||
{prompts.map((item, index) => (
|
||||
<motion.div
|
||||
key={index}
|
||||
initial={{ y: 5, opacity: 0 }}
|
||||
animate={{ y: 0, opacity: 1 }}
|
||||
transition={{ duration: 0.3, delay: index * 0.05 }}
|
||||
>
|
||||
<Button
|
||||
size="small"
|
||||
type="text"
|
||||
className="w-full justify-start border-b hover:border-b-0 hover:rounded-md rounded-none"
|
||||
icon={<FileText strokeWidth={1.5} size={14} className="text-foreground-light" />}
|
||||
onClick={() => {
|
||||
onValueChange(item.prompt)
|
||||
onFocusInput?.()
|
||||
}}
|
||||
>
|
||||
{item.title}
|
||||
</Button>
|
||||
</motion.div>
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
{performanceErrorLints.length > 0 && (
|
||||
<div className="mb-4">
|
||||
<h3 className="heading-meta text-foreground-light mb-3 mx-4">Improve Performance</h3>
|
||||
{performanceErrorLints.map((lint, index) => {
|
||||
return (
|
||||
<motion.div
|
||||
key={lint.cache_key ?? index}
|
||||
initial={{ y: 5, opacity: 0 }}
|
||||
animate={{ y: 0, opacity: 1 }}
|
||||
transition={{ duration: 0.3, delay: index * 0.03 }}
|
||||
>
|
||||
<Button
|
||||
size="small"
|
||||
type="text"
|
||||
className="w-full justify-start"
|
||||
icon={
|
||||
<BarChart strokeWidth={1.5} size={14} className="text-foreground-light" />
|
||||
}
|
||||
onClick={() => {
|
||||
onValueChange(createLintSummaryPrompt(lint))
|
||||
onFocusInput?.()
|
||||
}}
|
||||
>
|
||||
{lint.detail ? lint.detail.replace('\\`', '') : lint.title}
|
||||
</Button>
|
||||
</motion.div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{securityErrorLints.length > 0 && (
|
||||
<div className="mb-4">
|
||||
<h3 className="heading-meta text-foreground-light mb-3 mx-4">Improve Security</h3>
|
||||
{securityErrorLints.map((lint, index) => {
|
||||
return (
|
||||
<div className="flex-1 overflow-y-auto">
|
||||
<div className="w-full flex-1 max-h-full min-h-full px-4 flex flex-col gap-0">
|
||||
<div className="mt-auto w-full space-y-6 py-8 ">
|
||||
<h2 className="heading-section text-foreground mx-4">How can I assist you?</h2>
|
||||
{suggestions?.prompts?.length ? (
|
||||
<div>
|
||||
<h3 className="heading-meta text-foreground-light mb-3 mx-4">Suggestions</h3>
|
||||
{prompts.map((item, index) => (
|
||||
<motion.div
|
||||
key={index}
|
||||
initial={{ y: 5, opacity: 0 }}
|
||||
animate={{ y: 0, opacity: 1 }}
|
||||
transition={{ duration: 0.3, delay: index * 0.05 }}
|
||||
>
|
||||
<Button
|
||||
size="small"
|
||||
type="text"
|
||||
className="w-full justify-start"
|
||||
icon={<Shield strokeWidth={1.5} size={14} className="text-warning" />}
|
||||
className="w-full justify-start border-b hover:border-b-0 hover:rounded-md rounded-none"
|
||||
icon={
|
||||
<FileText strokeWidth={1.5} size={14} className="text-foreground-light" />
|
||||
}
|
||||
onClick={() => {
|
||||
onValueChange(createLintSummaryPrompt(lint))
|
||||
onValueChange(item.prompt)
|
||||
onFocusInput?.()
|
||||
}}
|
||||
>
|
||||
{lint.detail ? lint.detail.replace(/`/g, '') : lint.title}
|
||||
{item.title}
|
||||
</Button>
|
||||
)
|
||||
})}
|
||||
</motion.div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
) : (
|
||||
<>
|
||||
{isLintsLoading ? (
|
||||
<div className="px-4 flex flex-col gap-2">
|
||||
{Array.from({ length: 6 }).map((_, index) => (
|
||||
<Skeleton className="h-4 w-full" />
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
{performanceErrorLints.length > 0 && (
|
||||
<div className="mb-4">
|
||||
<h3 className="heading-meta text-foreground-light mb-3 mx-4">
|
||||
Improve Performance
|
||||
</h3>
|
||||
{performanceErrorLints.map((lint, index) => {
|
||||
return (
|
||||
<Button
|
||||
size="small"
|
||||
type="text"
|
||||
className="w-full justify-start"
|
||||
icon={
|
||||
<BarChart
|
||||
strokeWidth={1.5}
|
||||
size={14}
|
||||
className="text-foreground-light"
|
||||
/>
|
||||
}
|
||||
onClick={() => {
|
||||
onValueChange(createLintSummaryPrompt(lint))
|
||||
onFocusInput?.()
|
||||
}}
|
||||
>
|
||||
{lint.detail ? lint.detail.replace('\\`', '') : lint.title}
|
||||
</Button>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div>
|
||||
<h3 className="heading-meta text-foreground-light mb-3 mx-4">Ideas</h3>
|
||||
{prompts.map((item, index) => (
|
||||
<motion.div
|
||||
key={index}
|
||||
initial={{ y: 5, opacity: 0 }}
|
||||
animate={{ y: 0, opacity: 1 }}
|
||||
transition={{ duration: 0.3, delay: index * 0.05 }}
|
||||
>
|
||||
<Button
|
||||
size="small"
|
||||
type="text"
|
||||
className="w-full justify-start"
|
||||
icon={<FileText strokeWidth={1.5} size={14} className="text-foreground-light" />}
|
||||
onClick={() => {
|
||||
onValueChange(item.prompt)
|
||||
onFocusInput?.()
|
||||
}}
|
||||
>
|
||||
{item.title}
|
||||
</Button>
|
||||
</motion.div>
|
||||
))}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
{securityErrorLints.length > 0 && (
|
||||
<div className="mb-4">
|
||||
<h3 className="heading-meta text-foreground-light mb-3 mx-4">
|
||||
Improve Security
|
||||
</h3>
|
||||
{securityErrorLints.map((lint, index) => {
|
||||
return (
|
||||
<Button
|
||||
size="small"
|
||||
type="text"
|
||||
className="w-full justify-start"
|
||||
icon={<Shield strokeWidth={1.5} size={14} className="text-warning" />}
|
||||
onClick={() => {
|
||||
onValueChange(createLintSummaryPrompt(lint))
|
||||
onFocusInput?.()
|
||||
}}
|
||||
>
|
||||
{lint.detail ? lint.detail.replace(/`/g, '') : lint.title}
|
||||
</Button>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div>
|
||||
<h3 className="heading-meta text-foreground-light mb-3 mx-4">Ideas</h3>
|
||||
{prompts.map((item, index) => (
|
||||
<Button
|
||||
size="small"
|
||||
type="text"
|
||||
className="w-full justify-start"
|
||||
icon={
|
||||
<FileText strokeWidth={1.5} size={14} className="text-foreground-light" />
|
||||
}
|
||||
onClick={() => {
|
||||
onValueChange(item.prompt)
|
||||
onFocusInput?.()
|
||||
}}
|
||||
>
|
||||
{item.title}
|
||||
</Button>
|
||||
))}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in new issue
Block a user