feat(UI): Adding linter and prettier for UI (#3156)

This commit is contained in:
Francisco Arceo 2025-08-14 15:58:43 -06:00 committed by GitHub
parent 61582f327c
commit e69acbafbf
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
73 changed files with 1452 additions and 1226 deletions

View file

@ -1,4 +1,4 @@
"use client"
"use client";
import {
forwardRef,
@ -6,48 +6,48 @@ import {
useRef,
useState,
type ReactElement,
} from "react"
import { ArrowDown, ThumbsDown, ThumbsUp } from "lucide-react"
} from "react";
import { ArrowDown, ThumbsDown, ThumbsUp } from "lucide-react";
import { cn } from "@/lib/utils"
import { useAutoScroll } from "@/hooks/use-auto-scroll"
import { Button } from "@/components/ui/button"
import { type Message } from "@/components/chat-playground/chat-message"
import { CopyButton } from "@/components/ui/copy-button"
import { MessageInput } from "@/components/chat-playground/message-input"
import { MessageList } from "@/components/chat-playground/message-list"
import { PromptSuggestions } from "@/components/chat-playground/prompt-suggestions"
import { cn } from "@/lib/utils";
import { useAutoScroll } from "@/hooks/use-auto-scroll";
import { Button } from "@/components/ui/button";
import { type Message } from "@/components/chat-playground/chat-message";
import { CopyButton } from "@/components/ui/copy-button";
import { MessageInput } from "@/components/chat-playground/message-input";
import { MessageList } from "@/components/chat-playground/message-list";
import { PromptSuggestions } from "@/components/chat-playground/prompt-suggestions";
interface ChatPropsBase {
handleSubmit: (
event?: { preventDefault?: () => void },
options?: { experimental_attachments?: FileList }
) => void
messages: Array<Message>
input: string
className?: string
handleInputChange: React.ChangeEventHandler<HTMLTextAreaElement>
isGenerating: boolean
stop?: () => void
) => void;
messages: Array<Message>;
input: string;
className?: string;
handleInputChange: React.ChangeEventHandler<HTMLTextAreaElement>;
isGenerating: boolean;
stop?: () => void;
onRateResponse?: (
messageId: string,
rating: "thumbs-up" | "thumbs-down"
) => void
setMessages?: (messages: any[]) => void
transcribeAudio?: (blob: Blob) => Promise<string>
) => void;
setMessages?: (messages: Message[]) => void;
transcribeAudio?: (blob: Blob) => Promise<string>;
}
interface ChatPropsWithoutSuggestions extends ChatPropsBase {
append?: never
suggestions?: never
append?: never;
suggestions?: never;
}
interface ChatPropsWithSuggestions extends ChatPropsBase {
append: (message: { role: "user"; content: string }) => void
suggestions: string[]
append: (message: { role: "user"; content: string }) => void;
suggestions: string[];
}
type ChatProps = ChatPropsWithoutSuggestions | ChatPropsWithSuggestions
type ChatProps = ChatPropsWithoutSuggestions | ChatPropsWithSuggestions;
export function Chat({
messages,
@ -63,34 +63,34 @@ export function Chat({
setMessages,
transcribeAudio,
}: ChatProps) {
const lastMessage = messages.at(-1)
const isEmpty = messages.length === 0
const isTyping = lastMessage?.role === "user"
const lastMessage = messages.at(-1);
const isEmpty = messages.length === 0;
const isTyping = lastMessage?.role === "user";
const messagesRef = useRef(messages)
messagesRef.current = messages
const messagesRef = useRef(messages);
messagesRef.current = messages;
// Enhanced stop function that marks pending tool calls as cancelled
const handleStop = useCallback(() => {
stop?.()
stop?.();
if (!setMessages) return
if (!setMessages) return;
const latestMessages = [...messagesRef.current]
const latestMessages = [...messagesRef.current];
const lastAssistantMessage = latestMessages.findLast(
(m) => m.role === "assistant"
)
m => m.role === "assistant"
);
if (!lastAssistantMessage) return
if (!lastAssistantMessage) return;
let needsUpdate = false
let updatedMessage = { ...lastAssistantMessage }
let needsUpdate = false;
let updatedMessage = { ...lastAssistantMessage };
if (lastAssistantMessage.toolInvocations) {
const updatedToolInvocations = lastAssistantMessage.toolInvocations.map(
(toolInvocation) => {
toolInvocation => {
if (toolInvocation.state === "call") {
needsUpdate = true
needsUpdate = true;
return {
...toolInvocation,
state: "result",
@ -98,61 +98,66 @@ export function Chat({
content: "Tool execution was cancelled",
__cancelled: true, // Special marker to indicate cancellation
},
} as const
} as const;
}
return toolInvocation
return toolInvocation;
}
)
);
if (needsUpdate) {
updatedMessage = {
...updatedMessage,
toolInvocations: updatedToolInvocations,
}
};
}
}
if (lastAssistantMessage.parts && lastAssistantMessage.parts.length > 0) {
const updatedParts = lastAssistantMessage.parts.map((part: any) => {
if (
part.type === "tool-invocation" &&
part.toolInvocation &&
part.toolInvocation.state === "call"
) {
needsUpdate = true
return {
...part,
toolInvocation: {
...part.toolInvocation,
state: "result",
result: {
content: "Tool execution was cancelled",
__cancelled: true,
const updatedParts = lastAssistantMessage.parts.map(
(part: {
type: string;
toolInvocation?: { state: string; toolName: string };
}) => {
if (
part.type === "tool-invocation" &&
part.toolInvocation &&
part.toolInvocation.state === "call"
) {
needsUpdate = true;
return {
...part,
toolInvocation: {
...part.toolInvocation,
state: "result",
result: {
content: "Tool execution was cancelled",
__cancelled: true,
},
},
},
};
}
return part;
}
return part
})
);
if (needsUpdate) {
updatedMessage = {
...updatedMessage,
parts: updatedParts,
}
};
}
}
if (needsUpdate) {
const messageIndex = latestMessages.findIndex(
(m) => m.id === lastAssistantMessage.id
)
m => m.id === lastAssistantMessage.id
);
if (messageIndex !== -1) {
latestMessages[messageIndex] = updatedMessage
setMessages(latestMessages)
latestMessages[messageIndex] = updatedMessage;
setMessages(latestMessages);
}
}
}, [stop, setMessages, messagesRef])
}, [stop, setMessages, messagesRef]);
const messageOptions = useCallback(
(message: Message) => ({
@ -189,7 +194,7 @@ export function Chat({
),
}),
[onRateResponse]
)
);
return (
<ChatContainer className={className}>
@ -237,15 +242,15 @@ export function Chat({
</div>
</div>
</ChatContainer>
)
);
}
Chat.displayName = "Chat"
Chat.displayName = "Chat";
export function ChatMessages({
messages,
children,
}: React.PropsWithChildren<{
messages: Message[]
messages: Message[];
}>) {
const {
containerRef,
@ -253,7 +258,7 @@ export function ChatMessages({
handleScroll,
shouldAutoScroll,
handleTouchStart,
} = useAutoScroll([messages])
} = useAutoScroll([messages]);
return (
<div
@ -281,7 +286,7 @@ export function ChatMessages({
</div>
)}
</div>
)
);
}
export const ChatContainer = forwardRef<
@ -294,56 +299,56 @@ export const ChatContainer = forwardRef<
className={cn("flex flex-col max-h-full w-full", className)}
{...props}
/>
)
})
ChatContainer.displayName = "ChatContainer"
);
});
ChatContainer.displayName = "ChatContainer";
interface ChatFormProps {
className?: string
isPending: boolean
className?: string;
isPending: boolean;
handleSubmit: (
event?: { preventDefault?: () => void },
options?: { experimental_attachments?: FileList }
) => void
) => void;
children: (props: {
files: File[] | null
setFiles: React.Dispatch<React.SetStateAction<File[] | null>>
}) => ReactElement
files: File[] | null;
setFiles: React.Dispatch<React.SetStateAction<File[] | null>>;
}) => ReactElement;
}
export const ChatForm = forwardRef<HTMLFormElement, ChatFormProps>(
({ children, handleSubmit, isPending, className }, ref) => {
const [files, setFiles] = useState<File[] | null>(null)
const [files, setFiles] = useState<File[] | null>(null);
const onSubmit = (event: React.FormEvent) => {
// if (isPending) {
// event.preventDefault()
// return
// }
if (!files) {
handleSubmit(event)
return
if (isPending) {
event.preventDefault();
return;
}
const fileList = createFileList(files)
handleSubmit(event, { experimental_attachments: fileList })
setFiles(null)
}
if (!files) {
handleSubmit(event);
return;
}
const fileList = createFileList(files);
handleSubmit(event, { experimental_attachments: fileList });
setFiles(null);
};
return (
<form ref={ref} onSubmit={onSubmit} className={className}>
{children({ files, setFiles })}
</form>
)
);
}
)
ChatForm.displayName = "ChatForm"
);
ChatForm.displayName = "ChatForm";
function createFileList(files: File[] | FileList): FileList {
const dataTransfer = new DataTransfer()
const dataTransfer = new DataTransfer();
for (const file of Array.from(files)) {
dataTransfer.items.add(file)
dataTransfer.items.add(file);
}
return dataTransfer.files
return dataTransfer.files;
}