路由嵌套修改

This commit is contained in:
fengxiangdebaozi committed 2026-05-14 19:25:39 +08:00
1 parent 8ecc32da6d
commit d6ec0afbd6
16 files changed
+453 -376

No files matched your search

+10 -8
View File
@@ -31,23 +31,25 @@ function BreadcrumbItem({ className, ...props }: React.ComponentProps<"li">) {
); );
} }
function BreadcrumbLink({ const BreadcrumbLink = React.forwardRef<
asChild, HTMLAnchorElement,
className, React.ComponentProps<"a"> & {
...props asChild?: boolean;
}: React.ComponentProps<"a"> & { }
asChild?: boolean; >(({ asChild, className, ...props }, ref) => {
}) {
const Comp = asChild ? Slot : "a"; const Comp = asChild ? Slot : "a";
return ( return (
<Comp <Comp
ref={ref}
data-slot="breadcrumb-link" data-slot="breadcrumb-link"
className={cn("hover:text-foreground transition-colors", className)} className={cn("hover:text-foreground transition-colors", className)}
{...props} {...props}
/> />
); );
} });
BreadcrumbLink.displayName = "BreadcrumbLink";
function BreadcrumbPage({ className, ...props }: React.ComponentProps<"span">) { function BreadcrumbPage({ className, ...props }: React.ComponentProps<"span">) {
return ( return (
+11 -11
View File
@@ -37,20 +37,18 @@ const buttonVariants = cva(
}, },
); );
function Button({ const Button = React.forwardRef<
className, HTMLButtonElement,
variant = "default", React.ComponentProps<"button"> &
size = "default", VariantProps<typeof buttonVariants> & {
asChild = false, asChild?: boolean;
...props }
}: React.ComponentProps<"button"> & >(({ className, variant = "default", size = "default", asChild = false, ...props }, ref) => {
VariantProps<typeof buttonVariants> & {
asChild?: boolean;
}) {
const Comp = asChild ? Slot : "button"; const Comp = asChild ? Slot : "button";
return ( return (
<Comp <Comp
ref={ref}
data-slot="button" data-slot="button"
{...(variant !== undefined && { "data-variant": variant })} {...(variant !== undefined && { "data-variant": variant })}
{...(size !== undefined && { "data-size": size })} {...(size !== undefined && { "data-size": size })}
@@ -58,6 +56,8 @@ function Button({
{...props} {...props}
/> />
); );
} });
Button.displayName = "Button";
export { Button, buttonVariants }; export { Button, buttonVariants };
+19 -9
View File
@@ -1,5 +1,6 @@
"use client"; "use client";
import * as React from "react";
import * as CollapsiblePrimitive from "@radix-ui/react-collapsible"; import * as CollapsiblePrimitive from "@radix-ui/react-collapsible";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
@@ -10,28 +11,37 @@ function Collapsible({
return <CollapsiblePrimitive.Root data-slot="collapsible" {...props} />; return <CollapsiblePrimitive.Root data-slot="collapsible" {...props} />;
} }
function CollapsibleTrigger({ const CollapsibleTrigger = React.forwardRef<
className, React.ElementRef<typeof CollapsiblePrimitive.CollapsibleTrigger>,
...props React.ComponentPropsWithoutRef<typeof CollapsiblePrimitive.CollapsibleTrigger>
}: React.ComponentProps<typeof CollapsiblePrimitive.CollapsibleTrigger>) { >(({ className, ...props }, ref) => {
return ( return (
<CollapsiblePrimitive.CollapsibleTrigger <CollapsiblePrimitive.CollapsibleTrigger
ref={ref}
data-slot="collapsible-trigger" data-slot="collapsible-trigger"
className={cn("cursor-pointer", className)} className={cn("cursor-pointer", className)}
{...props} {...props}
/> />
); );
} });
function CollapsibleContent({ CollapsibleTrigger.displayName =
...props CollapsiblePrimitive.CollapsibleTrigger.displayName;
}: React.ComponentProps<typeof CollapsiblePrimitive.CollapsibleContent>) {
const CollapsibleContent = React.forwardRef<
React.ElementRef<typeof CollapsiblePrimitive.CollapsibleContent>,
React.ComponentPropsWithoutRef<typeof CollapsiblePrimitive.CollapsibleContent>
>(({ ...props }, ref) => {
return ( return (
<CollapsiblePrimitive.CollapsibleContent <CollapsiblePrimitive.CollapsibleContent
ref={ref}
data-slot="collapsible-content" data-slot="collapsible-content"
{...props} {...props}
/> />
); );
} });
CollapsibleContent.displayName =
CollapsiblePrimitive.CollapsibleContent.displayName;
export { Collapsible, CollapsibleTrigger, CollapsibleContent }; export { Collapsible, CollapsibleTrigger, CollapsibleContent };
+40 -24
View File
@@ -12,11 +12,20 @@ function Dialog({
return <DialogPrimitive.Root data-slot="dialog" {...props} />; return <DialogPrimitive.Root data-slot="dialog" {...props} />;
} }
function DialogTrigger({ const DialogTrigger = React.forwardRef<
...props React.ElementRef<typeof DialogPrimitive.Trigger>,
}: React.ComponentProps<typeof DialogPrimitive.Trigger>) { React.ComponentPropsWithoutRef<typeof DialogPrimitive.Trigger>
return <DialogPrimitive.Trigger data-slot="dialog-trigger" {...props} />; >(({ ...props }, ref) => {
} return (
<DialogPrimitive.Trigger
ref={ref}
data-slot="dialog-trigger"
{...props}
/>
);
});
DialogTrigger.displayName = DialogPrimitive.Trigger.displayName;
function DialogPortal({ function DialogPortal({
...props ...props
@@ -24,18 +33,22 @@ function DialogPortal({
return <DialogPrimitive.Portal data-slot="dialog-portal" {...props} />; return <DialogPrimitive.Portal data-slot="dialog-portal" {...props} />;
} }
function DialogClose({ const DialogClose = React.forwardRef<
...props React.ElementRef<typeof DialogPrimitive.Close>,
}: React.ComponentProps<typeof DialogPrimitive.Close>) { React.ComponentPropsWithoutRef<typeof DialogPrimitive.Close>
return <DialogPrimitive.Close data-slot="dialog-close" {...props} />; >(({ ...props }, ref) => {
} return <DialogPrimitive.Close ref={ref} data-slot="dialog-close" {...props} />;
});
function DialogOverlay({ DialogClose.displayName = DialogPrimitive.Close.displayName;
className,
...props const DialogOverlay = React.forwardRef<
}: React.ComponentProps<typeof DialogPrimitive.Overlay>) { React.ElementRef<typeof DialogPrimitive.Overlay>,
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>
>(({ className, ...props }, ref) => {
return ( return (
<DialogPrimitive.Overlay <DialogPrimitive.Overlay
ref={ref}
data-slot="dialog-overlay" data-slot="dialog-overlay"
className={cn( className={cn(
"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50", "data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50",
@@ -44,20 +57,21 @@ function DialogOverlay({
{...props} {...props}
/> />
); );
} });
function DialogContent({ DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
className,
children, const DialogContent = React.forwardRef<
showCloseButton = true, React.ElementRef<typeof DialogPrimitive.Content>,
...props React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content> & {
}: React.ComponentProps<typeof DialogPrimitive.Content> & { showCloseButton?: boolean;
showCloseButton?: boolean; }
}) { >(({ className, children, showCloseButton = true, ...props }, ref) => {
return ( return (
<DialogPortal data-slot="dialog-portal"> <DialogPortal data-slot="dialog-portal">
<DialogOverlay /> <DialogOverlay />
<DialogPrimitive.Content <DialogPrimitive.Content
ref={ref}
data-slot="dialog-content" data-slot="dialog-content"
className={cn( className={cn(
"bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border p-6 shadow-lg duration-200 outline-none sm:max-w-lg", "bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border p-6 shadow-lg duration-200 outline-none sm:max-w-lg",
@@ -78,7 +92,9 @@ function DialogContent({
</DialogPrimitive.Content> </DialogPrimitive.Content>
</DialogPortal> </DialogPortal>
); );
} });
DialogContent.displayName = DialogPrimitive.Content.displayName;
function DialogHeader({ className, ...props }: React.ComponentProps<"div">) { function DialogHeader({ className, ...props }: React.ComponentProps<"div">) {
return ( return (
@@ -20,25 +20,29 @@ function DropdownMenuPortal({
); );
} }
function DropdownMenuTrigger({ const DropdownMenuTrigger = React.forwardRef<
...props React.ElementRef<typeof DropdownMenuPrimitive.Trigger>,
}: React.ComponentProps<typeof DropdownMenuPrimitive.Trigger>) { React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Trigger>
>(({ ...props }, ref) => {
return ( return (
<DropdownMenuPrimitive.Trigger <DropdownMenuPrimitive.Trigger
ref={ref}
data-slot="dropdown-menu-trigger" data-slot="dropdown-menu-trigger"
{...props} {...props}
/> />
); );
} });
function DropdownMenuContent({ DropdownMenuTrigger.displayName = DropdownMenuPrimitive.Trigger.displayName;
className,
sideOffset = 4, const DropdownMenuContent = React.forwardRef<
...props React.ElementRef<typeof DropdownMenuPrimitive.Content>,
}: React.ComponentProps<typeof DropdownMenuPrimitive.Content>) { React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Content>
>(({ className, sideOffset = 4, ...props }, ref) => {
return ( return (
<DropdownMenuPrimitive.Portal> <DropdownMenuPrimitive.Portal>
<DropdownMenuPrimitive.Content <DropdownMenuPrimitive.Content
ref={ref}
data-slot="dropdown-menu-content" data-slot="dropdown-menu-content"
sideOffset={sideOffset} sideOffset={sideOffset}
className={cn( className={cn(
@@ -49,7 +53,9 @@ function DropdownMenuContent({
/> />
</DropdownMenuPrimitive.Portal> </DropdownMenuPrimitive.Portal>
); );
} });
DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName;
function DropdownMenuGroup({ function DropdownMenuGroup({
...props ...props
@@ -59,17 +65,16 @@ function DropdownMenuGroup({
); );
} }
function DropdownMenuItem({ const DropdownMenuItem = React.forwardRef<
className, React.ElementRef<typeof DropdownMenuPrimitive.Item>,
inset, React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> & {
variant = "default", inset?: boolean;
...props variant?: "default" | "destructive";
}: React.ComponentProps<typeof DropdownMenuPrimitive.Item> & { }
inset?: boolean; >(({ className, inset, variant = "default", ...props }, ref) => {
variant?: "default" | "destructive";
}) {
return ( return (
<DropdownMenuPrimitive.Item <DropdownMenuPrimitive.Item
ref={ref}
data-slot="dropdown-menu-item" data-slot="dropdown-menu-item"
data-inset={inset} data-inset={inset}
data-variant={variant} data-variant={variant}
@@ -80,7 +85,9 @@ function DropdownMenuItem({
{...props} {...props}
/> />
); );
} });
DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName;
function DropdownMenuCheckboxItem({ function DropdownMenuCheckboxItem({
className, className,
@@ -198,16 +205,15 @@ function DropdownMenuSub({
return <DropdownMenuPrimitive.Sub data-slot="dropdown-menu-sub" {...props} />; return <DropdownMenuPrimitive.Sub data-slot="dropdown-menu-sub" {...props} />;
} }
function DropdownMenuSubTrigger({ const DropdownMenuSubTrigger = React.forwardRef<
className, React.ElementRef<typeof DropdownMenuPrimitive.SubTrigger>,
inset, React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubTrigger> & {
children, inset?: boolean;
...props }
}: React.ComponentProps<typeof DropdownMenuPrimitive.SubTrigger> & { >(({ className, inset, children, ...props }, ref) => {
inset?: boolean;
}) {
return ( return (
<DropdownMenuPrimitive.SubTrigger <DropdownMenuPrimitive.SubTrigger
ref={ref}
data-slot="dropdown-menu-sub-trigger" data-slot="dropdown-menu-sub-trigger"
data-inset={inset} data-inset={inset}
className={cn( className={cn(
@@ -220,14 +226,18 @@ function DropdownMenuSubTrigger({
<ChevronRightIcon className="ml-auto size-4" /> <ChevronRightIcon className="ml-auto size-4" />
</DropdownMenuPrimitive.SubTrigger> </DropdownMenuPrimitive.SubTrigger>
); );
} });
function DropdownMenuSubContent({ DropdownMenuSubTrigger.displayName =
className, DropdownMenuPrimitive.SubTrigger.displayName;
...props
}: React.ComponentProps<typeof DropdownMenuPrimitive.SubContent>) { const DropdownMenuSubContent = React.forwardRef<
React.ElementRef<typeof DropdownMenuPrimitive.SubContent>,
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubContent>
>(({ className, ...props }, ref) => {
return ( return (
<DropdownMenuPrimitive.SubContent <DropdownMenuPrimitive.SubContent
ref={ref}
data-slot="dropdown-menu-sub-content" data-slot="dropdown-menu-sub-content"
className={cn( className={cn(
"bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-hidden rounded-md border p-1 shadow-lg", "bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-hidden rounded-md border p-1 shadow-lg",
@@ -236,7 +246,10 @@ function DropdownMenuSubContent({
{...props} {...props}
/> />
); );
} });
DropdownMenuSubContent.displayName =
DropdownMenuPrimitive.SubContent.displayName;
export { export {
DropdownMenu, DropdownMenu,
+20 -12
View File
@@ -11,23 +11,29 @@ function HoverCard({
return <HoverCardPrimitive.Root data-slot="hover-card" {...props} />; return <HoverCardPrimitive.Root data-slot="hover-card" {...props} />;
} }
function HoverCardTrigger({ const HoverCardTrigger = React.forwardRef<
...props React.ElementRef<typeof HoverCardPrimitive.Trigger>,
}: React.ComponentProps<typeof HoverCardPrimitive.Trigger>) { React.ComponentPropsWithoutRef<typeof HoverCardPrimitive.Trigger>
>(({ ...props }, ref) => {
return ( return (
<HoverCardPrimitive.Trigger data-slot="hover-card-trigger" {...props} /> <HoverCardPrimitive.Trigger
ref={ref}
data-slot="hover-card-trigger"
{...props}
/>
); );
} });
function HoverCardContent({ HoverCardTrigger.displayName = HoverCardPrimitive.Trigger.displayName;
className,
align = "center", const HoverCardContent = React.forwardRef<
sideOffset = 4, React.ElementRef<typeof HoverCardPrimitive.Content>,
...props React.ComponentPropsWithoutRef<typeof HoverCardPrimitive.Content>
}: React.ComponentProps<typeof HoverCardPrimitive.Content>) { >(({ className, align = "center", sideOffset = 4, ...props }, ref) => {
return ( return (
<HoverCardPrimitive.Portal data-slot="hover-card-portal"> <HoverCardPrimitive.Portal data-slot="hover-card-portal">
<HoverCardPrimitive.Content <HoverCardPrimitive.Content
ref={ref}
data-slot="hover-card-content" data-slot="hover-card-content"
align={align} align={align}
sideOffset={sideOffset} sideOffset={sideOffset}
@@ -39,6 +45,8 @@ function HoverCardContent({
/> />
</HoverCardPrimitive.Portal> </HoverCardPrimitive.Portal>
); );
} });
HoverCardContent.displayName = HoverCardPrimitive.Content.displayName;
export { HoverCard, HoverCardTrigger, HoverCardContent }; export { HoverCard, HoverCardTrigger, HoverCardContent };
+26 -23
View File
@@ -24,16 +24,15 @@ function SelectValue({
return <SelectPrimitive.Value data-slot="select-value" {...props} />; return <SelectPrimitive.Value data-slot="select-value" {...props} />;
} }
function SelectTrigger({ const SelectTrigger = React.forwardRef<
className, React.ElementRef<typeof SelectPrimitive.Trigger>,
size = "default", React.ComponentPropsWithoutRef<typeof SelectPrimitive.Trigger> & {
children, size?: "sm" | "default";
...props }
}: React.ComponentProps<typeof SelectPrimitive.Trigger> & { >(({ className, size = "default", children, ...props }, ref) => {
size?: "sm" | "default";
}) {
return ( return (
<SelectPrimitive.Trigger <SelectPrimitive.Trigger
ref={ref}
data-slot="select-trigger" data-slot="select-trigger"
data-size={size} data-size={size}
className={cn( className={cn(
@@ -48,18 +47,18 @@ function SelectTrigger({
</SelectPrimitive.Icon> </SelectPrimitive.Icon>
</SelectPrimitive.Trigger> </SelectPrimitive.Trigger>
); );
} });
function SelectContent({ SelectTrigger.displayName = SelectPrimitive.Trigger.displayName;
className,
children, const SelectContent = React.forwardRef<
position = "item-aligned", React.ElementRef<typeof SelectPrimitive.Content>,
align = "center", React.ComponentPropsWithoutRef<typeof SelectPrimitive.Content>
...props >(({ className, children, position = "item-aligned", align = "center", ...props }, ref) => {
}: React.ComponentProps<typeof SelectPrimitive.Content>) {
return ( return (
<SelectPrimitive.Portal> <SelectPrimitive.Portal>
<SelectPrimitive.Content <SelectPrimitive.Content
ref={ref}
data-slot="select-content" data-slot="select-content"
className={cn( className={cn(
"bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 relative z-50 max-h-(--radix-select-content-available-height) min-w-[8rem] origin-(--radix-select-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border shadow-md", "bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 relative z-50 max-h-(--radix-select-content-available-height) min-w-[8rem] origin-(--radix-select-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border shadow-md",
@@ -85,7 +84,9 @@ function SelectContent({
</SelectPrimitive.Content> </SelectPrimitive.Content>
</SelectPrimitive.Portal> </SelectPrimitive.Portal>
); );
} });
SelectContent.displayName = SelectPrimitive.Content.displayName;
function SelectLabel({ function SelectLabel({
className, className,
@@ -100,13 +101,13 @@ function SelectLabel({
); );
} }
function SelectItem({ const SelectItem = React.forwardRef<
className, React.ElementRef<typeof SelectPrimitive.Item>,
children, React.ComponentPropsWithoutRef<typeof SelectPrimitive.Item>
...props >(({ className, children, ...props }, ref) => {
}: React.ComponentProps<typeof SelectPrimitive.Item>) {
return ( return (
<SelectPrimitive.Item <SelectPrimitive.Item
ref={ref}
data-slot="select-item" data-slot="select-item"
className={cn( className={cn(
"focus:bg-accent focus:text-accent-foreground [&_svg:not([class*='text-'])]:text-muted-foreground relative flex w-full cursor-pointer items-center gap-2 rounded-sm py-1.5 pr-8 pl-2 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2", "focus:bg-accent focus:text-accent-foreground [&_svg:not([class*='text-'])]:text-muted-foreground relative flex w-full cursor-pointer items-center gap-2 rounded-sm py-1.5 pr-8 pl-2 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2",
@@ -125,7 +126,9 @@ function SelectItem({
<SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText> <SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
</SelectPrimitive.Item> </SelectPrimitive.Item>
); );
} });
SelectItem.displayName = SelectPrimitive.Item.displayName;
function SelectSeparator({ function SelectSeparator({
className, className,
+34 -24
View File
@@ -10,17 +10,23 @@ function Sheet({ ...props }: React.ComponentProps<typeof SheetPrimitive.Root>) {
return <SheetPrimitive.Root data-slot="sheet" {...props} />; return <SheetPrimitive.Root data-slot="sheet" {...props} />;
} }
function SheetTrigger({ const SheetTrigger = React.forwardRef<
...props React.ElementRef<typeof SheetPrimitive.Trigger>,
}: React.ComponentProps<typeof SheetPrimitive.Trigger>) { React.ComponentPropsWithoutRef<typeof SheetPrimitive.Trigger>
return <SheetPrimitive.Trigger data-slot="sheet-trigger" {...props} />; >(({ ...props }, ref) => {
} return <SheetPrimitive.Trigger ref={ref} data-slot="sheet-trigger" {...props} />;
});
function SheetClose({ SheetTrigger.displayName = SheetPrimitive.Trigger.displayName;
...props
}: React.ComponentProps<typeof SheetPrimitive.Close>) { const SheetClose = React.forwardRef<
return <SheetPrimitive.Close data-slot="sheet-close" {...props} />; React.ElementRef<typeof SheetPrimitive.Close>,
} React.ComponentPropsWithoutRef<typeof SheetPrimitive.Close>
>(({ ...props }, ref) => {
return <SheetPrimitive.Close ref={ref} data-slot="sheet-close" {...props} />;
});
SheetClose.displayName = SheetPrimitive.Close.displayName;
function SheetPortal({ function SheetPortal({
...props ...props
@@ -28,12 +34,13 @@ function SheetPortal({
return <SheetPrimitive.Portal data-slot="sheet-portal" {...props} />; return <SheetPrimitive.Portal data-slot="sheet-portal" {...props} />;
} }
function SheetOverlay({ const SheetOverlay = React.forwardRef<
className, React.ElementRef<typeof SheetPrimitive.Overlay>,
...props React.ComponentPropsWithoutRef<typeof SheetPrimitive.Overlay>
}: React.ComponentProps<typeof SheetPrimitive.Overlay>) { >(({ className, ...props }, ref) => {
return ( return (
<SheetPrimitive.Overlay <SheetPrimitive.Overlay
ref={ref}
data-slot="sheet-overlay" data-slot="sheet-overlay"
className={cn( className={cn(
"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50", "data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50",
@@ -42,20 +49,21 @@ function SheetOverlay({
{...props} {...props}
/> />
); );
} });
function SheetContent({ SheetOverlay.displayName = SheetPrimitive.Overlay.displayName;
className,
children, const SheetContent = React.forwardRef<
side = "right", React.ElementRef<typeof SheetPrimitive.Content>,
...props React.ComponentPropsWithoutRef<typeof SheetPrimitive.Content> & {
}: React.ComponentProps<typeof SheetPrimitive.Content> & { side?: "top" | "right" | "bottom" | "left";
side?: "top" | "right" | "bottom" | "left"; }
}) { >(({ className, children, side = "right", ...props }, ref) => {
return ( return (
<SheetPortal> <SheetPortal>
<SheetOverlay /> <SheetOverlay />
<SheetPrimitive.Content <SheetPrimitive.Content
ref={ref}
data-slot="sheet-content" data-slot="sheet-content"
className={cn( className={cn(
"bg-background data-[state=open]:animate-in data-[state=closed]:animate-out fixed z-50 flex flex-col gap-4 shadow-lg transition ease-in-out data-[state=closed]:duration-300 data-[state=open]:duration-500", "bg-background data-[state=open]:animate-in data-[state=closed]:animate-out fixed z-50 flex flex-col gap-4 shadow-lg transition ease-in-out data-[state=closed]:duration-300 data-[state=open]:duration-500",
@@ -79,7 +87,9 @@ function SheetContent({
</SheetPrimitive.Content> </SheetPrimitive.Content>
</SheetPortal> </SheetPortal>
); );
} });
SheetContent.displayName = SheetPrimitive.Content.displayName;
function SheetHeader({ className, ...props }: React.ComponentProps<"div">) { function SheetHeader({ className, ...props }: React.ComponentProps<"div">) {
return ( return (
+97 -81
View File
@@ -397,15 +397,15 @@ function SidebarGroup({ className, ...props }: React.ComponentProps<"div">) {
); );
} }
function SidebarGroupLabel({ const SidebarGroupLabel = React.forwardRef<
className, HTMLDivElement,
asChild = false, React.ComponentProps<"div"> & { asChild?: boolean }
...props >(({ className, asChild = false, ...props }, ref) => {
}: React.ComponentProps<"div"> & { asChild?: boolean }) {
const Comp = asChild ? Slot : "div"; const Comp = asChild ? Slot : "div";
return ( return (
<Comp <Comp
ref={ref}
data-slot="sidebar-group-label" data-slot="sidebar-group-label"
data-sidebar="group-label" data-sidebar="group-label"
className={cn( className={cn(
@@ -416,17 +416,19 @@ function SidebarGroupLabel({
{...props} {...props}
/> />
); );
} });
function SidebarGroupAction({ SidebarGroupLabel.displayName = "SidebarGroupLabel";
className,
asChild = false, const SidebarGroupAction = React.forwardRef<
...props HTMLButtonElement,
}: React.ComponentProps<"button"> & { asChild?: boolean }) { React.ComponentProps<"button"> & { asChild?: boolean }
>(({ className, asChild = false, ...props }, ref) => {
const Comp = asChild ? Slot : "button"; const Comp = asChild ? Slot : "button";
return ( return (
<Comp <Comp
ref={ref}
data-slot="sidebar-group-action" data-slot="sidebar-group-action"
data-sidebar="group-action" data-sidebar="group-action"
className={cn( className={cn(
@@ -439,7 +441,9 @@ function SidebarGroupAction({
{...props} {...props}
/> />
); );
} });
SidebarGroupAction.displayName = "SidebarGroupAction";
function SidebarGroupContent({ function SidebarGroupContent({
className, className,
@@ -499,69 +503,79 @@ const sidebarMenuButtonVariants = cva(
}, },
); );
function SidebarMenuButton({ const SidebarMenuButton = React.forwardRef<
asChild = false, HTMLButtonElement,
isActive = false, React.ComponentProps<"button"> & {
variant = "default", asChild?: boolean;
size = "default", isActive?: boolean;
tooltip, tooltip?: string | React.ComponentProps<typeof TooltipContent>;
className, } & VariantProps<typeof sidebarMenuButtonVariants>
...props >(
}: React.ComponentProps<"button"> & { (
asChild?: boolean; {
isActive?: boolean; asChild = false,
tooltip?: string | React.ComponentProps<typeof TooltipContent>; isActive = false,
} & VariantProps<typeof sidebarMenuButtonVariants>) { variant = "default",
const Comp = asChild ? Slot : "button"; size = "default",
const { isMobile, state } = useSidebar(); tooltip,
className,
...props
},
ref,
) => {
const Comp = asChild ? Slot : "button";
const { isMobile, state } = useSidebar();
const button = ( const button = (
<Comp <Comp
data-slot="sidebar-menu-button" ref={ref}
data-sidebar="menu-button" data-slot="sidebar-menu-button"
data-size={size} data-sidebar="menu-button"
data-active={isActive} data-size={size}
className={cn(sidebarMenuButtonVariants({ variant, size }), className)} data-active={isActive}
{...props} className={cn(sidebarMenuButtonVariants({ variant, size }), className)}
/> {...props}
);
if (!tooltip) {
return button;
}
if (typeof tooltip === "string") {
tooltip = {
children: tooltip,
};
}
return (
<Tooltip>
<TooltipTrigger asChild>{button}</TooltipTrigger>
<TooltipContent
side="right"
align="center"
hidden={state !== "collapsed" || isMobile}
{...tooltip}
/> />
</Tooltip> );
);
}
function SidebarMenuAction({ if (!tooltip) {
className, return button;
asChild = false, }
showOnHover = false,
...props if (typeof tooltip === "string") {
}: React.ComponentProps<"button"> & { tooltip = {
asChild?: boolean; children: tooltip,
showOnHover?: boolean; };
}) { }
return (
<Tooltip>
<TooltipTrigger asChild>{button}</TooltipTrigger>
<TooltipContent
side="right"
align="center"
hidden={state !== "collapsed" || isMobile}
{...tooltip}
/>
</Tooltip>
);
},
);
SidebarMenuButton.displayName = "SidebarMenuButton";
const SidebarMenuAction = React.forwardRef<
HTMLButtonElement,
React.ComponentProps<"button"> & {
asChild?: boolean;
showOnHover?: boolean;
}
>(({ className, asChild = false, showOnHover = false, ...props }, ref) => {
const Comp = asChild ? Slot : "button"; const Comp = asChild ? Slot : "button";
return ( return (
<Comp <Comp
ref={ref}
data-slot="sidebar-menu-action" data-slot="sidebar-menu-action"
data-sidebar="menu-action" data-sidebar="menu-action"
className={cn( className={cn(
@@ -579,7 +593,9 @@ function SidebarMenuAction({
{...props} {...props}
/> />
); );
} });
SidebarMenuAction.displayName = "SidebarMenuAction";
function SidebarMenuBadge({ function SidebarMenuBadge({
className, className,
@@ -670,21 +686,19 @@ function SidebarMenuSubItem({
); );
} }
function SidebarMenuSubButton({ const SidebarMenuSubButton = React.forwardRef<
asChild = false, HTMLAnchorElement,
size = "md", React.ComponentProps<"a"> & {
isActive = false, asChild?: boolean;
className, size?: "sm" | "md";
...props isActive?: boolean;
}: React.ComponentProps<"a"> & { }
asChild?: boolean; >(({ asChild = false, size = "md", isActive = false, className, ...props }, ref) => {
size?: "sm" | "md";
isActive?: boolean;
}) {
const Comp = asChild ? Slot : "a"; const Comp = asChild ? Slot : "a";
return ( return (
<Comp <Comp
ref={ref}
data-slot="sidebar-menu-sub-button" data-slot="sidebar-menu-sub-button"
data-sidebar="menu-sub-button" data-sidebar="menu-sub-button"
data-size={size} data-size={size}
@@ -700,7 +714,9 @@ function SidebarMenuSubButton({
{...props} {...props}
/> />
); );
} });
SidebarMenuSubButton.displayName = "SidebarMenuSubButton";
export { export {
Sidebar, Sidebar,
+25 -17
View File
@@ -40,28 +40,31 @@ const tabsListVariants = cva(
}, },
); );
function TabsList({ const TabsList = React.forwardRef<
className, React.ElementRef<typeof TabsPrimitive.List>,
variant = "default", React.ComponentPropsWithoutRef<typeof TabsPrimitive.List> &
...props VariantProps<typeof tabsListVariants>
}: React.ComponentProps<typeof TabsPrimitive.List> & >(({ className, variant = "default", ...props }, ref) => {
VariantProps<typeof tabsListVariants>) {
return ( return (
<TabsPrimitive.List <TabsPrimitive.List
ref={ref}
data-slot="tabs-list" data-slot="tabs-list"
data-variant={variant} data-variant={variant}
className={cn(tabsListVariants({ variant }), className)} className={cn(tabsListVariants({ variant }), className)}
{...props} {...props}
/> />
); );
} });
function TabsTrigger({ TabsList.displayName = TabsPrimitive.List.displayName;
className,
...props const TabsTrigger = React.forwardRef<
}: React.ComponentProps<typeof TabsPrimitive.Trigger>) { React.ElementRef<typeof TabsPrimitive.Trigger>,
React.ComponentPropsWithoutRef<typeof TabsPrimitive.Trigger>
>(({ className, ...props }, ref) => {
return ( return (
<TabsPrimitive.Trigger <TabsPrimitive.Trigger
ref={ref}
data-slot="tabs-trigger" data-slot="tabs-trigger"
className={cn( className={cn(
"focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:outline-ring text-foreground/60 hover:text-foreground dark:text-muted-foreground dark:hover:text-foreground relative inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-1.5 rounded-md border border-transparent px-2 py-1 text-sm font-medium whitespace-nowrap transition-all group-data-[orientation=vertical]/tabs:w-full group-data-[orientation=vertical]/tabs:justify-start focus-visible:ring-[3px] focus-visible:outline-1 disabled:pointer-events-none disabled:opacity-50 group-data-[variant=default]/tabs-list:data-[state=active]:shadow-sm group-data-[variant=line]/tabs-list:data-[state=active]:shadow-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", "focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:outline-ring text-foreground/60 hover:text-foreground dark:text-muted-foreground dark:hover:text-foreground relative inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-1.5 rounded-md border border-transparent px-2 py-1 text-sm font-medium whitespace-nowrap transition-all group-data-[orientation=vertical]/tabs:w-full group-data-[orientation=vertical]/tabs:justify-start focus-visible:ring-[3px] focus-visible:outline-1 disabled:pointer-events-none disabled:opacity-50 group-data-[variant=default]/tabs-list:data-[state=active]:shadow-sm group-data-[variant=line]/tabs-list:data-[state=active]:shadow-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
@@ -73,19 +76,24 @@ function TabsTrigger({
{...props} {...props}
/> />
); );
} });
function TabsContent({ TabsTrigger.displayName = TabsPrimitive.Trigger.displayName;
className,
...props const TabsContent = React.forwardRef<
}: React.ComponentProps<typeof TabsPrimitive.Content>) { React.ElementRef<typeof TabsPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof TabsPrimitive.Content>
>(({ className, ...props }, ref) => {
return ( return (
<TabsPrimitive.Content <TabsPrimitive.Content
ref={ref}
data-slot="tabs-content" data-slot="tabs-content"
className={cn("flex-1 outline-none", className)} className={cn("flex-1 outline-none", className)}
{...props} {...props}
/> />
); );
} });
TabsContent.displayName = TabsPrimitive.Content.displayName;
export { Tabs, TabsList, TabsTrigger, TabsContent, tabsListVariants }; export { Tabs, TabsList, TabsTrigger, TabsContent, tabsListVariants };
+22 -12
View File
@@ -28,21 +28,29 @@ function Tooltip({
); );
} }
function TooltipTrigger({ const TooltipTrigger = React.forwardRef<
...props React.ElementRef<typeof TooltipPrimitive.Trigger>,
}: React.ComponentProps<typeof TooltipPrimitive.Trigger>) { React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Trigger>
return <TooltipPrimitive.Trigger data-slot="tooltip-trigger" {...props} />; >(({ ...props }, ref) => {
} return (
<TooltipPrimitive.Trigger
ref={ref}
data-slot="tooltip-trigger"
{...props}
/>
);
});
function TooltipContent({ TooltipTrigger.displayName = TooltipPrimitive.Trigger.displayName;
className,
sideOffset, const TooltipContent = React.forwardRef<
children, React.ElementRef<typeof TooltipPrimitive.Content>,
...props React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content>
}: React.ComponentProps<typeof TooltipPrimitive.Content>) { >(({ className, sideOffset, children, ...props }, ref) => {
return ( return (
<TooltipPrimitive.Portal> <TooltipPrimitive.Portal>
<TooltipPrimitive.Content <TooltipPrimitive.Content
ref={ref}
data-slot="tooltip-content" data-slot="tooltip-content"
sideOffset={sideOffset ?? 4} sideOffset={sideOffset ?? 4}
className={cn( className={cn(
@@ -55,6 +63,8 @@ function TooltipContent({
</TooltipPrimitive.Content> </TooltipPrimitive.Content>
</TooltipPrimitive.Portal> </TooltipPrimitive.Portal>
); );
} });
TooltipContent.displayName = TooltipPrimitive.Content.displayName;
export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider }; export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider };
@@ -179,82 +179,80 @@ export function RecentChatList() {
className="group/side-menu-item" className="group/side-menu-item"
> >
<SidebarMenuButton isActive={isActive} asChild> <SidebarMenuButton isActive={isActive} asChild>
<div> <Link
<Link className="text-muted-foreground block w-full whitespace-nowrap group-hover/side-menu-item:overflow-hidden"
className="text-muted-foreground block w-full whitespace-nowrap group-hover/side-menu-item:overflow-hidden" href={pathOfThread(thread)}
href={pathOfThread(thread)} >
{titleOfThread(thread)}
</Link>
</SidebarMenuButton>
{env.NEXT_PUBLIC_STATIC_WEBSITE_ONLY !== "true" && (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<SidebarMenuAction
showOnHover
className="bg-background/50 hover:bg-background"
>
<MoreHorizontal />
<span className="sr-only">{t.common.more}</span>
</SidebarMenuAction>
</DropdownMenuTrigger>
<DropdownMenuContent
className="w-48 rounded-lg"
side={"right"}
align={"start"}
> >
{titleOfThread(thread)} <DropdownMenuItem
</Link> onSelect={() =>
{env.NEXT_PUBLIC_STATIC_WEBSITE_ONLY !== "true" && ( handleRenameClick(
<DropdownMenu> thread.thread_id,
<DropdownMenuTrigger asChild> titleOfThread(thread),
<SidebarMenuAction )
showOnHover }
className="bg-background/50 hover:bg-background" >
> <Pencil className="text-muted-foreground" />
<MoreHorizontal /> <span>{t.common.rename}</span>
<span className="sr-only">{t.common.more}</span> </DropdownMenuItem>
</SidebarMenuAction> <DropdownMenuItem
</DropdownMenuTrigger> onSelect={() => handleShare(thread)}
<DropdownMenuContent >
className="w-48 rounded-lg" <Share2 className="text-muted-foreground" />
side={"right"} <span>{t.common.share}</span>
align={"start"} </DropdownMenuItem>
> <DropdownMenuSub>
<DropdownMenuSubTrigger>
<Download className="text-muted-foreground" />
<span>{t.common.export}</span>
</DropdownMenuSubTrigger>
<DropdownMenuSubContent>
<DropdownMenuItem <DropdownMenuItem
onSelect={() => onSelect={() =>
handleRenameClick( handleExport(thread, "markdown")
thread.thread_id,
titleOfThread(thread),
)
} }
> >
<Pencil className="text-muted-foreground" /> <FileText className="text-muted-foreground" />
<span>{t.common.rename}</span> <span>{t.common.exportAsMarkdown}</span>
</DropdownMenuItem> </DropdownMenuItem>
<DropdownMenuItem <DropdownMenuItem
onSelect={() => handleShare(thread)} onSelect={() =>
handleExport(thread, "json")
}
> >
<Share2 className="text-muted-foreground" /> <FileJson className="text-muted-foreground" />
<span>{t.common.share}</span> <span>{t.common.exportAsJSON}</span>
</DropdownMenuItem> </DropdownMenuItem>
<DropdownMenuSub> </DropdownMenuSubContent>
<DropdownMenuSubTrigger> </DropdownMenuSub>
<Download className="text-muted-foreground" /> <DropdownMenuSeparator />
<span>{t.common.export}</span> <DropdownMenuItem
</DropdownMenuSubTrigger> onSelect={() => handleDelete(thread.thread_id)}
<DropdownMenuSubContent> >
<DropdownMenuItem <Trash2 className="text-muted-foreground" />
onSelect={() => <span>{t.common.delete}</span>
handleExport(thread, "markdown") </DropdownMenuItem>
} </DropdownMenuContent>
> </DropdownMenu>
<FileText className="text-muted-foreground" /> )}
<span>{t.common.exportAsMarkdown}</span>
</DropdownMenuItem>
<DropdownMenuItem
onSelect={() =>
handleExport(thread, "json")
}
>
<FileJson className="text-muted-foreground" />
<span>{t.common.exportAsJSON}</span>
</DropdownMenuItem>
</DropdownMenuSubContent>
</DropdownMenuSub>
<DropdownMenuSeparator />
<DropdownMenuItem
onSelect={() => handleDelete(thread.thread_id)}
>
<Trash2 className="text-muted-foreground" />
<span>{t.common.delete}</span>
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
)}
</div>
</SidebarMenuButton>
</SidebarMenuItem> </SidebarMenuItem>
); );
})} })}
+31 -38
View File
@@ -1,4 +1,4 @@
"use client"; "use client";
import { import {
ArrowLeftIcon, ArrowLeftIcon,
@@ -17,13 +17,6 @@ import {
} from "@/components/ai-elements/prompt-input"; } from "@/components/ai-elements/prompt-input";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input"; import { Input } from "@/components/ui/input";
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
import { Textarea } from "@/components/ui/textarea"; import { Textarea } from "@/components/ui/textarea";
import { ArtifactsProvider } from "@/components/workspace/artifacts"; import { ArtifactsProvider } from "@/components/workspace/artifacts";
import { import {
@@ -120,7 +113,7 @@ export default function NewAgentPage() {
model_name: chatModelInput || undefined, model_name: chatModelInput || undefined,
}, },
onToolEnd() { onToolEnd() {
// setup_agent never actually executes in this flow — it gets // setup_agent never actually executes in this flow 鈥?it gets
// intercepted by SetupAgentApprovalMiddleware and the form is filled // intercepted by SetupAgentApprovalMiddleware and the form is filled
// from the approval ToolMessage payload (handleApproveSetupAgent). // from the approval ToolMessage payload (handleApproveSetupAgent).
// No agent record is fetched/refreshed during chat. // No agent record is fetched/refreshed during chat.
@@ -156,7 +149,7 @@ export default function NewAgentPage() {
if (!name) { if (!name) {
// Names are display-only and may collide, so a timestamped placeholder // Names are display-only and may collide, so a timestamped placeholder
// is safe to send to the backend just to satisfy the required-field // is safe to send to the backend just to satisfy the required-field
// validation. Intentionally NOT written back into the visible input — // validation. Intentionally NOT written back into the visible input 鈥?
// the user wants the name box to stay blank while they chat, and we // the user wants the name box to stay blank while they chat, and we
// refill it later (with the model's proposed name) on setup_agent // refill it later (with the model's proposed name) on setup_agent
// approval. // approval.
@@ -245,7 +238,7 @@ export default function NewAgentPage() {
// Chat is purely a discussion channel. The agent record is only // Chat is purely a discussion channel. The agent record is only
// created when the user explicitly clicks Save (top-right). If the // created when the user explicitly clicks Save (top-right). If the
// model proposes a config via setup_agent, our approval handler // model proposes a config via setup_agent, our approval handler
// prefills the form locally — it does NOT persist anything. // prefills the form locally 鈥?it does NOT persist anything.
await ensureThreadExists(); await ensureThreadExists();
await sendMessage(threadId, { text: trimmed, files: [] }); await sendMessage(threadId, { text: trimmed, files: [] });
}, },
@@ -255,7 +248,7 @@ export default function NewAgentPage() {
const handleApproveSetupAgent = useCallback( const handleApproveSetupAgent = useCallback(
async (payload: SetupAgentApprovalPayload) => { async (payload: SetupAgentApprovalPayload) => {
// Approving the model's setup_agent proposal **does not** persist // Approving the model's setup_agent proposal **does not** persist
// anything — it only mirrors the proposal into the form so the user // anything 鈥?it only mirrors the proposal into the form so the user
// can review it. Creation/update happens later when the user clicks // can review it. Creation/update happens later when the user clicks
// the top-right Save button. // the top-right Save button.
const proposedName = payload.name?.trim() ?? ""; const proposedName = payload.name?.trim() ?? "";
@@ -338,22 +331,23 @@ export default function NewAgentPage() {
<span className="text-muted-foreground text-xs"> <span className="text-muted-foreground text-xs">
当前对话模型 当前对话模型
</span> </span>
<Select <select
value={chatModelInput} value={chatModelInput}
onValueChange={setChatModelInput} onChange={(event) =>
setChatModelInput(event.currentTarget.value)
}
disabled={isModelsLoading || thread.isLoading} disabled={isModelsLoading || thread.isLoading}
className="border-input bg-background h-7 min-w-[10rem] rounded-md border px-2 text-xs shadow-xs outline-none"
> >
<SelectTrigger className="h-7 w-auto min-w-[10rem] gap-2 px-2 text-xs"> <option value="" disabled>
<SelectValue placeholder="选择模型" /> 选择模型
</SelectTrigger> </option>
<SelectContent> {models.map((model) => (
{models.map((model) => ( <option key={model.name} value={model.name}>
<SelectItem key={model.name} value={model.name}> {model.display_name || model.name}
{model.display_name || model.name} </option>
</SelectItem> ))}
))} </select>
</SelectContent>
</Select>
</div> </div>
<PromptInput <PromptInput
onSubmit={({ text }) => void handleChatSubmit(text)} onSubmit={({ text }) => void handleChatSubmit(text)}
@@ -405,22 +399,21 @@ export default function NewAgentPage() {
<div className="space-y-2"> <div className="space-y-2">
<label className="text-sm font-medium">模型</label> <label className="text-sm font-medium">模型</label>
<Select <select
value={modelInput} value={modelInput}
onValueChange={setModelInput} onChange={(event) => setModelInput(event.currentTarget.value)}
disabled={isModelsLoading} disabled={isModelsLoading}
className="border-input bg-background h-9 w-full rounded-md border px-3 text-sm shadow-xs outline-none"
> >
<SelectTrigger className="w-full"> <option value="" disabled>
<SelectValue placeholder="选择模型" /> 选择模型
</SelectTrigger> </option>
<SelectContent> {models.map((model) => (
{models.map((model) => ( <option key={model.name} value={model.name}>
<SelectItem key={model.name} value={model.name}> {model.display_name || model.name}
{model.display_name || model.name} </option>
</SelectItem> ))}
))} </select>
</SelectContent>
</Select>
<p className="text-muted-foreground text-xs"> <p className="text-muted-foreground text-xs">
该专家被使用时调用的模型。 该专家被使用时调用的模型。
</p> </p>
+1 -1
View File
@@ -8,7 +8,7 @@ import StrategyRoutes from "./StrategyRoutes";
import Header from "@/strategy-components/Header"; import Header from "@/strategy-components/Header";
// 设为 true 时隐藏侧边栏(开发中,暂未完成) // 设为 true 时隐藏侧边栏(开发中,暂未完成)
const SIDEBAR_ENABLED = false; const SIDEBAR_ENABLED = true;
function PageLayout() { function PageLayout() {
const [collapsed, setCollapsed] = useState(false); const [collapsed, setCollapsed] = useState(false);
+4 -14
View File
@@ -1,14 +1,12 @@
import { Navigate, Route, Routes } from "react-router-dom"; import { Navigate, Route, Routes } from "react-router-dom";
import type { ReactNode } from "react";
import { Toaster } from "sonner"; import { Toaster } from "sonner";
import { getStoredAuth } from "@/core/auth"; import { getStoredAuth } from "@/core/auth";
import { RouteBaseProvider } from "@/core/route-base"; import { RouteBaseProvider } from "@/core/route-base";
import { SubtasksProvider } from "@/core/tasks/context"; import { SidebarProvider } from "@/components/ui/sidebar";
import { ArtifactsProvider } from "@/components/workspace/artifacts";
import { PromptInputProvider } from "@/components/ai-elements/prompt-input";
import GeneralQA from "@/strategy-components/components/qa/GeneralQA"; import GeneralQA from "@/strategy-components/components/qa/GeneralQA";
import { ChatRuntime } from "./WorkspaceRoutes";
import AgentsPage from "./AgentsPage"; import AgentsPage from "./AgentsPage";
import ChatsPage from "./ChatsPage"; import ChatsPage from "./ChatsPage";
import ChatPage from "./ChatPage"; import ChatPage from "./ChatPage";
@@ -18,19 +16,10 @@ import ScheduledTasksPage from "./ScheduledTasksPage";
import ScheduledTaskRunDetailPage from "./ScheduledTaskRunDetailPage"; import ScheduledTaskRunDetailPage from "./ScheduledTaskRunDetailPage";
import RecommendedQuestionsPage from "./RecommendedQuestionsPage"; import RecommendedQuestionsPage from "./RecommendedQuestionsPage";
function ChatRuntime({ children }: { children: ReactNode }) {
return (
<SubtasksProvider>
<ArtifactsProvider>
<PromptInputProvider>{children}</PromptInputProvider>
</ArtifactsProvider>
</SubtasksProvider>
);
}
export default function StrategyRoutes() { export default function StrategyRoutes() {
return ( return (
<RouteBaseProvider value="/page/strategy"> <RouteBaseProvider value="/page/strategy">
<SidebarProvider>
<div className="h-full w-full overflow-hidden"> <div className="h-full w-full overflow-hidden">
<Routes> <Routes>
<Route index element={<Navigate to="qa/general" replace />} /> <Route index element={<Navigate to="qa/general" replace />} />
@@ -89,6 +78,7 @@ export default function StrategyRoutes() {
/> />
</Routes> </Routes>
</div> </div>
</SidebarProvider>
<Toaster position="top-center" /> <Toaster position="top-center" />
</RouteBaseProvider> </RouteBaseProvider>
); );
+1 -1
View File
@@ -61,7 +61,7 @@ export function WorkspaceLayout({
); );
} }
function ChatRuntime({ children }: { children: ReactNode }) { export function ChatRuntime({ children }: { children: ReactNode }) {
return ( return (
<SubtasksProvider> <SubtasksProvider>
<ArtifactsProvider> <ArtifactsProvider>