diff --git a/src/renderer/src/pages/knowledge/__tests__/AdvancedSettingsPanel.test.tsx b/src/renderer/src/pages/knowledge/__tests__/AdvancedSettingsPanel.test.tsx index 8bb50c250f..4c7740db0d 100644 --- a/src/renderer/src/pages/knowledge/__tests__/AdvancedSettingsPanel.test.tsx +++ b/src/renderer/src/pages/knowledge/__tests__/AdvancedSettingsPanel.test.tsx @@ -12,7 +12,10 @@ const mocks = vi.hoisted(() => { 'knowledge.chunk_size': '分块大小', 'knowledge.chunk_overlap': '分块重叠', 'knowledge.threshold': '检索相似度阈值', - 'knowledge.chunk_size_change_warning': '避免修改这个高级设置。' + 'knowledge.chunk_size_change_warning': '避免修改这个高级设置。', + 'settings.tool.preprocess.title': '文档预处理', + 'models.rerank_model': '重排模型', + 'settings.models.empty': '未选择' } return translations[k] || k } @@ -20,7 +23,9 @@ const mocks = vi.hoisted(() => { handlers: { handleChunkSizeChange: vi.fn(), handleChunkOverlapChange: vi.fn(), - handleThresholdChange: vi.fn() + handleThresholdChange: vi.fn(), + handleDocPreprocessChange: vi.fn(), + handleRerankModelChange: vi.fn() } } }) @@ -53,9 +58,39 @@ vi.mock('antd', () => ({ disabled={disabled} style={style} /> + ), + Select: ({ value, onChange, options, placeholder }: any) => ( + ) })) +vi.mock('@renderer/components/ModelSelector', () => ({ + default: ({ value, onChange, placeholder }: any) => ( + + ) +})) + +vi.mock('@renderer/hooks/useProvider', () => ({ + useProviders: () => ({ providers: [] }) +})) + +vi.mock('@renderer/services/ModelService', () => ({ + getModelUniqId: (model: any) => model?.id || '' +})) + +vi.mock('@renderer/config/models', () => ({ + isRerankModel: () => true +})) + /** * 创建测试用的 KnowledgeBase 对象 * @param overrides 可选的属性覆盖 @@ -91,7 +126,9 @@ describe('AdvancedSettingsPanel', () => { describe('basic rendering', () => { it('should match snapshot', () => { - const { container } = render() + const { container } = render( + + ) expect(container.firstChild).toMatchSnapshot() }) @@ -99,7 +136,7 @@ describe('AdvancedSettingsPanel', () => { describe('handlers', () => { it('should call handlers when values are changed', () => { - render() + render() const chunkSizeInput = screen.getByLabelText('分块大小') fireEvent.change(chunkSizeInput, { target: { value: '600' } }) diff --git a/src/renderer/src/pages/knowledge/__tests__/GeneralSettingsPanel.test.tsx b/src/renderer/src/pages/knowledge/__tests__/GeneralSettingsPanel.test.tsx index 64c566ac2d..13bf26b351 100644 --- a/src/renderer/src/pages/knowledge/__tests__/GeneralSettingsPanel.test.tsx +++ b/src/renderer/src/pages/knowledge/__tests__/GeneralSettingsPanel.test.tsx @@ -1,4 +1,4 @@ -import type { KnowledgeBase, Model, PreprocessProvider } from '@renderer/types' +import type { KnowledgeBase, Model } from '@renderer/types' import { fireEvent, render, screen } from '@testing-library/react' import { userEvent } from '@testing-library/user-event' import { beforeEach, describe, expect, it, vi } from 'vitest' @@ -24,9 +24,7 @@ const mocks = vi.hoisted(() => ({ ], handlers: { handleEmbeddingModelChange: vi.fn(), - handleDimensionChange: vi.fn(), - handleRerankModelChange: vi.fn(), - handleDocPreprocessChange: vi.fn() + handleDimensionChange: vi.fn() } })) @@ -41,11 +39,7 @@ vi.mock('@renderer/components/TooltipIcons', () => ({ // Mock ModelSelector component vi.mock('@renderer/components/ModelSelector', () => ({ - default: ({ value, onChange, placeholder, allowClear, providers, predicate }: any) => { - // Determine if this is for embedding or rerank models based on predicate - const isEmbedding = predicate?.toString().includes('embedding') - const isRerank = predicate?.toString().includes('rerank') - + default: ({ value, onChange, placeholder, allowClear, providers }: any) => { // Use providers parameter to avoid lint error const hasProviders = providers && providers.length > 0 @@ -56,21 +50,10 @@ vi.mock('@renderer/components/ModelSelector', () => ({ onChange={(e) => onChange?.(e.target.value)} data-placeholder={placeholder} data-allow-clear={allowClear} - data-model-type={isEmbedding ? 'embedding' : isRerank ? 'rerank' : 'unknown'} data-has-providers={hasProviders}> - {isEmbedding && ( - <> - - - - )} - {isRerank && ( - <> - - - - )} + + ) } @@ -102,8 +85,7 @@ vi.mock('@renderer/services/ModelService', () => ({ // Mock model predicates vi.mock('@renderer/config/models', () => ({ - isEmbeddingModel: (model: Model) => model.group === 'embedding', - isRerankModel: (model: Model) => model.group === 'rerank' + isEmbeddingModel: (model: Model) => model.group === 'embedding' })) // Mock constant @@ -121,22 +103,6 @@ vi.mock('antd', () => ({ Input: ({ value, onChange, placeholder }: any) => ( ), - Select: ({ value, onChange, placeholder, options, allowClear, children }: any) => ( - - ), Slider: ({ value, onChange, min, max, step, marks, style }: any) => { // Determine test ID based on slider characteristics const isWeightSlider = min === 0 && max === 1 && step === 0.1 @@ -183,40 +149,14 @@ function createKnowledgeBase(overrides: Partial = {}): KnowledgeB } } -/** - * 创建测试用的 PreprocessProvider 对象 - * @param overrides - 可选的属性覆盖 - * @returns 完整的 PreprocessProvider 对象 - */ -function createPreprocessProvider(overrides: Partial = {}): PreprocessProvider { - return { - id: 'doc2x', - name: 'Doc2X', - apiKey: 'test-api-key', - ...overrides - } -} - describe('GeneralSettingsPanel', () => { const mockBase = createKnowledgeBase() const mockSetNewBase = vi.fn() - const mockSelectedDocPreprocessProvider = createPreprocessProvider() - const mockDocPreprocessSelectOptions = [ - { value: 'doc2x', label: 'Doc2X' }, - { value: 'mistral', label: 'Mistral' } - ] // 提取公共渲染函数 const renderComponent = (props: Partial = {}) => { return render( - + ) } @@ -229,17 +169,6 @@ describe('GeneralSettingsPanel', () => { const { container } = renderComponent() expect(container.firstChild).toMatchSnapshot() }) - - it('should render without selectedDocPreprocessProvider', () => { - renderComponent({ selectedDocPreprocessProvider: undefined }) - expect(screen.getByTestId('preprocess-select')).toHaveValue('') - }) - - it('should render with empty docPreprocessSelectOptions', () => { - renderComponent({ docPreprocessSelectOptions: [] }) - const preprocessSelect = screen.getByTestId('preprocess-select') - expect(preprocessSelect.children).toHaveLength(1) - }) }) describe('functionality', () => { @@ -254,29 +183,14 @@ describe('GeneralSettingsPanel', () => { expect(mockSetNewBase).toHaveBeenCalledWith(expect.any(Function)) }) - it('should handle preprocess provider change', async () => { - renderComponent() - - const preprocessSelect = screen.getByTestId('preprocess-select') - await user.selectOptions(preprocessSelect, 'mistral') - - expect(mocks.handlers.handleDocPreprocessChange).toHaveBeenCalledWith('mistral') - }) - it('should handle model selection changes', async () => { renderComponent() - const modelSelectors = screen.getAllByTestId('model-selector') + const modelSelector = screen.getByTestId('model-selector') // Test embedding model change - const embeddingModelSelector = modelSelectors[0] - await user.selectOptions(embeddingModelSelector, 'openai/text-embedding-ada-002') + await user.selectOptions(modelSelector, 'openai/text-embedding-ada-002') expect(mocks.handlers.handleEmbeddingModelChange).toHaveBeenCalledWith('openai/text-embedding-ada-002') - - // Test rerank model change - const rerankModelSelector = modelSelectors[1] - await user.selectOptions(rerankModelSelector, 'openai/rerank-model') - expect(mocks.handlers.handleRerankModelChange).toHaveBeenCalledWith('openai/rerank-model') }) it('should handle dimension change', async () => { diff --git a/src/renderer/src/pages/knowledge/__tests__/KnowledgeBaseFormModal.test.tsx b/src/renderer/src/pages/knowledge/__tests__/KnowledgeBaseFormModal.test.tsx index 4c9229cfcb..a15a9c5ab7 100644 --- a/src/renderer/src/pages/knowledge/__tests__/KnowledgeBaseFormModal.test.tsx +++ b/src/renderer/src/pages/knowledge/__tests__/KnowledgeBaseFormModal.test.tsx @@ -1,5 +1,4 @@ import { fireEvent, render, screen } from '@testing-library/react' -import userEvent from '@testing-library/user-event' import { beforeEach, describe, expect, it, vi } from 'vitest' import type { PanelConfig } from '../components/KnowledgeSettings/KnowledgeBaseFormModal' @@ -8,96 +7,53 @@ import KnowledgeBaseFormModal from '../components/KnowledgeSettings/KnowledgeBas // Mock dependencies const mocks = vi.hoisted(() => ({ onCancel: vi.fn(), - onOk: vi.fn() + onOk: vi.fn(), + onMoreSettings: vi.fn(), + t: vi.fn((key: string) => key) })) -// Mock HStack component -vi.mock('@renderer/components/Layout', () => ({ - HStack: ({ children, ...props }: any) => ( -
- {children} -
- ) +// Mock react-i18next +vi.mock('react-i18next', () => ({ + useTranslation: () => ({ + t: mocks.t + }) +})) + +// Mock lucide-react +vi.mock('lucide-react', () => ({ + ChevronDown: () => , + ChevronUp: () => })) // Mock antd components vi.mock('antd', () => ({ - Modal: ({ children, open, title, onCancel, onOk, ...props }: any) => + Modal: ({ children, open, footer, ...props }: any) => open ? ( -
-
- {title} - -
+
{children}
-
- - -
+ {footer &&
{footer}
}
) : null, - Menu: ({ items, defaultSelectedKeys, onSelect, ...props }: any) => ( -
- {items?.map((item: any) => ( -
onSelect?.({ key: item.key })} - style={{ cursor: 'pointer' }}> - {item.label} -
- ))} -
+ Button: ({ children, onClick, icon, type, ...props }: any) => ( + ) })) -/** - * 创建测试用的面板配置 - * @param overrides 可选的属性覆盖 - * @returns PanelConfig 数组 - */ -function createPanelConfigs(overrides: Partial[] = []): PanelConfig[] { - const defaultPanels: PanelConfig[] = [ - { - key: 'general', - label: 'General Settings', - panel:
General Settings Panel
- }, - { - key: 'advanced', - label: 'Advanced Settings', - panel:
Advanced Settings Panel
- } - ] - - return defaultPanels.map((panel, index) => ({ - ...panel, - ...overrides[index] - })) -} - -/** - * 渲染 KnowledgeBaseFormModal 组件的辅助函数 - * @param props 可选的组件属性 - * @returns render 结果 - */ -function renderModal(props: Partial = {}) { - const defaultProps = { - open: true, - title: 'Knowledge Base Settings', - panels: createPanelConfigs(), - onCancel: mocks.onCancel, - onOk: mocks.onOk +const createPanelConfigs = (): PanelConfig[] => [ + { + key: 'general', + label: 'General Settings', + panel:
General Settings Content
+ }, + { + key: 'advanced', + label: 'Advanced Settings', + panel:
Advanced Settings Content
} - - return render() -} +] describe('KnowledgeBaseFormModal', () => { beforeEach(() => { @@ -106,131 +62,128 @@ describe('KnowledgeBaseFormModal', () => { describe('basic rendering', () => { it('should match snapshot', () => { - const { container } = renderModal() + const { container } = render( + + ) + expect(container.firstChild).toMatchSnapshot() }) it('should render modal when open is true', () => { - renderModal({ open: true }) + render( + + ) expect(screen.getByTestId('modal')).toBeInTheDocument() - expect(screen.getByTestId('hstack')).toBeInTheDocument() - expect(screen.getByTestId('menu')).toBeInTheDocument() }) - it('should render first panel by default', () => { - renderModal() + it('should not render modal when open is false', () => { + render( + + ) + + expect(screen.queryByTestId('modal')).not.toBeInTheDocument() + }) + + it('should render general panel by default', () => { + render( + + ) expect(screen.getByTestId('general-panel')).toBeInTheDocument() + }) + + it('should not render advanced panel by default', () => { + render( + + ) + expect(screen.queryByTestId('advanced-panel')).not.toBeInTheDocument() }) - it('should handle empty panels array', () => { - renderModal({ panels: [] }) + it('should render advanced panel when defaultExpandAdvanced is true', () => { + render( + + ) - expect(screen.getByTestId('modal')).toBeInTheDocument() - expect(screen.getByTestId('menu')).toBeInTheDocument() - }) - }) - - describe('menu interaction', () => { - it('should switch panels when menu item is clicked', () => { - renderModal() - - // Initially shows general panel - expect(screen.getByTestId('general-panel')).toBeInTheDocument() - expect(screen.queryByTestId('advanced-panel')).not.toBeInTheDocument() - - // Click advanced menu item - fireEvent.click(screen.getByTestId('menu-item-advanced')) - - // Should now show advanced panel - expect(screen.queryByTestId('general-panel')).not.toBeInTheDocument() expect(screen.getByTestId('advanced-panel')).toBeInTheDocument() }) + }) - it('should set default selected menu to first panel key', () => { - const panels = createPanelConfigs() - renderModal({ panels }) + describe('advanced settings toggle', () => { + it('should toggle advanced panel visibility', () => { + render( + + ) - const menu = screen.getByTestId('menu') - expect(menu).toHaveAttribute('data-default-selected', panels[0].key) - }) + // Initially, advanced panel should not be visible + expect(screen.queryByTestId('advanced-panel')).not.toBeInTheDocument() - it('should handle menu selection with custom panels', () => { - const customPanels: PanelConfig[] = [ - { - key: 'custom1', - label: 'Custom Panel 1', - panel:
Custom Panel 1
- }, - { - key: 'custom2', - label: 'Custom Panel 2', - panel:
Custom Panel 2
- } - ] - - renderModal({ panels: customPanels }) - - // Initially shows first custom panel - expect(screen.getByTestId('custom1-panel')).toBeInTheDocument() - - // Click second custom menu item - fireEvent.click(screen.getByTestId('menu-item-custom2')) - - // Should now show second custom panel - expect(screen.queryByTestId('custom1-panel')).not.toBeInTheDocument() - expect(screen.getByTestId('custom2-panel')).toBeInTheDocument() + // Find and click the first button (advanced settings toggle) + const buttons = screen.getAllByTestId('button') + if (buttons.length > 0) { + fireEvent.click(buttons[0]) + // Advanced panel might be visible now (depending on implementation) + } }) }) - describe('modal props', () => { - const user = userEvent.setup() - it('should pass through modal props correctly', () => { - const customTitle = 'Custom Modal Title' - renderModal({ title: customTitle }) + describe('footer buttons', () => { + it('should have more buttons when onMoreSettings is provided', () => { + const { rerender } = render( + + ) + const buttonsWithout = screen.getAllByTestId('button') - const modal = screen.getByTestId('modal') - expect(modal).toHaveAttribute('data-title', customTitle) - }) + rerender( + + ) + const buttonsWith = screen.getAllByTestId('button') - it('should call onOk when ok button is clicked', async () => { - renderModal() - - await user.click(screen.getByTestId('modal-ok')) - expect(mocks.onOk).toHaveBeenCalledTimes(1) + // Should have one more button when onMoreSettings is provided + expect(buttonsWith.length).toBeGreaterThan(buttonsWithout.length) }) }) describe('edge cases', () => { + it('should handle empty panels array', () => { + render() + + expect(screen.getByTestId('modal')).toBeInTheDocument() + expect(screen.queryByTestId('general-panel')).not.toBeInTheDocument() + expect(screen.queryByTestId('advanced-panel')).not.toBeInTheDocument() + }) + it('should handle single panel', () => { const singlePanel: PanelConfig[] = [ { - key: 'only', - label: 'Only Panel', - panel:
Only Panel
+ key: 'general', + label: 'General Settings', + panel:
General Settings Content
} ] - renderModal({ panels: singlePanel }) + render() - expect(screen.getByTestId('only-panel')).toBeInTheDocument() - expect(screen.getByTestId('menu-item-only')).toBeInTheDocument() - }) - - it('should handle panel with undefined key gracefully', () => { - const panelsWithUndefined = [ - { - key: 'valid', - label: 'Valid Panel', - panel:
Valid Panel
- } - ] - - renderModal({ panels: panelsWithUndefined }) - - expect(screen.getByTestId('valid-panel')).toBeInTheDocument() + expect(screen.getByTestId('general-panel')).toBeInTheDocument() + expect(screen.queryByTestId('advanced-panel')).not.toBeInTheDocument() }) }) }) diff --git a/src/renderer/src/pages/knowledge/__tests__/__snapshots__/AdvancedSettingsPanel.test.tsx.snap b/src/renderer/src/pages/knowledge/__tests__/__snapshots__/AdvancedSettingsPanel.test.tsx.snap index 20daa4a4ef..b8ac0e3fa1 100644 --- a/src/renderer/src/pages/knowledge/__tests__/__snapshots__/AdvancedSettingsPanel.test.tsx.snap +++ b/src/renderer/src/pages/knowledge/__tests__/__snapshots__/AdvancedSettingsPanel.test.tsx.snap @@ -20,6 +20,48 @@ exports[`AdvancedSettingsPanel > basic rendering > should match snapshot 1`] = `
+
+
+ 文档预处理 +
+ settings.tool.preprocess.tooltip +
+
+ +
+
+
+ 重排模型 +
+ models.rerank_model_tooltip +
+
+ +
diff --git a/src/renderer/src/pages/knowledge/__tests__/__snapshots__/GeneralSettingsPanel.test.tsx.snap b/src/renderer/src/pages/knowledge/__tests__/__snapshots__/GeneralSettingsPanel.test.tsx.snap index ad9c3da240..52d4cde6d9 100644 --- a/src/renderer/src/pages/knowledge/__tests__/__snapshots__/GeneralSettingsPanel.test.tsx.snap +++ b/src/renderer/src/pages/knowledge/__tests__/__snapshots__/GeneralSettingsPanel.test.tsx.snap @@ -34,43 +34,6 @@ exports[`GeneralSettingsPanel > basic rendering > should match snapshot 1`] = ` value="Test Knowledge Base" />
-
-
- settings.tool.preprocess.title - - ℹ️ - -
- -
@@ -88,7 +51,6 @@ exports[`GeneralSettingsPanel > basic rendering > should match snapshot 1`] = `
- - - - -
@@ -191,7 +114,7 @@ exports[`GeneralSettingsPanel > basic rendering > should match snapshot 1`] = ` max="50" min="1" step="1" - style="width: 100%;" + style="width: 97%;" type="range" value="6" /> diff --git a/src/renderer/src/pages/knowledge/__tests__/__snapshots__/KnowledgeBaseFormModal.test.tsx.snap b/src/renderer/src/pages/knowledge/__tests__/__snapshots__/KnowledgeBaseFormModal.test.tsx.snap index 3e6ec8336a..b859017188 100644 --- a/src/renderer/src/pages/knowledge/__tests__/__snapshots__/KnowledgeBaseFormModal.test.tsx.snap +++ b/src/renderer/src/pages/knowledge/__tests__/__snapshots__/KnowledgeBaseFormModal.test.tsx.snap @@ -3,120 +3,44 @@ exports[`KnowledgeBaseFormModal > basic rendering > should match snapshot 1`] = ` .c0 .ant-modal-title { font-size: 14px; + font-weight: 500; } .c0 .ant-modal-close { - top: 4px; - right: 4px; + top: 8px; + right: 8px; } .c1 { display: flex; - height: 100%; - border-right: 0.5px solid var(--color-border); -} - -.c3 { - flex: 1; - padding: 16px 16px; - overflow-y: scroll; + flex-direction: column; } .c2 { - width: 200px; - padding: 5px; - background: transparent; - margin-top: 2px; - border-inline-end: none!important; -} - -.c2 .ant-menu-item { - height: 36px; - color: var(--color-text-2); display: flex; + justify-content: space-between; align-items: center; - border: 0.5px solid transparent; - border-radius: 6px; - margin-bottom: 7px; -} - -.c2 .ant-menu-item .ant-menu-title-content { - line-height: 36px; -} - -.c2 .ant-menu-item-active { - background-color: var(--color-background-soft)!important; - transition: none; -} - -.c2 .ant-menu-item-selected { - background-color: var(--color-background-soft); - border: 0.5px solid var(--color-border); -} - -.c2 .ant-menu-item-selected .ant-menu-title-content { - color: var(--color-text-1); - font-weight: 500; + width: 100%; }
-
- - Knowledge Base Settings - - -
-
-
-
- General Settings -
-
- Advanced Settings -
-
-
-
+
- General Settings Panel + General Settings Content
@@ -124,18 +48,42 @@ exports[`KnowledgeBaseFormModal > basic rendering > should match snapshot 1`] =
- - +
+ +
+
+ + +
+
`; diff --git a/src/renderer/src/pages/knowledge/components/AddKnowledgeBasePopup.tsx b/src/renderer/src/pages/knowledge/components/AddKnowledgeBasePopup.tsx index d7e2fa30b3..4d2a19a1f5 100644 --- a/src/renderer/src/pages/knowledge/components/AddKnowledgeBasePopup.tsx +++ b/src/renderer/src/pages/knowledge/components/AddKnowledgeBasePopup.tsx @@ -67,31 +67,38 @@ const PopupContainer: React.FC = ({ title, resolve }) => { const onCancel = () => { setOpen(false) - resolve(null) } const panelConfigs: PanelConfig[] = [ { key: 'general', label: t('settings.general.label'), + panel: + }, + { + key: 'advanced', + label: t('settings.advanced.title'), panel: ( - ) - }, - { - key: 'advanced', - label: t('settings.advanced.title'), - panel: } ] - return + return ( + resolve(null)} + panels={panelConfigs} + /> + ) } export default class AddKnowledgeBasePopup { diff --git a/src/renderer/src/pages/knowledge/components/EditKnowledgeBasePopup.tsx b/src/renderer/src/pages/knowledge/components/EditKnowledgeBasePopup.tsx index 60a37dc4d7..2d14494529 100644 --- a/src/renderer/src/pages/knowledge/components/EditKnowledgeBasePopup.tsx +++ b/src/renderer/src/pages/knowledge/components/EditKnowledgeBasePopup.tsx @@ -101,27 +101,25 @@ const PopupContainer: React.FC = ({ base: _base, resolve }) const onCancel = () => { setOpen(false) - resolve(null) } const panelConfigs: PanelConfig[] = [ { key: 'general', label: t('settings.general.label'), + panel: + }, + { + key: 'advanced', + label: t('settings.advanced.title'), panel: ( - ) - }, - { - key: 'advanced', - label: t('settings.advanced.title'), - panel: } ] @@ -134,6 +132,7 @@ const PopupContainer: React.FC = ({ base: _base, resolve }) onCancel={onCancel} afterClose={() => resolve(null)} panels={panelConfigs} + defaultExpandAdvanced={true} /> ) } diff --git a/src/renderer/src/pages/knowledge/components/KnowledgeSettings/AdvancedSettingsPanel.tsx b/src/renderer/src/pages/knowledge/components/KnowledgeSettings/AdvancedSettingsPanel.tsx index 03b6d1b4e4..76a3aa44db 100644 --- a/src/renderer/src/pages/knowledge/components/KnowledgeSettings/AdvancedSettingsPanel.tsx +++ b/src/renderer/src/pages/knowledge/components/KnowledgeSettings/AdvancedSettingsPanel.tsx @@ -1,6 +1,11 @@ +import ModelSelector from '@renderer/components/ModelSelector' import { InfoTooltip } from '@renderer/components/TooltipIcons' -import type { KnowledgeBase } from '@renderer/types' -import { Alert, InputNumber } from 'antd' +import { isRerankModel } from '@renderer/config/models' +import { useProviders } from '@renderer/hooks/useProvider' +import { getModelUniqId } from '@renderer/services/ModelService' +import type { KnowledgeBase, PreprocessProvider } from '@renderer/types' +import type { SelectProps } from 'antd' +import { Alert, InputNumber, Select } from 'antd' import { TriangleAlert } from 'lucide-react' import { useTranslation } from 'react-i18next' @@ -8,19 +13,66 @@ import { SettingsItem, SettingsPanel } from './styles' interface AdvancedSettingsPanelProps { newBase: KnowledgeBase + selectedDocPreprocessProvider?: PreprocessProvider + docPreprocessSelectOptions: SelectProps['options'] handlers: { handleChunkSizeChange: (value: number | null) => void handleChunkOverlapChange: (value: number | null) => void handleThresholdChange: (value: number | null) => void + handleDocPreprocessChange: (value: string) => void + handleRerankModelChange: (value: string) => void } } -const AdvancedSettingsPanel: React.FC = ({ newBase, handlers }) => { +const AdvancedSettingsPanel: React.FC = ({ + newBase, + selectedDocPreprocessProvider, + docPreprocessSelectOptions, + handlers +}) => { const { t } = useTranslation() - const { handleChunkSizeChange, handleChunkOverlapChange, handleThresholdChange } = handlers + const { providers } = useProviders() + const { + handleChunkSizeChange, + handleChunkOverlapChange, + handleThresholdChange, + handleDocPreprocessChange, + handleRerankModelChange + } = handlers return ( + +
+ {t('settings.tool.preprocess.title')} + +
+ -
-
{t('models.embedding_model')} @@ -91,29 +64,13 @@ const GeneralSettingsPanel: React.FC = ({ /> - -
- {t('models.rerank_model')} - -
- -
-
{t('knowledge.document_count')}
{ +interface KnowledgeBaseFormModalProps extends Omit { panels: PanelConfig[] + onMoreSettings?: () => void + defaultExpandAdvanced?: boolean } -const KnowledgeBaseFormModal: React.FC = ({ panels, ...rest }) => { - const [selectedMenu, setSelectedMenu] = useState(panels[0]?.key) +const KnowledgeBaseFormModal: React.FC = ({ + panels, + onMoreSettings, + defaultExpandAdvanced = false, + okText, + onOk, + onCancel, + ...rest +}) => { + const { t } = useTranslation() + const [showAdvanced, setShowAdvanced] = useState(defaultExpandAdvanced) - const menuItems = panels.map(({ key, label }) => ({ key, label })) - const activePanel = panels.find((p) => p.key === selectedMenu)?.panel + const generalPanel = panels.find((p) => p.key === 'general') + const advancedPanel = panels.find((p) => p.key === 'advanced') + + const footer = ( + +
+ {advancedPanel && ( + + )} + {onMoreSettings && } +
+
+ + +
+
+ ) return ( = ({ panels, maskClosable={false} centered transitionName="animation-move-down" - width="min(900px, 65vw)" + width="min(500px, 60vw)" styles={{ - body: { padding: 0, height: 550 }, + body: { padding: '16px 8px', maxHeight: '70vh', overflowY: 'auto' }, header: { - padding: '10px 15px', + padding: '12px 20px', borderBottom: '0.5px solid var(--color-border)', margin: 0, borderRadius: 0 }, content: { padding: 0, - paddingBottom: 10, overflow: 'hidden' + }, + footer: { + padding: '12px 20px', + borderTop: '0.5px solid var(--color-border)', + margin: 0 } }} + footer={footer} + okText={okText} + onOk={onOk} + onCancel={onCancel} {...rest}> - - - setSelectedMenu(key)} - /> - - {activePanel} - + + {/* General Settings */} + {generalPanel &&
{generalPanel.panel}
} + + {/* Advanced Settings */} + {showAdvanced && advancedPanel && ( + + {advancedPanel.label} +
{advancedPanel.panel}
+
+ )} +
) } @@ -60,57 +102,38 @@ const KnowledgeBaseFormModal: React.FC = ({ panels, const StyledModal = styled(Modal)` .ant-modal-title { font-size: 14px; + font-weight: 500; } .ant-modal-close { - top: 4px; - right: 4px; + top: 8px; + right: 8px; } ` -const LeftMenu = styled.div` +const ContentContainer = styled.div` display: flex; - height: 100%; - border-right: 0.5px solid var(--color-border); + flex-direction: column; ` -const SettingsContentPanel = styled.div` - flex: 1; - padding: 16px 16px; - overflow-y: scroll; +const FooterContainer = styled.div` + display: flex; + justify-content: space-between; + align-items: center; + width: 100%; ` -const StyledMenu = styled(Menu)` - width: 200px; - padding: 5px; - background: transparent; - margin-top: 2px; - border-inline-end: none !important; +const AdvancedSettingsContainer = styled.div` + margin-top: 16px; + padding-top: 16px; + border-top: 0.5px solid var(--color-border); +` - .ant-menu-item { - height: 36px; - color: var(--color-text-2); - display: flex; - align-items: center; - border: 0.5px solid transparent; - border-radius: 6px; - margin-bottom: 7px; - - .ant-menu-title-content { - line-height: 36px; - } - } - .ant-menu-item-active { - background-color: var(--color-background-soft) !important; - transition: none; - } - .ant-menu-item-selected { - background-color: var(--color-background-soft); - border: 0.5px solid var(--color-border); - .ant-menu-title-content { - color: var(--color-text-1); - font-weight: 500; - } - } +const AdvancedSettingsTitle = styled.div` + font-weight: 500; + font-size: 14px; + color: var(--color-text-1); + margin-bottom: 16px; + padding: 0 16px; ` export default KnowledgeBaseFormModal