### What problem does this PR solve? Feat: Upload agent file #3221 ### Type of change - [x] New Feature (non-breaking change which adds functionality)tags/v0.17.0
| "@radix-ui/react-slot": "^1.1.0", | "@radix-ui/react-slot": "^1.1.0", | ||||
| "@radix-ui/react-switch": "^1.1.1", | "@radix-ui/react-switch": "^1.1.1", | ||||
| "@radix-ui/react-tabs": "^1.1.1", | "@radix-ui/react-tabs": "^1.1.1", | ||||
| "@radix-ui/react-toast": "^1.2.2", | |||||
| "@radix-ui/react-toast": "^1.2.6", | |||||
| "@radix-ui/react-tooltip": "^1.1.4", | "@radix-ui/react-tooltip": "^1.1.4", | ||||
| "@tailwindcss/line-clamp": "^0.4.4", | "@tailwindcss/line-clamp": "^0.4.4", | ||||
| "@tanstack/react-query": "^5.40.0", | "@tanstack/react-query": "^5.40.0", | ||||
| } | } | ||||
| }, | }, | ||||
| "node_modules/@radix-ui/react-toast": { | "node_modules/@radix-ui/react-toast": { | ||||
| "version": "1.2.2", | |||||
| "resolved": "https://registry.npmmirror.com/@radix-ui/react-toast/-/react-toast-1.2.2.tgz", | |||||
| "integrity": "sha512-Z6pqSzmAP/bFJoqMAston4eSNa+ud44NSZTiZUmUen+IOZ5nBY8kzuU5WDBVyFXPtcW6yUalOHsxM/BP6Sv8ww==", | |||||
| "version": "1.2.6", | |||||
| "resolved": "https://registry.npmmirror.com/@radix-ui/react-toast/-/react-toast-1.2.6.tgz", | |||||
| "integrity": "sha512-gN4dpuIVKEgpLn1z5FhzT9mYRUitbfZq9XqN/7kkBMUgFTzTG8x/KszWJugJXHcwxckY8xcKDZPz7kG3o6DsUA==", | |||||
| "license": "MIT", | |||||
| "dependencies": { | "dependencies": { | ||||
| "@radix-ui/primitive": "1.1.0", | |||||
| "@radix-ui/react-collection": "1.1.0", | |||||
| "@radix-ui/react-compose-refs": "1.1.0", | |||||
| "@radix-ui/primitive": "1.1.1", | |||||
| "@radix-ui/react-collection": "1.1.2", | |||||
| "@radix-ui/react-compose-refs": "1.1.1", | |||||
| "@radix-ui/react-context": "1.1.1", | "@radix-ui/react-context": "1.1.1", | ||||
| "@radix-ui/react-dismissable-layer": "1.1.1", | |||||
| "@radix-ui/react-portal": "1.1.2", | |||||
| "@radix-ui/react-presence": "1.1.1", | |||||
| "@radix-ui/react-primitive": "2.0.0", | |||||
| "@radix-ui/react-dismissable-layer": "1.1.5", | |||||
| "@radix-ui/react-portal": "1.1.4", | |||||
| "@radix-ui/react-presence": "1.1.2", | |||||
| "@radix-ui/react-primitive": "2.0.2", | |||||
| "@radix-ui/react-use-callback-ref": "1.1.0", | "@radix-ui/react-use-callback-ref": "1.1.0", | ||||
| "@radix-ui/react-use-controllable-state": "1.1.0", | "@radix-ui/react-use-controllable-state": "1.1.0", | ||||
| "@radix-ui/react-use-layout-effect": "1.1.0", | "@radix-ui/react-use-layout-effect": "1.1.0", | ||||
| "@radix-ui/react-visually-hidden": "1.1.0" | |||||
| "@radix-ui/react-visually-hidden": "1.1.2" | |||||
| }, | |||||
| "peerDependencies": { | |||||
| "@types/react": "*", | |||||
| "@types/react-dom": "*", | |||||
| "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", | |||||
| "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" | |||||
| }, | |||||
| "peerDependenciesMeta": { | |||||
| "@types/react": { | |||||
| "optional": true | |||||
| }, | |||||
| "@types/react-dom": { | |||||
| "optional": true | |||||
| } | |||||
| } | |||||
| }, | |||||
| "node_modules/@radix-ui/react-toast/node_modules/@radix-ui/primitive": { | |||||
| "version": "1.1.1", | |||||
| "resolved": "https://registry.npmmirror.com/@radix-ui/primitive/-/primitive-1.1.1.tgz", | |||||
| "integrity": "sha512-SJ31y+Q/zAyShtXJc8x83i9TYdbAfHZ++tUZnvjJJqFjzsdUnKsxPL6IEtBlxKkU7yzer//GQtZSV4GbldL3YA==", | |||||
| "license": "MIT" | |||||
| }, | |||||
| "node_modules/@radix-ui/react-toast/node_modules/@radix-ui/react-collection": { | |||||
| "version": "1.1.2", | |||||
| "resolved": "https://registry.npmmirror.com/@radix-ui/react-collection/-/react-collection-1.1.2.tgz", | |||||
| "integrity": "sha512-9z54IEKRxIa9VityapoEYMuByaG42iSy1ZXlY2KcuLSEtq8x4987/N6m15ppoMffgZX72gER2uHe1D9Y6Unlcw==", | |||||
| "license": "MIT", | |||||
| "dependencies": { | |||||
| "@radix-ui/react-compose-refs": "1.1.1", | |||||
| "@radix-ui/react-context": "1.1.1", | |||||
| "@radix-ui/react-primitive": "2.0.2", | |||||
| "@radix-ui/react-slot": "1.1.2" | |||||
| }, | |||||
| "peerDependencies": { | |||||
| "@types/react": "*", | |||||
| "@types/react-dom": "*", | |||||
| "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", | |||||
| "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" | |||||
| }, | |||||
| "peerDependenciesMeta": { | |||||
| "@types/react": { | |||||
| "optional": true | |||||
| }, | |||||
| "@types/react-dom": { | |||||
| "optional": true | |||||
| } | |||||
| } | |||||
| }, | |||||
| "node_modules/@radix-ui/react-toast/node_modules/@radix-ui/react-compose-refs": { | |||||
| "version": "1.1.1", | |||||
| "resolved": "https://registry.npmmirror.com/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.1.tgz", | |||||
| "integrity": "sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw==", | |||||
| "license": "MIT", | |||||
| "peerDependencies": { | |||||
| "@types/react": "*", | |||||
| "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" | |||||
| }, | |||||
| "peerDependenciesMeta": { | |||||
| "@types/react": { | |||||
| "optional": true | |||||
| } | |||||
| } | |||||
| }, | |||||
| "node_modules/@radix-ui/react-toast/node_modules/@radix-ui/react-dismissable-layer": { | |||||
| "version": "1.1.5", | |||||
| "resolved": "https://registry.npmmirror.com/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.5.tgz", | |||||
| "integrity": "sha512-E4TywXY6UsXNRhFrECa5HAvE5/4BFcGyfTyK36gP+pAW1ed7UTK4vKwdr53gAJYwqbfCWC6ATvJa3J3R/9+Qrg==", | |||||
| "license": "MIT", | |||||
| "dependencies": { | |||||
| "@radix-ui/primitive": "1.1.1", | |||||
| "@radix-ui/react-compose-refs": "1.1.1", | |||||
| "@radix-ui/react-primitive": "2.0.2", | |||||
| "@radix-ui/react-use-callback-ref": "1.1.0", | |||||
| "@radix-ui/react-use-escape-keydown": "1.1.0" | |||||
| }, | |||||
| "peerDependencies": { | |||||
| "@types/react": "*", | |||||
| "@types/react-dom": "*", | |||||
| "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", | |||||
| "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" | |||||
| }, | |||||
| "peerDependenciesMeta": { | |||||
| "@types/react": { | |||||
| "optional": true | |||||
| }, | |||||
| "@types/react-dom": { | |||||
| "optional": true | |||||
| } | |||||
| } | |||||
| }, | |||||
| "node_modules/@radix-ui/react-toast/node_modules/@radix-ui/react-portal": { | |||||
| "version": "1.1.4", | |||||
| "resolved": "https://registry.npmmirror.com/@radix-ui/react-portal/-/react-portal-1.1.4.tgz", | |||||
| "integrity": "sha512-sn2O9k1rPFYVyKd5LAJfo96JlSGVFpa1fS6UuBJfrZadudiw5tAmru+n1x7aMRQ84qDM71Zh1+SzK5QwU0tJfA==", | |||||
| "license": "MIT", | |||||
| "dependencies": { | |||||
| "@radix-ui/react-primitive": "2.0.2", | |||||
| "@radix-ui/react-use-layout-effect": "1.1.0" | |||||
| }, | |||||
| "peerDependencies": { | |||||
| "@types/react": "*", | |||||
| "@types/react-dom": "*", | |||||
| "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", | |||||
| "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" | |||||
| }, | |||||
| "peerDependenciesMeta": { | |||||
| "@types/react": { | |||||
| "optional": true | |||||
| }, | |||||
| "@types/react-dom": { | |||||
| "optional": true | |||||
| } | |||||
| } | |||||
| }, | |||||
| "node_modules/@radix-ui/react-toast/node_modules/@radix-ui/react-presence": { | |||||
| "version": "1.1.2", | |||||
| "resolved": "https://registry.npmmirror.com/@radix-ui/react-presence/-/react-presence-1.1.2.tgz", | |||||
| "integrity": "sha512-18TFr80t5EVgL9x1SwF/YGtfG+l0BS0PRAlCWBDoBEiDQjeKgnNZRVJp/oVBl24sr3Gbfwc/Qpj4OcWTQMsAEg==", | |||||
| "license": "MIT", | |||||
| "dependencies": { | |||||
| "@radix-ui/react-compose-refs": "1.1.1", | |||||
| "@radix-ui/react-use-layout-effect": "1.1.0" | |||||
| }, | |||||
| "peerDependencies": { | |||||
| "@types/react": "*", | |||||
| "@types/react-dom": "*", | |||||
| "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", | |||||
| "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" | |||||
| }, | |||||
| "peerDependenciesMeta": { | |||||
| "@types/react": { | |||||
| "optional": true | |||||
| }, | |||||
| "@types/react-dom": { | |||||
| "optional": true | |||||
| } | |||||
| } | |||||
| }, | |||||
| "node_modules/@radix-ui/react-toast/node_modules/@radix-ui/react-primitive": { | |||||
| "version": "2.0.2", | |||||
| "resolved": "https://registry.npmmirror.com/@radix-ui/react-primitive/-/react-primitive-2.0.2.tgz", | |||||
| "integrity": "sha512-Ec/0d38EIuvDF+GZjcMU/Ze6MxntVJYO/fRlCPhCaVUyPY9WTalHJw54tp9sXeJo3tlShWpy41vQRgLRGOuz+w==", | |||||
| "license": "MIT", | |||||
| "dependencies": { | |||||
| "@radix-ui/react-slot": "1.1.2" | |||||
| }, | |||||
| "peerDependencies": { | |||||
| "@types/react": "*", | |||||
| "@types/react-dom": "*", | |||||
| "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", | |||||
| "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" | |||||
| }, | |||||
| "peerDependenciesMeta": { | |||||
| "@types/react": { | |||||
| "optional": true | |||||
| }, | |||||
| "@types/react-dom": { | |||||
| "optional": true | |||||
| } | |||||
| } | |||||
| }, | |||||
| "node_modules/@radix-ui/react-toast/node_modules/@radix-ui/react-slot": { | |||||
| "version": "1.1.2", | |||||
| "resolved": "https://registry.npmmirror.com/@radix-ui/react-slot/-/react-slot-1.1.2.tgz", | |||||
| "integrity": "sha512-YAKxaiGsSQJ38VzKH86/BPRC4rh+b1Jpa+JneA5LRE7skmLPNAyeG8kPJj/oo4STLvlrs8vkf/iYyc3A5stYCQ==", | |||||
| "license": "MIT", | |||||
| "dependencies": { | |||||
| "@radix-ui/react-compose-refs": "1.1.1" | |||||
| }, | |||||
| "peerDependencies": { | |||||
| "@types/react": "*", | |||||
| "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" | |||||
| }, | |||||
| "peerDependenciesMeta": { | |||||
| "@types/react": { | |||||
| "optional": true | |||||
| } | |||||
| } | |||||
| }, | |||||
| "node_modules/@radix-ui/react-toast/node_modules/@radix-ui/react-visually-hidden": { | |||||
| "version": "1.1.2", | |||||
| "resolved": "https://registry.npmmirror.com/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.1.2.tgz", | |||||
| "integrity": "sha512-1SzA4ns2M1aRlvxErqhLHsBHoS5eI5UUcI2awAMgGUp4LoaoWOKYmvqDY2s/tltuPkh3Yk77YF/r3IRj+Amx4Q==", | |||||
| "license": "MIT", | |||||
| "dependencies": { | |||||
| "@radix-ui/react-primitive": "2.0.2" | |||||
| }, | }, | ||||
| "peerDependencies": { | "peerDependencies": { | ||||
| "@types/react": "*", | "@types/react": "*", |
| "@radix-ui/react-slot": "^1.1.0", | "@radix-ui/react-slot": "^1.1.0", | ||||
| "@radix-ui/react-switch": "^1.1.1", | "@radix-ui/react-switch": "^1.1.1", | ||||
| "@radix-ui/react-tabs": "^1.1.1", | "@radix-ui/react-tabs": "^1.1.1", | ||||
| "@radix-ui/react-toast": "^1.2.2", | |||||
| "@radix-ui/react-toast": "^1.2.6", | |||||
| "@radix-ui/react-tooltip": "^1.1.4", | "@radix-ui/react-tooltip": "^1.1.4", | ||||
| "@tailwindcss/line-clamp": "^0.4.4", | "@tailwindcss/line-clamp": "^0.4.4", | ||||
| "@tanstack/react-query": "^5.40.0", | "@tanstack/react-query": "^5.40.0", |
| import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; | import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; | ||||
| import { ReactQueryDevtools } from '@tanstack/react-query-devtools'; | import { ReactQueryDevtools } from '@tanstack/react-query-devtools'; | ||||
| import { App, ConfigProvider, ConfigProviderProps, theme } from 'antd'; | import { App, ConfigProvider, ConfigProviderProps, theme } from 'antd'; | ||||
| import pt_BR from 'antd/lib/locale/pt_BR'; | |||||
| import enUS from 'antd/locale/en_US'; | import enUS from 'antd/locale/en_US'; | ||||
| import vi_VN from 'antd/locale/vi_VN'; | import vi_VN from 'antd/locale/vi_VN'; | ||||
| import zhCN from 'antd/locale/zh_CN'; | import zhCN from 'antd/locale/zh_CN'; | ||||
| import zh_HK from 'antd/locale/zh_HK'; | import zh_HK from 'antd/locale/zh_HK'; | ||||
| import pt_BR from 'antd/lib/locale/pt_BR'; | |||||
| import dayjs from 'dayjs'; | import dayjs from 'dayjs'; | ||||
| import advancedFormat from 'dayjs/plugin/advancedFormat'; | import advancedFormat from 'dayjs/plugin/advancedFormat'; | ||||
| import customParseFormat from 'dayjs/plugin/customParseFormat'; | import customParseFormat from 'dayjs/plugin/customParseFormat'; | ||||
| }} | }} | ||||
| locale={locale} | locale={locale} | ||||
| > | > | ||||
| <App> {children}</App> | |||||
| <App>{children}</App> | |||||
| </ConfigProvider> | </ConfigProvider> | ||||
| <ReactQueryDevtools buttonPosition={'top-left'} /> | <ReactQueryDevtools buttonPosition={'top-left'} /> | ||||
| </> | </> |
| // Inspired by react-hot-toast library | // Inspired by react-hot-toast library | ||||
| import * as React from 'react'; | import * as React from 'react'; | ||||
| import type { ToastActionElement, ToastProps } from '@/components/ui/toast'; | |||||
| import type { | |||||
| ToastActionElement, | |||||
| ToastProps, | |||||
| } from '@/registry/default/ui/toast'; | |||||
| const TOAST_LIMIT = 1; | const TOAST_LIMIT = 1; | ||||
| const TOAST_REMOVE_DELAY = 1000000; | const TOAST_REMOVE_DELAY = 1000000; |
| import { ControllerRenderProps } from 'react-hook-form'; | import { ControllerRenderProps } from 'react-hook-form'; | ||||
| import { FormControl } from '@/components/ui/form'; | import { FormControl } from '@/components/ui/form'; | ||||
| import { useCallback, useEffect } from 'react'; | |||||
| import { forwardRef, useCallback, useEffect } from 'react'; | |||||
| const Select = SelectPrimitive.Root; | const Select = SelectPrimitive.Root; | ||||
| React.ElementRef<typeof SelectPrimitive.Trigger>, | React.ElementRef<typeof SelectPrimitive.Trigger>, | ||||
| React.ComponentPropsWithoutRef<typeof SelectPrimitive.Trigger> & { | React.ComponentPropsWithoutRef<typeof SelectPrimitive.Trigger> & { | ||||
| onReset?: () => void; | onReset?: () => void; | ||||
| allowClear?: boolean; | |||||
| } | } | ||||
| >(({ className, children, value, onReset, ...props }, ref) => ( | |||||
| >(({ className, children, value, onReset, allowClear, ...props }, ref) => ( | |||||
| <SelectPrimitive.Trigger | <SelectPrimitive.Trigger | ||||
| ref={ref} | ref={ref} | ||||
| className={cn( | className={cn( | ||||
| event.stopPropagation(); | event.stopPropagation(); | ||||
| }} | }} | ||||
| > | > | ||||
| {value ? ( | |||||
| {value && allowClear ? ( | |||||
| <X className="h-4 w-4 opacity-50 cursor-pointer" onClick={onReset} /> | <X className="h-4 w-4 opacity-50 cursor-pointer" onClick={onReset} /> | ||||
| ) : ( | ) : ( | ||||
| <ChevronDown className="h-4 w-4 opacity-50" /> | <ChevronDown className="h-4 w-4 opacity-50" /> | ||||
| type RAGFlowSelectProps = Partial<ControllerRenderProps> & { | type RAGFlowSelectProps = Partial<ControllerRenderProps> & { | ||||
| FormControlComponent?: typeof FormControl; | FormControlComponent?: typeof FormControl; | ||||
| options?: (RAGFlowSelectOptionType | RAGFlowSelectGroupOptionType)[]; | options?: (RAGFlowSelectOptionType | RAGFlowSelectGroupOptionType)[]; | ||||
| allowClear?: boolean; | |||||
| }; | }; | ||||
| /** | /** | ||||
| * } | * } | ||||
| * @return {*} | * @return {*} | ||||
| */ | */ | ||||
| export function RAGFlowSelect({ | |||||
| value: initialValue, | |||||
| onChange, | |||||
| FormControlComponent, | |||||
| options = [], | |||||
| }: RAGFlowSelectProps) { | |||||
| export const RAGFlowSelect = forwardRef< | |||||
| React.ElementRef<typeof SelectPrimitive.Trigger>, | |||||
| RAGFlowSelectProps | |||||
| >(function ( | |||||
| { | |||||
| value: initialValue, | |||||
| onChange, | |||||
| FormControlComponent, | |||||
| options = [], | |||||
| allowClear, | |||||
| }, | |||||
| ref, | |||||
| ) { | |||||
| const [key, setKey] = React.useState(+new Date()); | const [key, setKey] = React.useState(+new Date()); | ||||
| const [value, setValue] = React.useState<string | undefined>(undefined); | const [value, setValue] = React.useState<string | undefined>(undefined); | ||||
| const FormControlWidget = FormControlComponent | const FormControlWidget = FormControlComponent | ||||
| ? FormControlComponent | ? FormControlComponent | ||||
| : React.Fragment; | |||||
| : ({ children }: React.PropsWithChildren) => <div>{children}</div>; | |||||
| const handleChange = useCallback( | const handleChange = useCallback( | ||||
| (val?: string) => { | (val?: string) => { | ||||
| className="bg-colors-background-inverse-weak" | className="bg-colors-background-inverse-weak" | ||||
| value={value} | value={value} | ||||
| onReset={handleReset} | onReset={handleReset} | ||||
| allowClear={allowClear} | |||||
| ref={ref} | |||||
| > | > | ||||
| <SelectValue placeholder="Select a verified email to display" /> | <SelectValue placeholder="Select a verified email to display" /> | ||||
| </SelectTrigger> | </SelectTrigger> | ||||
| </SelectContent> | </SelectContent> | ||||
| </Select> | </Select> | ||||
| ); | ); | ||||
| } | |||||
| }); |
| ToastViewport.displayName = ToastPrimitives.Viewport.displayName; | ToastViewport.displayName = ToastPrimitives.Viewport.displayName; | ||||
| const toastVariants = cva( | const toastVariants = cva( | ||||
| 'group pointer-events-auto relative flex w-full items-center justify-between space-x-4 overflow-hidden rounded-md border p-6 pr-8 shadow-lg transition-all data-[swipe=cancel]:translate-x-0 data-[swipe=end]:translate-x-[var(--radix-toast-swipe-end-x)] data-[swipe=move]:translate-x-[var(--radix-toast-swipe-move-x)] data-[swipe=move]:transition-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[swipe=end]:animate-out data-[state=closed]:fade-out-80 data-[state=closed]:slide-out-to-right-full data-[state=open]:slide-in-from-top-full data-[state=open]:sm:slide-in-from-bottom-full', | |||||
| 'group pointer-events-auto relative flex w-full items-center justify-between space-x-2 overflow-hidden rounded-md border p-4 pr-6 shadow-lg transition-all data-[swipe=cancel]:translate-x-0 data-[swipe=end]:translate-x-[var(--radix-toast-swipe-end-x)] data-[swipe=move]:translate-x-[var(--radix-toast-swipe-move-x)] data-[swipe=move]:transition-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[swipe=end]:animate-out data-[state=closed]:fade-out-80 data-[state=closed]:slide-out-to-right-full data-[state=open]:slide-in-from-top-full data-[state=open]:sm:slide-in-from-bottom-full', | |||||
| { | { | ||||
| variants: { | variants: { | ||||
| variant: { | variant: { | ||||
| <ToastPrimitives.Action | <ToastPrimitives.Action | ||||
| ref={ref} | ref={ref} | ||||
| className={cn( | className={cn( | ||||
| 'inline-flex h-8 shrink-0 items-center justify-center rounded-md border bg-transparent px-3 text-sm font-medium ring-offset-background transition-colors hover:bg-secondary focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 group-[.destructive]:border-muted/40 group-[.destructive]:hover:border-destructive/30 group-[.destructive]:hover:bg-destructive group-[.destructive]:hover:text-destructive-foreground group-[.destructive]:focus:ring-destructive', | |||||
| 'inline-flex h-8 shrink-0 items-center justify-center rounded-md border bg-transparent px-3 text-sm font-medium transition-colors hover:bg-secondary focus:outline-none focus:ring-1 focus:ring-ring disabled:pointer-events-none disabled:opacity-50 group-[.destructive]:border-muted/40 group-[.destructive]:hover:border-destructive/30 group-[.destructive]:hover:bg-destructive group-[.destructive]:hover:text-destructive-foreground group-[.destructive]:focus:ring-destructive', | |||||
| className, | className, | ||||
| )} | )} | ||||
| {...props} | {...props} | ||||
| <ToastPrimitives.Close | <ToastPrimitives.Close | ||||
| ref={ref} | ref={ref} | ||||
| className={cn( | className={cn( | ||||
| 'absolute right-2 top-2 rounded-md p-1 text-foreground/50 opacity-0 transition-opacity hover:text-foreground focus:opacity-100 focus:outline-none focus:ring-2 group-hover:opacity-100 group-[.destructive]:text-red-300 group-[.destructive]:hover:text-red-50 group-[.destructive]:focus:ring-red-400 group-[.destructive]:focus:ring-offset-red-600', | |||||
| 'absolute right-1 top-1 rounded-md p-1 text-foreground/50 opacity-0 transition-opacity hover:text-foreground focus:opacity-100 focus:outline-none focus:ring-1 group-hover:opacity-100 group-[.destructive]:text-red-300 group-[.destructive]:hover:text-red-50 group-[.destructive]:focus:ring-red-400 group-[.destructive]:focus:ring-offset-red-600', | |||||
| className, | className, | ||||
| )} | )} | ||||
| toast-close="" | toast-close="" | ||||
| >(({ className, ...props }, ref) => ( | >(({ className, ...props }, ref) => ( | ||||
| <ToastPrimitives.Title | <ToastPrimitives.Title | ||||
| ref={ref} | ref={ref} | ||||
| className={cn('text-sm font-semibold', className)} | |||||
| className={cn('text-sm font-semibold [&+div]:text-xs', className)} | |||||
| {...props} | {...props} | ||||
| /> | /> | ||||
| )); | )); |
| return ( | return ( | ||||
| <ToastProvider> | <ToastProvider> | ||||
| {toasts.map(function ({ id, title, description, action, ...props }: any) { | |||||
| {toasts.map(function ({ id, title, description, action, ...props }) { | |||||
| return ( | return ( | ||||
| <Toast key={id} {...props}> | <Toast key={id} {...props}> | ||||
| <div className="grid gap-1"> | <div className="grid gap-1"> |
| export const SupportedPreviewDocumentTypes = [...ExceptiveType]; | export const SupportedPreviewDocumentTypes = [...ExceptiveType]; | ||||
| //#endregion | //#endregion | ||||
| export enum Platform { | |||||
| RAGFlow = 'RAGFlow', | |||||
| Dify = 'Dify', | |||||
| FastGPT = 'FastGPT', | |||||
| Coze = 'Coze', | |||||
| } |
| import { FileMimeType } from '@/constants/common'; | |||||
| import { useToast } from '@/components/hooks/use-toast'; | |||||
| import { FileMimeType, Platform } from '@/constants/common'; | |||||
| import { useSetModalState } from '@/hooks/common-hooks'; | import { useSetModalState } from '@/hooks/common-hooks'; | ||||
| import { useFetchFlow } from '@/hooks/flow-hooks'; | import { useFetchFlow } from '@/hooks/flow-hooks'; | ||||
| import { IGraph } from '@/interfaces/database/flow'; | import { IGraph } from '@/interfaces/database/flow'; | ||||
| import { downloadJsonFile } from '@/utils/file-util'; | import { downloadJsonFile } from '@/utils/file-util'; | ||||
| import { message, UploadFile } from 'antd'; | |||||
| import { message } from 'antd'; | |||||
| import isEmpty from 'lodash/isEmpty'; | import isEmpty from 'lodash/isEmpty'; | ||||
| import { useCallback } from 'react'; | import { useCallback } from 'react'; | ||||
| import { useTranslation } from 'react-i18next'; | import { useTranslation } from 'react-i18next'; | ||||
| const setGraphInfo = useSetGraphInfo(); | const setGraphInfo = useSetGraphInfo(); | ||||
| const { data } = useFetchFlow(); | const { data } = useFetchFlow(); | ||||
| const { t } = useTranslation(); | const { t } = useTranslation(); | ||||
| const { toast } = useToast(); | |||||
| const onFileUploadOk = useCallback( | const onFileUploadOk = useCallback( | ||||
| async (fileList: UploadFile[]) => { | |||||
| async ({ | |||||
| fileList, | |||||
| platform, | |||||
| }: { | |||||
| fileList: File[]; | |||||
| platform: Platform; | |||||
| }) => { | |||||
| console.log('🚀 ~ useHandleExportOrImportJsonFile ~ platform:', platform); | |||||
| if (fileList.length > 0) { | if (fileList.length > 0) { | ||||
| const file: File = fileList[0] as unknown as File; | |||||
| const file = fileList[0]; | |||||
| if (file.type !== FileMimeType.Json) { | if (file.type !== FileMimeType.Json) { | ||||
| message.error(t('flow.jsonUploadTypeErrorMessage')); | |||||
| toast({ title: t('flow.jsonUploadTypeErrorMessage') }); | |||||
| return; | return; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| }, | }, | ||||
| [hideFileUploadModal, setGraphInfo, t], | |||||
| [hideFileUploadModal, setGraphInfo, t, toast], | |||||
| ); | ); | ||||
| const handleExportJson = useCallback(() => { | const handleExportJson = useCallback(() => { |
| import { PageHeader } from '@/components/page-header'; | import { PageHeader } from '@/components/page-header'; | ||||
| import { Button } from '@/components/ui/button'; | import { Button } from '@/components/ui/button'; | ||||
| import { | |||||
| DropdownMenu, | |||||
| DropdownMenuContent, | |||||
| DropdownMenuItem, | |||||
| DropdownMenuSeparator, | |||||
| DropdownMenuTrigger, | |||||
| } from '@/components/ui/dropdown-menu'; | |||||
| import { SidebarProvider, SidebarTrigger } from '@/components/ui/sidebar'; | import { SidebarProvider, SidebarTrigger } from '@/components/ui/sidebar'; | ||||
| import { useSetModalState } from '@/hooks/common-hooks'; | import { useSetModalState } from '@/hooks/common-hooks'; | ||||
| import { useNavigatePage } from '@/hooks/logic-hooks/navigate-hooks'; | import { useNavigatePage } from '@/hooks/logic-hooks/navigate-hooks'; | ||||
| import { Trash2 } from 'lucide-react'; | |||||
| import { CodeXml, EllipsisVertical, Forward, Import, Key } from 'lucide-react'; | |||||
| import { ComponentPropsWithoutRef } from 'react'; | |||||
| import { useTranslation } from 'react-i18next'; | |||||
| import { AgentSidebar } from './agent-sidebar'; | import { AgentSidebar } from './agent-sidebar'; | ||||
| import FlowCanvas from './canvas'; | import FlowCanvas from './canvas'; | ||||
| import { useHandleExportOrImportJsonFile } from './hooks/use-export-json'; | |||||
| import { useFetchDataOnMount } from './hooks/use-fetch-data'; | import { useFetchDataOnMount } from './hooks/use-fetch-data'; | ||||
| import { useOpenDocument } from './hooks/use-open-document'; | |||||
| import { UploadAgentDialog } from './upload-agent-dialog'; | |||||
| function AgentDropdownMenuItem({ | |||||
| children, | |||||
| ...props | |||||
| }: ComponentPropsWithoutRef<typeof DropdownMenuItem>) { | |||||
| return ( | |||||
| <DropdownMenuItem className="flex justify-between items-center" {...props}> | |||||
| {children} | |||||
| </DropdownMenuItem> | |||||
| ); | |||||
| } | |||||
| export default function Agent() { | export default function Agent() { | ||||
| const { navigateToAgentList } = useNavigatePage(); | const { navigateToAgentList } = useNavigatePage(); | ||||
| hideModal: hideChatDrawer, | hideModal: hideChatDrawer, | ||||
| showModal: showChatDrawer, | showModal: showChatDrawer, | ||||
| } = useSetModalState(); | } = useSetModalState(); | ||||
| const { t } = useTranslation(); | |||||
| const openDocument = useOpenDocument(); | |||||
| const { | |||||
| handleExportJson, | |||||
| handleImportJson, | |||||
| fileUploadVisible, | |||||
| onFileUploadOk, | |||||
| hideFileUploadModal, | |||||
| } = useHandleExportOrImportJsonFile(); | |||||
| useFetchDataOnMount(); | useFetchDataOnMount(); | ||||
| <section> | <section> | ||||
| <PageHeader back={navigateToAgentList} title="Agent 01"> | <PageHeader back={navigateToAgentList} title="Agent 01"> | ||||
| <div className="flex items-center gap-2"> | <div className="flex items-center gap-2"> | ||||
| <Button variant={'icon'} size={'icon'}> | |||||
| <Trash2 /> | |||||
| </Button> | |||||
| <DropdownMenu> | |||||
| <DropdownMenuTrigger> | |||||
| <Button variant={'icon'} size={'icon'}> | |||||
| <EllipsisVertical /> | |||||
| </Button> | |||||
| </DropdownMenuTrigger> | |||||
| <DropdownMenuContent> | |||||
| <AgentDropdownMenuItem onClick={openDocument}> | |||||
| API | |||||
| <Key /> | |||||
| </AgentDropdownMenuItem> | |||||
| <DropdownMenuSeparator /> | |||||
| <AgentDropdownMenuItem onClick={handleImportJson}> | |||||
| Import | |||||
| <Import /> | |||||
| </AgentDropdownMenuItem> | |||||
| <DropdownMenuSeparator /> | |||||
| <AgentDropdownMenuItem onClick={handleExportJson}> | |||||
| Export | |||||
| <Forward /> | |||||
| </AgentDropdownMenuItem> | |||||
| <DropdownMenuSeparator /> | |||||
| <AgentDropdownMenuItem> | |||||
| {t('common.embedIntoSite')} | |||||
| <CodeXml /> | |||||
| </AgentDropdownMenuItem> | |||||
| </DropdownMenuContent> | |||||
| </DropdownMenu> | |||||
| <Button variant={'outline'} size={'sm'}> | <Button variant={'outline'} size={'sm'}> | ||||
| Save | Save | ||||
| </Button> | </Button> | ||||
| <Button variant={'outline'} size={'sm'}> | |||||
| API | |||||
| </Button> | |||||
| <Button variant={'outline'} size={'sm'}> | <Button variant={'outline'} size={'sm'}> | ||||
| Run app | Run app | ||||
| </Button> | </Button> | ||||
| </div> | </div> | ||||
| </SidebarProvider> | </SidebarProvider> | ||||
| </div> | </div> | ||||
| {fileUploadVisible && ( | |||||
| <UploadAgentDialog | |||||
| hideModal={hideFileUploadModal} | |||||
| onOk={onFileUploadOk} | |||||
| ></UploadAgentDialog> | |||||
| )} | |||||
| </section> | </section> | ||||
| ); | ); | ||||
| } | } |
| import { | |||||
| Dialog, | |||||
| DialogContent, | |||||
| DialogFooter, | |||||
| DialogHeader, | |||||
| DialogTitle, | |||||
| } from '@/components/ui/dialog'; | |||||
| import { LoadingButton } from '@/components/ui/loading-button'; | |||||
| import { IModalProps } from '@/interfaces/common'; | |||||
| import { TagRenameId } from '@/pages/add-knowledge/constant'; | |||||
| import { useTranslation } from 'react-i18next'; | |||||
| import { UploadAgentForm } from './upload-agent-form'; | |||||
| export function UploadAgentDialog({ | |||||
| hideModal, | |||||
| onOk, | |||||
| loading, | |||||
| }: IModalProps<any>) { | |||||
| const { t } = useTranslation(); | |||||
| return ( | |||||
| <Dialog open onOpenChange={hideModal}> | |||||
| <DialogContent className="sm:max-w-[425px]"> | |||||
| <DialogHeader> | |||||
| <DialogTitle>{t('fileManager.uploadFile')}</DialogTitle> | |||||
| </DialogHeader> | |||||
| <UploadAgentForm hideModal={hideModal} onOk={onOk}></UploadAgentForm> | |||||
| <DialogFooter> | |||||
| <LoadingButton type="submit" form={TagRenameId} loading={loading}> | |||||
| {t('common.save')} | |||||
| </LoadingButton> | |||||
| </DialogFooter> | |||||
| </DialogContent> | |||||
| </Dialog> | |||||
| ); | |||||
| } |
| 'use client'; | |||||
| import { zodResolver } from '@hookform/resolvers/zod'; | |||||
| import { useForm } from 'react-hook-form'; | |||||
| import { z } from 'zod'; | |||||
| import { FileUploader } from '@/components/file-uploader'; | |||||
| import { | |||||
| Form, | |||||
| FormControl, | |||||
| FormField, | |||||
| FormItem, | |||||
| FormLabel, | |||||
| FormMessage, | |||||
| } from '@/components/ui/form'; | |||||
| import { RAGFlowSelect } from '@/components/ui/select'; | |||||
| import { FileMimeType, Platform } from '@/constants/common'; | |||||
| import { IModalProps } from '@/interfaces/common'; | |||||
| import { TagRenameId } from '@/pages/add-knowledge/constant'; | |||||
| import { useTranslation } from 'react-i18next'; | |||||
| const options = Object.values(Platform).map((x) => ({ label: x, value: x })); | |||||
| export function UploadAgentForm({ hideModal, onOk }: IModalProps<any>) { | |||||
| const { t } = useTranslation(); | |||||
| const FormSchema = z.object({ | |||||
| platform: z | |||||
| .string() | |||||
| .min(1, { | |||||
| message: t('common.namePlaceholder'), | |||||
| }) | |||||
| .trim(), | |||||
| fileList: z.array(z.instanceof(File)), | |||||
| }); | |||||
| const form = useForm<z.infer<typeof FormSchema>>({ | |||||
| resolver: zodResolver(FormSchema), | |||||
| defaultValues: { platform: Platform.RAGFlow }, | |||||
| }); | |||||
| async function onSubmit(data: z.infer<typeof FormSchema>) { | |||||
| console.log('🚀 ~ onSubmit ~ data:', data); | |||||
| const ret = await onOk?.(data); | |||||
| if (ret) { | |||||
| hideModal?.(); | |||||
| } | |||||
| } | |||||
| return ( | |||||
| <Form {...form}> | |||||
| <form | |||||
| onSubmit={form.handleSubmit(onSubmit)} | |||||
| className="space-y-6" | |||||
| id={TagRenameId} | |||||
| > | |||||
| <FormField | |||||
| control={form.control} | |||||
| name="fileList" | |||||
| render={({ field }) => ( | |||||
| <FormItem> | |||||
| <FormLabel>{t('common.name')}</FormLabel> | |||||
| <FormControl> | |||||
| <FileUploader | |||||
| value={field.value} | |||||
| onValueChange={field.onChange} | |||||
| maxFileCount={1} | |||||
| maxSize={4 * 1024 * 1024} | |||||
| accept={{ '*.json': [FileMimeType.Json] }} | |||||
| /> | |||||
| </FormControl> | |||||
| <FormMessage /> | |||||
| </FormItem> | |||||
| )} | |||||
| /> | |||||
| <FormField | |||||
| control={form.control} | |||||
| name="platform" | |||||
| render={({ field }) => ( | |||||
| <FormItem> | |||||
| <FormLabel>{t('common.name')}</FormLabel> | |||||
| <FormControl> | |||||
| <RAGFlowSelect {...field} options={options} /> | |||||
| </FormControl> | |||||
| <FormMessage /> | |||||
| </FormItem> | |||||
| )} | |||||
| /> | |||||
| </form> | |||||
| </Form> | |||||
| ); | |||||
| } |