Merge main HEAD (segment 5) into sandboxed-agent-rebase

Resolve 83 conflicts: 10 backend, 62 frontend, 11 config/lock files.
Preserve sandbox/agent/collaboration features while adopting main's
UI refactorings (Dialog/AlertDialog/Popover), model provider updates,
and enterprise features.

Made-with: Cursor
This commit is contained in:
Novice
2026-03-23 14:20:06 +08:00
1671 changed files with 124822 additions and 22302 deletions

View File

@ -70,11 +70,11 @@ vi.mock('@/app/components/tools/edit-custom-collection-modal', () => ({
},
}))
// Mock Toast
const mockToastNotify = vi.fn()
vi.mock('@/app/components/base/toast', () => ({
default: {
notify: (options: { type: string, message: string }) => mockToastNotify(options),
// Mock toast
const mockToastSuccess = vi.fn()
vi.mock('@/app/components/base/ui/toast', () => ({
toast: {
success: (title: string) => mockToastSuccess(title),
},
}))
@ -198,10 +198,7 @@ describe('CustomCreateCard', () => {
fireEvent.click(screen.getByTestId('submit-modal'))
await waitFor(() => {
expect(mockToastNotify).toHaveBeenCalledWith({
type: 'success',
message: expect.any(String),
})
expect(mockToastSuccess).toHaveBeenCalledWith(expect.any(String))
})
})

View File

@ -92,8 +92,13 @@ vi.mock('@/app/components/base/confirm', () => ({
: null,
}))
vi.mock('@/app/components/base/toast', () => ({
default: { notify: vi.fn() },
const mockToastSuccess = vi.hoisted(() => vi.fn())
const mockToastError = vi.hoisted(() => vi.fn())
vi.mock('@/app/components/base/ui/toast', () => ({
toast: {
success: mockToastSuccess,
error: mockToastError,
},
}))
vi.mock('@/app/components/header/indicator', () => ({

View File

@ -5,7 +5,7 @@ import {
} from '@remixicon/react'
import { useState } from 'react'
import { useTranslation } from 'react-i18next'
import Toast from '@/app/components/base/toast'
import { toast } from '@/app/components/base/ui/toast'
import EditCustomToolModal from '@/app/components/tools/edit-custom-collection-modal'
import { useAppContext } from '@/context/app-context'
import { createCustomCollection } from '@/service/tools'
@ -21,10 +21,7 @@ const Contribute = ({ onRefreshData }: Props) => {
const [isShowEditCollectionToolModal, setIsShowEditCustomCollectionModal] = useState(false)
const doCreateCustomToolCollection = async (data: CustomCollectionBackend) => {
await createCustomCollection(data)
Toast.notify({
type: 'success',
message: t('api.actionSuccess', { ns: 'common' }),
})
toast.success(t('api.actionSuccess', { ns: 'common' }))
setIsShowEditCustomCollectionModal(false)
onRefreshData()
}

View File

@ -13,7 +13,7 @@ import Confirm from '@/app/components/base/confirm'
import Drawer from '@/app/components/base/drawer'
import { LinkExternal02, Settings01 } from '@/app/components/base/icons/src/vender/line/general'
import Loading from '@/app/components/base/loading'
import Toast from '@/app/components/base/toast'
import { toast } from '@/app/components/base/ui/toast'
import { ConfigurationMethodEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
import Indicator from '@/app/components/header/indicator'
import Icon from '@/app/components/plugins/card/base/card-icon'
@ -122,19 +122,13 @@ const ProviderDetail = ({
await getCustomProvider()
// Use fresh data from form submission to avoid race condition with collection.labels
setCustomCollection(prev => prev ? { ...prev, labels: data.labels } : null)
Toast.notify({
type: 'success',
message: t('api.actionSuccess', { ns: 'common' }),
})
toast.success(t('api.actionSuccess', { ns: 'common' }))
setIsShowEditCustomCollectionModal(false)
}
const doRemoveCustomToolCollection = async () => {
await removeCustomCollection(collection?.name as string)
onRefreshData()
Toast.notify({
type: 'success',
message: t('api.actionSuccess', { ns: 'common' }),
})
toast.success(t('api.actionSuccess', { ns: 'common' }))
setIsShowEditCustomCollectionModal(false)
}
// workflow provider
@ -161,10 +155,7 @@ const ProviderDetail = ({
const removeWorkflowToolProvider = async () => {
await deleteWorkflowTool(collection.id)
onRefreshData()
Toast.notify({
type: 'success',
message: t('api.actionSuccess', { ns: 'common' }),
})
toast.success(t('api.actionSuccess', { ns: 'common' }))
setIsShowEditWorkflowToolModal(false)
}
const updateWorkflowToolProvider = async (data: WorkflowToolProviderRequest & Partial<{
@ -175,10 +166,7 @@ const ProviderDetail = ({
invalidateAllWorkflowTools()
onRefreshData()
getWorkflowToolProvider()
Toast.notify({
type: 'success',
message: t('api.actionSuccess', { ns: 'common' }),
})
toast.success(t('api.actionSuccess', { ns: 'common' }))
setIsShowEditWorkflowToolModal(false)
}
const onClickCustomToolDelete = () => {
@ -385,19 +373,13 @@ const ProviderDetail = ({
onCancel={() => setShowSettingAuth(false)}
onSaved={async (value) => {
await updateBuiltInToolCredential(collection.name, value)
Toast.notify({
type: 'success',
message: t('api.actionSuccess', { ns: 'common' }),
})
toast.success(t('api.actionSuccess', { ns: 'common' }))
await onRefreshData()
setShowSettingAuth(false)
}}
onRemove={async () => {
await removeBuiltInToolCredential(collection.name)
Toast.notify({
type: 'success',
message: t('api.actionSuccess', { ns: 'common' }),
})
toast.success(t('api.actionSuccess', { ns: 'common' }))
await onRefreshData()
setShowSettingAuth(false)
}}

View File

@ -1,8 +1,8 @@
'use client'
import { RiArrowRightUpLine } from '@remixicon/react'
import Link from 'next/link'
import { useTranslation } from 'react-i18next'
import useTheme from '@/hooks/use-theme'
import Link from '@/next/link'
import { cn } from '@/utils/classnames'
import { NoToolPlaceholder } from '../../base/icons/src/vender/other'
import { ToolTypeEnum } from '../../workflow/block-selector/types'