fix: actions

This commit is contained in:
shadcn 2023-06-16 21:52:01 +04:00
parent 071778533c
commit cb941daca9
17 changed files with 277 additions and 65 deletions

View file

@ -1,10 +1,11 @@
'use client'
import { type Message } from 'ai-connector'
import { Button } from '@/components/ui/button'
import { IconCheck, IconCopy } from '@/components/ui/icons'
import { useCopyToClipboard } from '@/lib/hooks/use-copy-to-clipboard'
import { cn } from '@/lib/utils'
import { type Message } from 'ai-connector'
interface ChatMessageActionsProps extends React.ComponentProps<'div'> {
message: Message

View file

@ -1,7 +1,6 @@
import { type UseChatHelpers } from 'ai-connector/react'
import { Button } from '@/components/ui/button'
import { ExternalLink } from '@/components/external-link'
import { PromptForm } from '@/components/prompt-form'
import { ButtonScrollToBottom } from '@/components/button-scroll-to-bottom'
import { IconRefresh, IconStop } from '@/components/ui/icons'

View file

@ -10,11 +10,10 @@ import { ChatScrollAnchor } from '@/components/chat-scroll-anchor'
export interface ChatProps extends React.ComponentProps<'div'> {
initialMessages?: Message[]
id?: string
}
export function Chat({ id, title, initialMessages, className }: ChatProps) {
export function Chat({ id, initialMessages, className }: ChatProps) {
const { messages, append, reload, stop, isLoading, input, setInput } =
useChat({
initialMessages,

View file

@ -2,7 +2,9 @@
import * as React from 'react'
import { useRouter } from 'next/navigation'
import { toast } from 'react-hot-toast'
import { ServerActionResult } from '@/lib/types'
import { Button } from '@/components/ui/button'
import {
AlertDialog,
@ -18,7 +20,7 @@ import {
import { IconSpinner } from '@/components/ui/icons'
interface ClearHistoryProps {
clearChats: () => Promise<void>
clearChats: () => ServerActionResult<void>
}
export function ClearHistory({ clearChats }: ClearHistoryProps) {
@ -49,7 +51,13 @@ export function ClearHistory({ clearChats }: ClearHistoryProps) {
onClick={event => {
event.preventDefault()
startTransition(async () => {
await clearChats()
const result = await clearChats()
if (result && 'error' in result) {
toast.error(result.error)
return
}
setOpen(false)
router.push('/')
})

View file

@ -1,7 +1,7 @@
import React from 'react'
import { ExternalLink } from '@/components/external-link'
import { cn } from '@/lib/utils'
import { ExternalLink } from '@/components/external-link'
export function FooterText({ className, ...props }: React.ComponentProps<'p'>) {
return (

View file

@ -1,19 +1,18 @@
import { Suspense, use } from 'react'
import * as React from 'react'
import Link from 'next/link'
import { cn } from '@/lib/utils'
import { auth } from '@/auth'
import { clearChats } from '@/app/actions'
import { buttonVariants } from '@/components/ui/button'
import { Sidebar } from '@/components/sidebar'
import { SidebarList } from '@/components/sidebar-list'
import { IconGitHub, IconSeparator, IconVercel } from '@/components/ui/icons'
import { SidebarFooter } from '@/components/sidebar-footer'
import { ThemeToggle } from '@/components/theme-toggle'
import { ClearHistory } from '@/components/clear-history'
import { clearChats } from '@/app/actions'
import Link from 'next/link'
import { auth } from '@/auth'
import { UserMenu } from './user-menu'
import { LoginButton } from './login-button'
import { UserMenu } from '@/components/user-menu'
import { LoginButton } from '@/components/login-button'
export async function Header() {
const session = await auth()
@ -22,10 +21,10 @@ export async function Header() {
<div className="flex items-center">
{session?.user ? (
<Sidebar>
<Suspense fallback={<div className="flex-1 overflow-auto" />}>
<React.Suspense fallback={<div className="flex-1 overflow-auto" />}>
{/* @ts-ignore */}
<SidebarList userId={session?.user?.id} />
</Suspense>
</React.Suspense>
<SidebarFooter>
<ThemeToggle />
<ClearHistory clearChats={clearChats} />

View file

@ -3,6 +3,7 @@
import * as React from 'react'
import { ThemeProvider as NextThemesProvider } from 'next-themes'
import { ThemeProviderProps } from 'next-themes/dist/types'
import { TooltipProvider } from '@/components/ui/tooltip'
export function Providers({ children, ...props }: ThemeProviderProps) {

View file

@ -41,7 +41,7 @@ import {
interface SidebarActionsProps {
chat: Chat
removeChat: (args: { id: string; path: string }) => Promise<void>
removeChat: (args: { id: string; path: string }) => ServerActionResult<void>
shareChat: (chat: Chat) => ServerActionResult<Chat>
}
@ -150,8 +150,8 @@ export function SidebarActions({
const result = await shareChat(chat)
if (!('id' in result)) {
toast.error(result.message)
if (result && 'error' in result) {
toast.error(result.error)
return
}
@ -189,10 +189,16 @@ export function SidebarActions({
onClick={event => {
event.preventDefault()
startRemoveTransition(async () => {
await removeChat({
const result = await removeChat({
id: chat.id,
path: chat.path
})
if (result && 'error' in result) {
toast.error(result.error)
return
}
setDeleteDialogOpen(false)
router.push('/')
})

View file

@ -1,6 +1,5 @@
import { getChats, removeChat, shareChat } from '@/app/actions'
import { SidebarActions } from '@/components/sidebar-actions'
import { SidebarItem } from '@/components/sidebar-item'
export interface SidebarListProps {

View file

@ -459,6 +459,23 @@ function IconExternalLink({
)
}
function IconChevronUpDown({
className,
...props
}: React.ComponentProps<'svg'>) {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
fill="currentColor"
className={cn('h-4 w-4', className)}
viewBox="0 0 256 256"
{...props}
>
<path d="M181.66 170.34a8 8 0 0 1 0 11.32l-48 48a8 8 0 0 1-11.32 0l-48-48a8 8 0 0 1 11.32-11.32L128 212.69l42.34-42.35a8 8 0 0 1 11.32 0Zm-96-84.68L128 43.31l42.34 42.35a8 8 0 0 0 11.32-11.32l-48-48a8 8 0 0 0-11.32 0l-48 48a8 8 0 0 0 11.32 11.32Z" />
</svg>
)
}
export {
IconEdit,
IconNextChat,
@ -485,5 +502,6 @@ export {
IconClose,
IconShare,
IconUsers,
IconExternalLink
IconExternalLink,
IconChevronUpDown
}

123
components/ui/select.tsx Normal file
View file

@ -0,0 +1,123 @@
'use client'
import * as React from 'react'
import * as SelectPrimitive from '@radix-ui/react-select'
import { cn } from '@/lib/utils'
import {
IconArrowDown,
IconCheck,
IconChevronUpDown
} from '@/components/ui/icons'
const Select = SelectPrimitive.Root
const SelectGroup = SelectPrimitive.Group
const SelectValue = SelectPrimitive.Value
const SelectTrigger = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.Trigger>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Trigger>
>(({ className, children, ...props }, ref) => (
<SelectPrimitive.Trigger
ref={ref}
className={cn(
'flex h-9 w-full items-center justify-between rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50',
className
)}
{...props}
>
{children}
<SelectPrimitive.Icon asChild>
<IconChevronUpDown className="opacity-50" />
</SelectPrimitive.Icon>
</SelectPrimitive.Trigger>
))
SelectTrigger.displayName = SelectPrimitive.Trigger.displayName
const SelectContent = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Content>
>(({ className, children, position = 'popper', ...props }, ref) => (
<SelectPrimitive.Portal>
<SelectPrimitive.Content
ref={ref}
className={cn(
'relative z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md animate-in fade-in-80',
position === 'popper' && 'translate-y-1',
className
)}
position={position}
{...props}
>
<SelectPrimitive.Viewport
className={cn(
'p-1',
position === 'popper' &&
'h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]'
)}
>
{children}
</SelectPrimitive.Viewport>
</SelectPrimitive.Content>
</SelectPrimitive.Portal>
))
SelectContent.displayName = SelectPrimitive.Content.displayName
const SelectLabel = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.Label>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Label>
>(({ className, ...props }, ref) => (
<SelectPrimitive.Label
ref={ref}
className={cn('py-1.5 pl-8 pr-2 text-sm font-semibold', className)}
{...props}
/>
))
SelectLabel.displayName = SelectPrimitive.Label.displayName
const SelectItem = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.Item>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Item>
>(({ className, children, ...props }, ref) => (
<SelectPrimitive.Item
ref={ref}
className={cn(
'relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
className
)}
{...props}
>
<span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
<SelectPrimitive.ItemIndicator>
<IconCheck className="h-4 w-4" />
</SelectPrimitive.ItemIndicator>
</span>
<SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
</SelectPrimitive.Item>
))
SelectItem.displayName = SelectPrimitive.Item.displayName
const SelectSeparator = React.forwardRef<
React.ElementRef<typeof SelectPrimitive.Separator>,
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Separator>
>(({ className, ...props }, ref) => (
<SelectPrimitive.Separator
ref={ref}
className={cn('-mx-1 my-1 h-px bg-muted', className)}
{...props}
/>
))
SelectSeparator.displayName = SelectPrimitive.Separator.displayName
export {
Select,
SelectGroup,
SelectValue,
SelectTrigger,
SelectContent,
SelectLabel,
SelectItem,
SelectSeparator
}