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

@ -10,14 +10,14 @@ import { RETRIEVE_METHOD } from '@/types/app'
import EmbeddingProcess from '../index'
const mockPush = vi.fn()
vi.mock('next/navigation', () => ({
vi.mock('@/next/navigation', () => ({
useRouter: () => ({
push: mockPush,
}),
}))
// Mock next/link
vi.mock('next/link', () => ({
vi.mock('@/next/link', () => ({
default: function MockLink({ children, href, ...props }: { children: React.ReactNode, href: string }) {
return <a href={href} {...props}>{children}</a>
},

View File

@ -6,14 +6,6 @@ import { ProcessMode } from '@/models/datasets'
import { RETRIEVE_METHOD } from '@/types/app'
import RuleDetail from '../rule-detail'
// Override global next/image auto-mock: tests assert on data-testid="next-image" and src attributes
vi.mock('next/image', () => ({
default: function MockImage({ src, alt, className }: { src: string, alt: string, className?: string }) {
// eslint-disable-next-line next/no-img-element
return <img src={src} alt={alt} className={className} data-testid="next-image" />
},
}))
// Mock FieldInfo component
vi.mock('@/app/components/datasets/documents/detail/metadata', () => ({
FieldInfo: ({ label, displayedValue, valueIcon }: { label: string, displayedValue: string, valueIcon?: React.ReactNode }) => (
@ -184,16 +176,16 @@ describe('RuleDetail', () => {
})
it('should show high_quality icon for qualified indexing', () => {
render(<RuleDetail indexingType={IndexingType.QUALIFIED} />)
const { container } = render(<RuleDetail indexingType={IndexingType.QUALIFIED} />)
const images = screen.getAllByTestId('next-image')
const images = container.querySelectorAll('img')
expect(images[0]).toHaveAttribute('src', '/icons/high_quality.svg')
})
it('should show economical icon for economical indexing', () => {
render(<RuleDetail indexingType={IndexingType.ECONOMICAL} />)
const { container } = render(<RuleDetail indexingType={IndexingType.ECONOMICAL} />)
const images = screen.getAllByTestId('next-image')
const images = container.querySelectorAll('img')
expect(images[0]).toHaveAttribute('src', '/icons/economical.svg')
})
})
@ -256,38 +248,38 @@ describe('RuleDetail', () => {
})
it('should show vector icon for semantic search', () => {
render(
const { container } = render(
<RuleDetail
indexingType={IndexingType.QUALIFIED}
retrievalMethod={RETRIEVE_METHOD.semantic}
/>,
)
const images = screen.getAllByTestId('next-image')
const images = container.querySelectorAll('img')
expect(images[1]).toHaveAttribute('src', '/icons/vector.svg')
})
it('should show fullText icon for full text search', () => {
render(
const { container } = render(
<RuleDetail
indexingType={IndexingType.QUALIFIED}
retrievalMethod={RETRIEVE_METHOD.fullText}
/>,
)
const images = screen.getAllByTestId('next-image')
const images = container.querySelectorAll('img')
expect(images[1]).toHaveAttribute('src', '/icons/fullText.svg')
})
it('should show hybrid icon for hybrid search', () => {
render(
const { container } = render(
<RuleDetail
indexingType={IndexingType.QUALIFIED}
retrievalMethod={RETRIEVE_METHOD.hybrid}
/>,
)
const images = screen.getAllByTestId('next-image')
const images = container.querySelectorAll('img')
expect(images[1]).toHaveAttribute('src', '/icons/hybrid.svg')
})
})
@ -308,9 +300,9 @@ describe('RuleDetail', () => {
})
it('should handle undefined retrievalMethod with defined indexingType', () => {
render(<RuleDetail indexingType={IndexingType.QUALIFIED} />)
const { container } = render(<RuleDetail indexingType={IndexingType.QUALIFIED} />)
const images = screen.getAllByTestId('next-image')
const images = container.querySelectorAll('img')
// When retrievalMethod is undefined, vector icon is used as default
expect(images[1]).toHaveAttribute('src', '/icons/vector.svg')
})

View File

@ -10,8 +10,6 @@ import {
RiLoader2Fill,
RiTerminalBoxLine,
} from '@remixicon/react'
import Link from 'next/link'
import { useRouter } from 'next/navigation'
import * as React from 'react'
import { useEffect, useMemo, useState } from 'react'
import { useTranslation } from 'react-i18next'
@ -26,6 +24,8 @@ import DocumentFileIcon from '@/app/components/datasets/common/document-file-ico
import { useProviderContext } from '@/context/provider-context'
import { useDatasetApiAccessUrl } from '@/hooks/use-api-access-url'
import { DatasourceType } from '@/models/pipeline'
import Link from '@/next/link'
import { useRouter } from '@/next/navigation'
import { useIndexingStatusBatch, useProcessRule } from '@/service/knowledge/use-dataset'
import { useInvalidDocumentList } from '@/service/knowledge/use-document'
import { cn } from '@/utils/classnames'

View File

@ -1,5 +1,4 @@
import type { ProcessRuleResponse } from '@/models/datasets'
import Image from 'next/image'
import * as React from 'react'
import { useCallback } from 'react'
import { useTranslation } from 'react-i18next'
@ -50,7 +49,7 @@ const RuleDetail = ({
label={t('stepTwo.indexMode', { ns: 'datasetCreation' })}
displayedValue={t(`stepTwo.${indexingType === IndexingType.ECONOMICAL ? 'economical' : 'qualified'}`, { ns: 'datasetCreation' }) as string}
valueIcon={(
<Image
<img
className="size-4"
src={
indexingType === IndexingType.ECONOMICAL
@ -65,7 +64,7 @@ const RuleDetail = ({
label={t('form.retrievalSetting.title', { ns: 'datasetSettings' })}
displayedValue={t(`retrieval.${indexingType === IndexingType.ECONOMICAL ? 'keyword_search' : retrievalMethod ?? 'semantic_search'}.title`, { ns: 'dataset' })}
valueIcon={(
<Image
<img
className="size-4"
src={
retrievalMethod === RETRIEVE_METHOD.fullText