Fix: Optimize dataset page layout and internationalization and default values for multi selection #3221 (#9695)

### What problem does this PR solve?

Fix: Optimize dataset page layout and internationalization and Fix
setting default values for multi selection drop-down boxes #3221

-Adjust the style and layout of each component on the dataset page
-Add and update multilingual translation content

### Type of change

- [x] Bug Fix (non-breaking change which fixes an issue)
This commit is contained in:
chanx
2025-08-25 17:29:15 +08:00
committed by GitHub
parent a3aa3f0d36
commit d367c7e226
15 changed files with 99 additions and 39 deletions

View File

@ -68,7 +68,7 @@ export function LayoutRecognizeFormField() {
<div className="flex items-center"> <div className="flex items-center">
<FormLabel <FormLabel
tooltip={t('layoutRecognizeTip')} tooltip={t('layoutRecognizeTip')}
className="text-sm text-muted-foreground whitespace-nowrap w-1/4" className="text-sm text-muted-foreground whitespace-wrap w-1/4"
> >
{t('layoutRecognize')} {t('layoutRecognize')}
</FormLabel> </FormLabel>

View File

@ -28,6 +28,7 @@ import {
PopoverTrigger, PopoverTrigger,
} from '@/components/ui/popover'; } from '@/components/ui/popover';
import { cn } from '@/lib/utils'; import { cn } from '@/lib/utils';
import { t } from 'i18next';
import { RAGFlowSelectOptionType } from '../ui/select'; import { RAGFlowSelectOptionType } from '../ui/select';
import { Separator } from '../ui/separator'; import { Separator } from '../ui/separator';
@ -114,7 +115,9 @@ export const SelectWithSearch = forwardRef<
<span className="leading-none truncate">{selectLabel}</span> <span className="leading-none truncate">{selectLabel}</span>
</span> </span>
) : ( ) : (
<span className="text-muted-foreground">Select value</span> <span className="text-muted-foreground">
{t('common.selectPlaceholder')}
</span>
)} )}
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
{value && allowClear && ( {value && allowClear && (

View File

@ -3,7 +3,7 @@ import { DocumentParserType } from '@/constants/knowledge';
import { useTranslate } from '@/hooks/common-hooks'; import { useTranslate } from '@/hooks/common-hooks';
import random from 'lodash/random'; import random from 'lodash/random';
import { Plus } from 'lucide-react'; import { Plus } from 'lucide-react';
import { useCallback, useEffect } from 'react'; import { useCallback } from 'react';
import { useFormContext, useWatch } from 'react-hook-form'; import { useFormContext, useWatch } from 'react-hook-form';
import { SliderInputFormField } from '../slider-input-form-field'; import { SliderInputFormField } from '../slider-input-form-field';
import { Button } from '../ui/button'; import { Button } from '../ui/button';
@ -57,15 +57,19 @@ const RaptorFormFields = () => {
const form = useFormContext(); const form = useFormContext();
const { t } = useTranslate('knowledgeConfiguration'); const { t } = useTranslate('knowledgeConfiguration');
const useRaptor = useWatch({ name: UseRaptorField }); const useRaptor = useWatch({ name: UseRaptorField });
useEffect(() => {
if (useRaptor) { const changeRaptor = useCallback(
(isUseRaptor: boolean) => {
if (isUseRaptor) {
form.setValue(MaxTokenField, 256); form.setValue(MaxTokenField, 256);
form.setValue(ThresholdField, 0.1); form.setValue(ThresholdField, 0.1);
form.setValue(MaxCluster, 64); form.setValue(MaxCluster, 64);
form.setValue(RandomSeedField, 0); form.setValue(RandomSeedField, 0);
form.setValue(Prompt, t('promptText')); form.setValue(Prompt, t('promptText'));
} }
}, [form, useRaptor, t]); },
[form],
);
const handleGenerate = useCallback(() => { const handleGenerate = useCallback(() => {
form.setValue(RandomSeedField, random(10000)); form.setValue(RandomSeedField, random(10000));
@ -97,7 +101,10 @@ const RaptorFormFields = () => {
<FormControl> <FormControl>
<Switch <Switch
checked={field.value} checked={field.value}
onCheckedChange={field.onChange} onCheckedChange={(e) => {
changeRaptor(e);
field.onChange(e);
}}
></Switch> ></Switch>
</FormControl> </FormControl>
</div> </div>
@ -127,7 +134,13 @@ const RaptorFormFields = () => {
</FormLabel> </FormLabel>
<div className="w-3/4"> <div className="w-3/4">
<FormControl> <FormControl>
<Textarea {...field} rows={8} /> <Textarea
{...field}
rows={8}
onChange={(e) => {
field.onChange(e?.target?.value);
}}
/>
</FormControl> </FormControl>
</div> </div>
</div> </div>

View File

@ -209,10 +209,16 @@ export const MultiSelect = React.forwardRef<
const [isAnimating, setIsAnimating] = React.useState(false); const [isAnimating, setIsAnimating] = React.useState(false);
React.useEffect(() => { React.useEffect(() => {
if (selectedValues === undefined) { if (!selectedValues && props.value) {
setSelectedValues(props.value as string[]);
}
}, [props.value, selectedValues]);
React.useEffect(() => {
if (!selectedValues && !props.value && defaultValue) {
setSelectedValues(defaultValue); setSelectedValues(defaultValue);
} }
}, [defaultValue, selectedValues]); }, [defaultValue, props.value, selectedValues]);
const flatOptions = React.useMemo(() => { const flatOptions = React.useMemo(() => {
return options.flatMap((option) => return options.flatMap((option) =>
@ -293,15 +299,18 @@ export const MultiSelect = React.forwardRef<
variant="secondary" variant="secondary"
className={cn( className={cn(
isAnimating ? 'animate-bounce' : '', isAnimating ? 'animate-bounce' : '',
'px-1',
multiSelectVariants({ variant }), multiSelectVariants({ variant }),
)} )}
style={{ animationDuration: `${animation}s` }} style={{ animationDuration: `${animation}s` }}
> >
<div className="flex items-center gap-1"> <div className="flex justify-between items-center gap-1">
{IconComponent && ( {IconComponent && (
<IconComponent className="h-4 w-4" /> <IconComponent className="h-4 w-4" />
)} )}
<div>{option?.label}</div> <div className="max-w-28 text-ellipsis overflow-hidden">
{option?.label}
</div>
<XCircle <XCircle
className="h-4 w-4 cursor-pointer" className="h-4 w-4 cursor-pointer"
onClick={(event) => { onClick={(event) => {

View File

@ -1,6 +1,7 @@
export default { export default {
translation: { translation: {
common: { common: {
selectPlaceholder: 'select value',
delete: 'Delete', delete: 'Delete',
deleteModalTitle: 'Are you sure to delete this item?', deleteModalTitle: 'Are you sure to delete this item?',
ok: 'Yes', ok: 'Yes',
@ -94,6 +95,16 @@ export default {
noMoreData: `That's all. Nothing more.`, noMoreData: `That's all. Nothing more.`,
}, },
knowledgeDetails: { knowledgeDetails: {
created: 'Created',
learnMore: 'Learn More',
general: 'General',
chunkMethodTab: 'Chunk Method',
testResults: 'Test Results',
testSetting: 'Test Setting',
retrievalTesting: 'Retrieval Testing',
retrievalTestingDescription:
'Conduct a retrieval test to check if RAGFlow can recover the intended content for the LLM.',
Parse: 'Parse',
dataset: 'Dataset', dataset: 'Dataset',
testing: 'Retrieval testing', testing: 'Retrieval testing',
files: 'files', files: 'files',

View File

@ -1,6 +1,7 @@
export default { export default {
translation: { translation: {
common: { common: {
selectPlaceholder: '请选择',
delete: '删除', delete: '删除',
deleteModalTitle: '确定删除吗?', deleteModalTitle: '确定删除吗?',
ok: '是', ok: '是',
@ -86,6 +87,16 @@ export default {
noMoreData: '没有更多数据了', noMoreData: '没有更多数据了',
}, },
knowledgeDetails: { knowledgeDetails: {
created: '创建于',
learnMore: '了解更多',
general: '通用',
chunkMethodTab: '切片方法',
testResults: '测试结果',
testSetting: '测试设置',
retrievalTesting: '知识检索测试',
retrievalTestingDescription:
'进行检索测试,检查 RAGFlow 是否能够为大语言模型LLM恢复预期的内容。',
Parse: '解析',
dataset: '数据集', dataset: '数据集',
testing: '检索测试', testing: '检索测试',
configuration: '配置', configuration: '配置',

View File

@ -30,7 +30,9 @@ export default function DatasetWrapper() {
</BreadcrumbItem> </BreadcrumbItem>
<BreadcrumbSeparator /> <BreadcrumbSeparator />
<BreadcrumbItem> <BreadcrumbItem>
<BreadcrumbPage>{data.name}</BreadcrumbPage> <BreadcrumbPage className="w-28 whitespace-nowrap text-ellipsis overflow-hidden">
{data.name}
</BreadcrumbPage>
</BreadcrumbItem> </BreadcrumbItem>
</BreadcrumbList> </BreadcrumbList>
</Breadcrumb> </Breadcrumb>

View File

@ -1,5 +1,6 @@
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { cn } from '@/lib/utils'; import { cn } from '@/lib/utils';
import { t } from 'i18next';
import { X } from 'lucide-react'; import { X } from 'lucide-react';
import { useState } from 'react'; import { useState } from 'react';
import CategoryPanel from './category-panel'; import CategoryPanel from './category-panel';
@ -26,7 +27,7 @@ export default ({
setVisible(!visible); setVisible(!visible);
}} }}
> >
Learn More {t('knowledgeDetails.learnMore')}
</Button> </Button>
</div> </div>
<div <div

View File

@ -29,7 +29,7 @@ export function ChunkMethodItem() {
<div className="flex items-center"> <div className="flex items-center">
<FormLabel <FormLabel
tooltip={t('chunkMethodTip')} tooltip={t('chunkMethodTip')}
className="text-sm text-muted-foreground whitespace-nowrap w-1/4" className="text-sm text-muted-foreground whitespace-wrap w-1/4"
> >
{t('chunkMethod')} {t('chunkMethod')}
</FormLabel> </FormLabel>
@ -69,7 +69,7 @@ export function EmbeddingModelItem() {
<div className="flex items-center"> <div className="flex items-center">
<FormLabel <FormLabel
tooltip={t('embeddingModelTip')} tooltip={t('embeddingModelTip')}
className="text-sm text-muted-foreground whitespace-nowrap w-1/4" className="text-sm text-muted-foreground whitespace-wrap w-1/4"
> >
{t('embeddingModel')} {t('embeddingModel')}
</FormLabel> </FormLabel>

View File

@ -107,7 +107,7 @@ export default function DatasetSettings() {
> >
<div className="flex w-full h-full justify-center items-center"> <div className="flex w-full h-full justify-center items-center">
<span className="h-full group-data-[state=active]:border-b-2 border-foreground "> <span className="h-full group-data-[state=active]:border-b-2 border-foreground ">
General {t('knowledgeDetails.general')}
</span> </span>
</div> </div>
</TabsTrigger> </TabsTrigger>
@ -117,7 +117,7 @@ export default function DatasetSettings() {
> >
<div className="flex w-full h-full justify-center items-center"> <div className="flex w-full h-full justify-center items-center">
<span className="h-full group-data-[state=active]:border-b-2 border-foreground "> <span className="h-full group-data-[state=active]:border-b-2 border-foreground ">
Chunk Method {t('knowledgeDetails.chunkMethodTab')}
</span> </span>
</div> </div>
</TabsTrigger> </TabsTrigger>

View File

@ -67,10 +67,14 @@ export function SideBar({ refreshCount }: PropType) {
{data.name} {data.name}
</h3> </h3>
<div className="flex justify-between"> <div className="flex justify-between">
<span>{data.doc_num} files</span> <span>
{data.doc_num} {t('knowledgeDetails.files')}
</span>
<span>{formatBytes(data.size)}</span> <span>{formatBytes(data.size)}</span>
</div> </div>
<div>Created {formatPureDate(data.create_time)}</div> <div>
{t('knowledgeDetails.created')} {formatPureDate(data.create_time)}
</div>
</div> </div>
</div> </div>

View File

@ -1,4 +1,5 @@
import { useTestRetrieval } from '@/hooks/use-knowledge-request'; import { useTestRetrieval } from '@/hooks/use-knowledge-request';
import { t } from 'i18next';
import { useState } from 'react'; import { useState } from 'react';
import { TopTitle } from '../dataset-title'; import { TopTitle } from '../dataset-title';
import TestingForm from './testing-form'; import TestingForm from './testing-form';
@ -23,8 +24,8 @@ export default function RetrievalTesting() {
<div className="p-5"> <div className="p-5">
<section className="flex justify-between items-center"> <section className="flex justify-between items-center">
<TopTitle <TopTitle
title={'Retrieval testing'} title={t('knowledgeDetails.retrievalTesting')}
description={`Conduct a retrieval test to check if RAGFlow can recover the intended content for the LLM.`} description={t('knowledgeDetails.retrievalTestingDescription')}
></TopTitle> ></TopTitle>
{/* <Button>Save as Preset</Button> */} {/* <Button>Save as Preset</Button> */}
</section> </section>
@ -33,7 +34,7 @@ export default function RetrievalTesting() {
<div className="p-4 flex-1"> <div className="p-4 flex-1">
<div className="flex justify-between pb-2.5"> <div className="flex justify-between pb-2.5">
<span className="text-text-primary font-semibold text-2xl"> <span className="text-text-primary font-semibold text-2xl">
Test setting {t('knowledgeDetails.testSetting')}
</span> </span>
{/* <Button variant={'outline'} onClick={addCount}> {/* <Button variant={'outline'} onClick={addCount}>
<Plus /> Add New Test <Plus /> Add New Test

View File

@ -6,6 +6,7 @@ import { RAGFlowPagination } from '@/components/ui/ragflow-pagination';
import { useTranslate } from '@/hooks/common-hooks'; import { useTranslate } from '@/hooks/common-hooks';
import { useTestRetrieval } from '@/hooks/use-knowledge-request'; import { useTestRetrieval } from '@/hooks/use-knowledge-request';
import { ITestingChunk } from '@/interfaces/database/knowledge'; import { ITestingChunk } from '@/interfaces/database/knowledge';
import { t } from 'i18next';
import camelCase from 'lodash/camelCase'; import camelCase from 'lodash/camelCase';
import { useMemo } from 'react'; import { useMemo } from 'react';
@ -66,7 +67,7 @@ export function TestingResult({
<div className="p-4 flex-1"> <div className="p-4 flex-1">
<div className="flex justify-between pb-2.5"> <div className="flex justify-between pb-2.5">
<span className="text-text-primary font-semibold text-2xl"> <span className="text-text-primary font-semibold text-2xl">
Test results {t('knowledgeDetails.testResults')}
</span> </span>
<FilterPopover <FilterPopover
filters={filters} filters={filters}

View File

@ -39,7 +39,7 @@ export function SeeAllCard() {
const { navigateToDatasetList } = useNavigatePage(); const { navigateToDatasetList } = useNavigatePage();
return ( return (
<Card className="w-40 flex-none" onClick={navigateToDatasetList}> <Card className="w-40 flex-none h-full" onClick={navigateToDatasetList}>
<CardContent className="p-2.5 pt-1 w-full h-full flex items-center justify-center gap-1.5 text-text-secondary"> <CardContent className="p-2.5 pt-1 w-full h-full flex items-center justify-center gap-1.5 text-text-secondary">
See All <ChevronRight className="size-4" /> See All <ChevronRight className="size-4" />
</CardContent> </CardContent>

View File

@ -31,16 +31,20 @@ export function Datasets() {
</div> </div>
) : ( ) : (
<div className="grid gap-6 sm:grid-cols-1 md:grid-cols-2 lg:grid-cols-4 xl:grid-cols-6 2xl:grid-cols-8 max-h-[78vh] overflow-auto"> <div className="grid gap-6 sm:grid-cols-1 md:grid-cols-2 lg:grid-cols-4 xl:grid-cols-6 2xl:grid-cols-8 max-h-[78vh] overflow-auto">
{kbs.slice(0, 6).map((dataset) => ( {kbs
?.slice(0, 6)
.map((dataset) => (
<DatasetCard <DatasetCard
key={dataset.id} key={dataset.id}
dataset={dataset} dataset={dataset}
showDatasetRenameModal={showDatasetRenameModal} showDatasetRenameModal={showDatasetRenameModal}
></DatasetCard> ></DatasetCard>
))} ))}
<div className="min-h-24">
<SeeAllCard></SeeAllCard>
</div>
</div> </div>
)} )}
<SeeAllCard></SeeAllCard>
</div> </div>
{datasetRenameVisible && ( {datasetRenameVisible && (
<RenameDialog <RenameDialog