diff --git a/src/components/assistant-select/create-edit-assistant-dialog.tsx b/src/components/assistant-select/create-edit-assistant-dialog.tsx index 59dd3406..c739544a 100644 --- a/src/components/assistant-select/create-edit-assistant-dialog.tsx +++ b/src/components/assistant-select/create-edit-assistant-dialog.tsx @@ -15,10 +15,12 @@ import { Label } from "../ui/label"; import { Input } from "../ui/input"; import { IconSelect } from "./icon-select"; import React from "react"; +import { useToast } from "@/hooks/use-toast"; interface CreateEditAssistantDialogProps { open: boolean; setOpen: Dispatch>; + userId: string | undefined; isEditing: boolean; assistant?: Assistant; createCustomAssistant: ( @@ -37,6 +39,7 @@ interface CreateEditAssistantDialogProps { export function CreateEditAssistantDialog( props: CreateEditAssistantDialogProps ) { + const { toast } = useToast(); const [name, setName] = useState(""); const [description, setDescription] = useState(""); const [iconName, setIconName] = useState("User"); @@ -45,6 +48,41 @@ export function CreateEditAssistantDialog( const handleSubmit = async (e: FormEvent) => { e.preventDefault(); + if (!props.userId) { + toast({ + title: "User not found", + variant: "destructive", + duration: 5000, + }); + return; + } + + const res = await props.createCustomAssistant( + { + name, + description, + iconData: { + iconName, + iconColor, + }, + }, + props.userId + ); + + if (res) { + toast({ + title: "Assistant created successfully", + duration: 5000, + }); + } else { + toast({ + title: "Failed to create assistant", + variant: "destructive", + duration: 5000, + }); + } + + props.setOpen(false); }; const handleClearState = () => { diff --git a/src/components/assistant-select/index.tsx b/src/components/assistant-select/index.tsx index ddca3be7..da7b9021 100644 --- a/src/components/assistant-select/index.tsx +++ b/src/components/assistant-select/index.tsx @@ -14,15 +14,8 @@ import { TooltipIconButton } from "../ui/assistant-ui/tooltip-icon-button"; import { useGraphContext } from "@/contexts/GraphContext"; import { Assistant } from "@langchain/langgraph-sdk"; import { CreateEditAssistantDialog } from "./create-edit-assistant-dialog"; - -const getIcon = (iconName?: string) => { - if (iconName && Icons[iconName as keyof typeof Icons]) { - return React.createElement( - Icons[iconName as keyof typeof Icons] as React.ElementType - ); - } - return React.createElement(Icons.User); -}; +import { cn } from "@/lib/utils"; +import { getIcon } from "./utils"; function AssistantItem({ assistant, @@ -35,23 +28,36 @@ function AssistantItem({ }) { const isDefault = assistant.metadata?.is_default as boolean | undefined; const isSelected = assistant.assistant_id === selectedAssistantId; + const metadata = assistant.metadata as Record; return ( - {isSelected && <>•} - {getIcon(assistant.metadata?.iconName as string | undefined)} + + {getIcon(metadata?.iconData?.iconName as string | undefined)} + {assistant.name} {isDefault && ( - {"(default)"} + {"(default)"} )} + {isSelected && } ); } -function AssistantSelectComponent() { +interface AssistantSelectProps { + userId: string | undefined; +} + +function AssistantSelectComponent(props: AssistantSelectProps) { const [open, setOpen] = useState(false); const [createEditDialogOpen, setCreateEditDialogOpen] = useState(false); const { @@ -71,6 +77,8 @@ function AssistantSelectComponent() { setCreateEditDialogOpen(true); }; + const metadata = selectedAssistant?.metadata as Record; + return ( <> @@ -80,10 +88,9 @@ function AssistantSelectComponent() { variant="ghost" delayDuration={200} className="w-8 h-8 transition-colors ease-in-out duration-200" + style={{ color: metadata?.iconData?.iconColor || "#4b5563" }} > - {getIcon( - selectedAssistant?.metadata?.iconName as string | undefined - )} + {getIcon(metadata?.iconData?.iconName as string | undefined)} @@ -100,7 +107,7 @@ function AssistantSelectComponent() { <> New @@ -128,9 +135,30 @@ function AssistantSelectComponent() { { + const res = await createCustomAssistant( + newAssistant, + userId, + successCallback + ); + setOpen(false); + return res; + }} + editCustomAssistant={async (editedAssistant, assistantId, userId) => { + const res = await editCustomAssistant( + editedAssistant, + assistantId, + userId + ); + setOpen(false); + return res; + }} isLoading={isLoadingAllAssistants} /> diff --git a/src/components/assistant-select/utils.tsx b/src/components/assistant-select/utils.tsx new file mode 100644 index 00000000..3320c7ae --- /dev/null +++ b/src/components/assistant-select/utils.tsx @@ -0,0 +1,11 @@ +import * as Icons from "lucide-react"; +import React from "react"; + +export const getIcon = (iconName?: string) => { + if (iconName && Icons[iconName as keyof typeof Icons]) { + return React.createElement( + Icons[iconName as keyof typeof Icons] as React.ElementType + ); + } + return React.createElement(Icons.User); +}; diff --git a/src/components/canvas/content-composer.tsx b/src/components/canvas/content-composer.tsx index 785f8b9e..a79c8aa1 100644 --- a/src/components/canvas/content-composer.tsx +++ b/src/components/canvas/content-composer.tsx @@ -94,6 +94,7 @@ export function ContentComposerChatInterfaceComponent(
{ ); }; -export const Composer: FC = () => { +interface ComposerProps { + userId: string | undefined; +} + +export const Composer: FC = (props: ComposerProps) => { return ( - + { }; export interface ThreadProps { + userId: string | undefined; hasChatStarted: boolean; handleQuickStart: ( type: "text" | "code", @@ -107,7 +108,7 @@ export const Thread: FC = (props: ThreadProps) => { ) : (
- +
)}
@@ -115,7 +116,7 @@ export const Thread: FC = (props: ThreadProps) => { {!hasChatStarted && ( } + composer={} /> )} = (props: ThreadProps) => { modelName={modelName} setModelName={setModelName} /> - + )} diff --git a/src/components/reflections-dialog/ReflectionsDialog.tsx b/src/components/reflections-dialog/ReflectionsDialog.tsx index 34c1a484..afadea76 100644 --- a/src/components/reflections-dialog/ReflectionsDialog.tsx +++ b/src/components/reflections-dialog/ReflectionsDialog.tsx @@ -14,18 +14,21 @@ import { TooltipIconButton } from "../ui/assistant-ui/tooltip-icon-button"; import { TighterText } from "../ui/header"; import { useStore } from "@/hooks/useStore"; import { useToast } from "@/hooks/use-toast"; +import { Assistant } from "@langchain/langgraph-sdk"; +import { Badge } from "../ui/badge"; +import { getIcon } from "../assistant-select/utils"; export interface NoReflectionsProps { - assistantId: string | undefined; + selectedAssistant: Assistant | undefined; getReflections: (assistantId: string) => Promise; } function NoReflections(props: NoReflectionsProps) { - const { assistantId } = props; + const { selectedAssistant } = props; const { toast } = useToast(); const getReflections = async () => { - if (!assistantId) { + if (!selectedAssistant) { toast({ title: "Error", description: "Assistant ID not found.", @@ -34,7 +37,7 @@ function NoReflections(props: NoReflectionsProps) { }); return; } - await props.getReflections(assistantId); + await props.getReflections(selectedAssistant.assistant_id); }; return ( @@ -52,13 +55,13 @@ function NoReflections(props: NoReflectionsProps) { } interface ReflectionsDialogProps { - assistantId: string | undefined; + selectedAssistant: Assistant | undefined; } export function ReflectionsDialog(props: ReflectionsDialogProps) { const { toast } = useToast(); const [open, setOpen] = useState(false); - const { assistantId } = props; + const { selectedAssistant } = props; const { isLoadingReflections, reflections, @@ -67,19 +70,19 @@ export function ReflectionsDialog(props: ReflectionsDialogProps) { } = useStore(); useEffect(() => { - if (!assistantId || typeof window === "undefined") return; + if (!selectedAssistant || typeof window === "undefined") return; // Don't re-fetch reflections if they already exist & are for the same assistant if ( (reflections?.content || reflections?.styleRules) && - reflections.assistantId === assistantId + reflections.assistantId === selectedAssistant.assistant_id ) return; - getReflections(assistantId); - }, [assistantId]); + getReflections(selectedAssistant.assistant_id); + }, [selectedAssistant]); const handleDelete = async () => { - if (!assistantId) { + if (!selectedAssistant) { toast({ title: "Error", description: "Assistant ID not found.", @@ -89,9 +92,12 @@ export function ReflectionsDialog(props: ReflectionsDialogProps) { return false; } setOpen(false); - return await deleteReflections(assistantId); + return await deleteReflections(selectedAssistant.assistant_id); }; + const iconData = (selectedAssistant?.metadata as Record) + ?.iconData; + return ( @@ -106,8 +112,34 @@ export function ReflectionsDialog(props: ReflectionsDialogProps) { - - Reflections + + + Reflections + + {selectedAssistant && ( + + + {getIcon( + (selectedAssistant?.metadata as Record) + ?.iconData?.iconName + )} + + {selectedAssistant?.name} + + )} @@ -117,7 +149,7 @@ export function ReflectionsDialog(props: ReflectionsDialogProps) { "Current reflections generated by the assistant for content generation." ) : ( )} diff --git a/src/components/ui/badge.tsx b/src/components/ui/badge.tsx new file mode 100644 index 00000000..fd92f29c --- /dev/null +++ b/src/components/ui/badge.tsx @@ -0,0 +1,36 @@ +import * as React from "react"; +import { cva, type VariantProps } from "class-variance-authority"; + +import { cn } from "@/lib/utils"; + +const badgeVariants = cva( + "inline-flex items-center rounded-md border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2", + { + variants: { + variant: { + default: + "border-transparent bg-primary text-primary-foreground shadow hover:bg-primary/80", + secondary: + "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80", + destructive: + "border-transparent bg-destructive text-destructive-foreground shadow hover:bg-destructive/80", + outline: "text-foreground", + }, + }, + defaultVariants: { + variant: "default", + }, + } +); + +export interface BadgeProps + extends React.HTMLAttributes, + VariantProps {} + +function Badge({ className, variant, ...props }: BadgeProps) { + return ( +
+ ); +} + +export { Badge, badgeVariants };