diff --git a/web/features/new-rag/add-source-page.tsx b/web/features/new-rag/add-source-page.tsx index 1daadb5c645..88f34c443ce 100644 --- a/web/features/new-rag/add-source-page.tsx +++ b/web/features/new-rag/add-source-page.tsx @@ -44,8 +44,9 @@ import { sourceProviderOptionForDraft, } from './source-provider-options' import { + SourceProviderIcon, SourceProviderNotInstalledCard, - SourceProviderRadioGroup, + SourceProviderSelector, SourceTypeSelector, } from './source-setup-fields' import { WebsiteCrawlPreview } from './website-crawl-preview' @@ -207,64 +208,6 @@ function getSupportedAuthKinds(provider: Provider, credentialId?: string) { return supported } -function ProviderSelector({ - disabled = false, - onMoreProviders, - options, - providerKey, - onChange, -}: { - disabled?: boolean - onMoreProviders: () => void - options: SourceProviderOption[] - providerKey: string - onChange: (providerKey: string) => void -}) { - const { t } = useTranslation('dataset') - - return ( -
-
- - {t(($) => $['newKnowledge.providerLabel'])} - - -
- ({ - icon: , - label: option.label, - value: option.key, - }))} - size="small" - onChange={onChange} - /> -
- ) -} - -function WebsiteProviderIcon({ option }: { option: SourceProviderOption }) { - const icon = option.installed - ? (option.datasource.identity.icon ?? option.plugin.declaration.identity.icon) - : undefined - if (typeof icon === 'string' && icon) - return - return -} - function ProviderFieldControl({ field, setValues, @@ -680,7 +623,15 @@ function UnconfiguredProvider({ return (
- +

{t(($) => $['newKnowledge.providerNotConfigured'], { @@ -1311,7 +1262,7 @@ export function AddSourcePage({ /> {sourceDraft.sourceType === 'websiteCrawl' ? ( <> - ) : websiteProviderOption && !websiteProviderOption.installed ? ( } + icon={} provider={websiteProviderOption.label} onInstall={() => globalThis.open( diff --git a/web/features/new-rag/components/retrieval-mode-segmented-control.tsx b/web/features/new-rag/components/retrieval-mode-segmented-control.tsx new file mode 100644 index 00000000000..c83a5f38c72 --- /dev/null +++ b/web/features/new-rag/components/retrieval-mode-segmented-control.tsx @@ -0,0 +1,56 @@ +'use client' + +import { cn } from '@langgenius/dify-ui/cn' +import { SegmentedControl, SegmentedControlItem } from '@langgenius/dify-ui/segmented-control' +import { useTranslation } from 'react-i18next' + +const retrievalModes = ['fast', 'deep', 'research'] as const + +export type RetrievalMode = (typeof retrievalModes)[number] + +export function RetrievalModeSegmentedControl({ + 'aria-label': ariaLabel, + 'aria-labelledby': ariaLabelledBy, + appearance = 'default', + disabled = false, + value, + onChange, +}: { + 'aria-label'?: string + 'aria-labelledby'?: string + appearance?: 'composer' | 'default' + disabled?: boolean + value: RetrievalMode + onChange: (value: RetrievalMode) => void +}) { + const { t } = useTranslation('dataset') + + return ( + + aria-label={ariaLabel} + aria-labelledby={ariaLabelledBy} + className={cn( + appearance === 'composer' && 'flex min-w-46.5 gap-0.5 bg-background-section-burn', + )} + value={[value]} + onValueChange={(values) => { + const nextValue = values[0] + if (nextValue) onChange(nextValue) + }} + > + {retrievalModes.map((mode) => ( + + key={mode} + value={mode} + disabled={disabled} + className={cn( + appearance === 'composer' && + 'grow border-0 px-2.5 py-1.25 system-sm-regular text-text-tertiary capitalize data-pressed:bg-components-panel-bg data-pressed:font-medium data-pressed:text-text-primary', + )} + > + {t(($) => $[`newKnowledge.settings.retrievalMode.${mode}`])} + + ))} + + ) +} diff --git a/web/features/new-rag/connected-source-setup.tsx b/web/features/new-rag/connected-source-setup.tsx index 25eacd3cbb2..b8fd07821ca 100644 --- a/web/features/new-rag/connected-source-setup.tsx +++ b/web/features/new-rag/connected-source-setup.tsx @@ -15,11 +15,9 @@ import type { DataSourceAuth, DataSourceCredential, } from '@/app/components/header/account-setting/data-source-page-new/types' -import type { DataSourceItem } from '@/app/components/workflow/block-selector/types' import { Button } from '@langgenius/dify-ui/button' import { Checkbox } from '@langgenius/dify-ui/checkbox' import { cn } from '@langgenius/dify-ui/cn' -import { Fieldset, FieldsetLegend } from '@langgenius/dify-ui/fieldset' import { useInfiniteQuery, useQuery, useQueryClient } from '@tanstack/react-query' import { useCallback, useEffect, useMemo, useRef, useState } from 'react' import { useTranslation } from 'react-i18next' @@ -46,8 +44,9 @@ import { import { SourceConnectionRequiredCard, SourceNameField, + SourceProviderIcon, SourceProviderNotInstalledCard, - SourceProviderRadioGroup, + SourceProviderSelector, SourceSyncPolicyField, } from './source-setup-fields' @@ -142,11 +141,9 @@ function datasourceProviderForOption(option?: SourceProviderOption) { : undefined } -type ProviderBrandIconValue = DataSourceItem['declaration']['identity']['icon'] - function datasourceProviderIcon( datasourceProvider: ReturnType, -): ProviderBrandIconValue | undefined { +) { return datasourceProvider?.plugin.declaration.identity.icon } @@ -315,83 +312,6 @@ function requestStatus(error: unknown) { return undefined } -function ProviderSelector({ - options, - providerKey, - onChange, - onMoreProviders, -}: { - options: SourceProviderOption[] - providerKey: string - onChange: (providerKey: string) => void - onMoreProviders: () => void -}) { - const { t } = useTranslation('dataset') - return ( -
-
- - {t(($) => $['newKnowledge.providerLabel'])} - - -
- ({ - icon: ( - - ), - label: option.label, - value: option.key, - }))} - size="small" - onChange={onChange} - /> -
- ) -} - -function ProviderBrandIcon({ - fallbackIcon, - icon, -}: { - fallbackIcon: string - icon?: ProviderBrandIconValue -}) { - if (typeof icon === 'string' && icon) - return - - if (icon && typeof icon !== 'string') - return ( - - {icon.content} - - ) - - return -} - function OAuthConnectionCard({ draft, icon, @@ -399,7 +319,7 @@ function OAuthConnectionCard({ onConnect, }: { draft: ConnectedSourceDraft - icon?: ProviderBrandIconValue + icon?: ReturnType providerOption: InstalledSourceProviderOption onConnect: () => void }) { @@ -414,7 +334,7 @@ function OAuthConnectionCard({ provider: draft.provider, }) } - icon={} + icon={} title={ draft.provider === 'Notion' ? t(($) => $['newKnowledge.notionNotConnected']) @@ -1824,7 +1744,8 @@ export function ConnectedSourceSetup({ } return (
- ) : providerOption && !providerOption.installed ? ( } + icon={} provider={providerOption.label} onInstall={() => globalThis.open( diff --git a/web/features/new-rag/knowledge-settings-form.tsx b/web/features/new-rag/knowledge-settings-form.tsx index eb0841739a5..fe086a1f43e 100644 --- a/web/features/new-rag/knowledge-settings-form.tsx +++ b/web/features/new-rag/knowledge-settings-form.tsx @@ -24,7 +24,6 @@ import { Button } from '@langgenius/dify-ui/button' import { cn } from '@langgenius/dify-ui/cn' import { Form } from '@langgenius/dify-ui/form' import { Input } from '@langgenius/dify-ui/input' -import { SegmentedControl, SegmentedControlItem } from '@langgenius/dify-ui/segmented-control' import { Slider } from '@langgenius/dify-ui/slider' import { Switch } from '@langgenius/dify-ui/switch' import { Textarea } from '@langgenius/dify-ui/textarea' @@ -40,6 +39,7 @@ import { useRouter } from '@/next/navigation' import { consoleQuery } from '@/service/client' import { KnowledgeSettingsMembers } from './components/knowledge-settings-members' import { KnowledgeSpaceIcon } from './components/knowledge-space-icon' +import { RetrievalModeSegmentedControl } from './components/retrieval-mode-segmented-control' import { isKnowledgeModelSetupReady, KNOWLEDGE_NAME_MAX_LENGTH } from './constants' import { newKnowledgeListPath } from './routes' @@ -1024,30 +1024,22 @@ export function KnowledgeSettingsForm({ > {t(($) => $['newKnowledge.settings.retrievalDepth'])} - { - const mode = values[0] - if (mode === 'fast' || mode === 'deep' || mode === 'research') { - const nextScoreThresholdEnabled = - mode !== 'research' && !rerankEnabled ? false : scoreThresholdEnabled - setRetrievalMode(mode) - setScoreThresholdEnabled(nextScoreThresholdEnabled) - void performSettingsSave({ - ...currentSettingsDraft, - retrievalMode: mode, - scoreThresholdEnabled: nextScoreThresholdEnabled, - }) - } + disabled={retrievalFieldsDisabled} + value={retrievalMode} + onChange={(mode) => { + const nextScoreThresholdEnabled = + mode !== 'research' && !rerankEnabled ? false : scoreThresholdEnabled + setRetrievalMode(mode) + setScoreThresholdEnabled(nextScoreThresholdEnabled) + void performSettingsSave({ + ...currentSettingsDraft, + retrievalMode: mode, + scoreThresholdEnabled: nextScoreThresholdEnabled, + }) }} - > - {(['fast', 'deep', 'research'] as const).map((mode) => ( - - {t(($) => $[`newKnowledge.settings.retrievalMode.${mode}`])} - - ))} - + />
diff --git a/web/features/new-rag/retrieval-test-page.tsx b/web/features/new-rag/retrieval-test-page.tsx index 159dc79e2de..168a8730653 100644 --- a/web/features/new-rag/retrieval-test-page.tsx +++ b/web/features/new-rag/retrieval-test-page.tsx @@ -26,6 +26,7 @@ import { Markdown } from '@/app/components/base/markdown' import { Link as MarkdownLink } from '@/app/components/base/markdown-blocks' import Link from '@/next/link' import { consoleClient, consoleQuery } from '@/service/client' +import { RetrievalModeSegmentedControl } from './components/retrieval-mode-segmented-control' import { extractRetrievalEvidence, extractStreamError, @@ -1589,34 +1590,19 @@ export function RetrievalTestPage({ knowledgeSpaceId }: { knowledgeSpaceId: stri }} />
-
$['newKnowledge.settings.retrievalModeLabel'])} - className="flex min-w-46.5 gap-0.5 rounded-lg bg-background-section-burn p-0.5" - > - {(['fast', 'deep', 'research'] as const).map((item) => ( - - ))} -
+ appearance="composer" + disabled={selectedResearchActive || localRun?.status === 'running'} + value={mode} + onChange={(nextMode) => + setComposerDraft({ + mode: nextMode, + query, + ...(selectedHistoryKey ? { selectionKey: selectedHistoryKey } : {}), + }) + } + /> +
+ ({ + icon: ( + + ), + label: option.label, + value: option.key, + }))} + size="small" + onChange={onChange} + /> + + ) +} + export function SourceNameField({ className, disabled = false,