mirror of
https://github.com/infiniflow/ragflow.git
synced 2025-12-08 20:42:30 +08:00
fix: fix dataset-page's bugs (#8786)
### What problem does this PR solve? fix dataset-page's bugs,Input component supports icon, added Radio component, and removed antd from chunk-result-bar page [#3221 ](https://github.com/infiniflow/ragflow/issues/3221) ### Type of change - [x] Bug Fix (non-breaking change which fixes an issue)
This commit is contained in:
@ -12,7 +12,13 @@ import {
|
|||||||
type EntityTypesFormFieldProps = {
|
type EntityTypesFormFieldProps = {
|
||||||
name?: string;
|
name?: string;
|
||||||
};
|
};
|
||||||
|
const initialEntityTypes = [
|
||||||
|
'organization',
|
||||||
|
'person',
|
||||||
|
'geo',
|
||||||
|
'event',
|
||||||
|
'category',
|
||||||
|
];
|
||||||
export function EntityTypesFormField({
|
export function EntityTypesFormField({
|
||||||
name = 'parser_config.entity_types',
|
name = 'parser_config.entity_types',
|
||||||
}: EntityTypesFormFieldProps) {
|
}: EntityTypesFormFieldProps) {
|
||||||
@ -23,24 +29,27 @@ export function EntityTypesFormField({
|
|||||||
<FormField
|
<FormField
|
||||||
control={form.control}
|
control={form.control}
|
||||||
name={name}
|
name={name}
|
||||||
render={({ field }) => (
|
defaultValue={initialEntityTypes}
|
||||||
<FormItem className=" items-center space-y-0 ">
|
render={({ field }) => {
|
||||||
<div className="flex items-center">
|
return (
|
||||||
<FormLabel className="text-sm text-muted-foreground whitespace-nowrap w-1/4">
|
<FormItem className=" items-center space-y-0 ">
|
||||||
<span className="text-red-600">*</span> {t('entityTypes')}
|
<div className="flex items-center">
|
||||||
</FormLabel>
|
<FormLabel className="text-sm text-muted-foreground whitespace-nowrap w-1/4">
|
||||||
<div className="w-3/4">
|
<span className="text-red-600">*</span> {t('entityTypes')}
|
||||||
<FormControl>
|
</FormLabel>
|
||||||
<EditTag {...field}></EditTag>
|
<div className="w-3/4">
|
||||||
</FormControl>
|
<FormControl>
|
||||||
|
<EditTag {...field}></EditTag>
|
||||||
|
</FormControl>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div className="flex pt-1">
|
||||||
<div className="flex pt-1">
|
<div className="w-1/4"></div>
|
||||||
<div className="w-1/4"></div>
|
<FormMessage />
|
||||||
<FormMessage />
|
</div>
|
||||||
</div>
|
</FormItem>
|
||||||
</FormItem>
|
);
|
||||||
)}
|
}}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -25,7 +25,7 @@ const EntityTypesItem = ({
|
|||||||
rules={[{ required: true }]}
|
rules={[{ required: true }]}
|
||||||
initialValue={initialEntityTypes}
|
initialValue={initialEntityTypes}
|
||||||
>
|
>
|
||||||
<EditTag></EditTag>
|
<EditTag value={field}></EditTag>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,12 +1,17 @@
|
|||||||
|
import { useGetPaginationWithRouter } from '@/hooks/logic-hooks';
|
||||||
import { useCallback, useState } from 'react';
|
import { useCallback, useState } from 'react';
|
||||||
import { FilterChange, FilterValue } from './interface';
|
import { FilterChange, FilterValue } from './interface';
|
||||||
|
|
||||||
export function useHandleFilterSubmit() {
|
export function useHandleFilterSubmit() {
|
||||||
const [filterValue, setFilterValue] = useState<FilterValue>({});
|
const [filterValue, setFilterValue] = useState<FilterValue>({});
|
||||||
|
const { setPagination } = useGetPaginationWithRouter();
|
||||||
const handleFilterSubmit: FilterChange = useCallback((value) => {
|
const handleFilterSubmit: FilterChange = useCallback(
|
||||||
setFilterValue(value);
|
(value) => {
|
||||||
}, []);
|
setFilterValue(value);
|
||||||
|
setPagination({ page: 1 });
|
||||||
|
},
|
||||||
|
[setPagination],
|
||||||
|
);
|
||||||
|
|
||||||
return { filterValue, setFilterValue, handleFilterSubmit };
|
return { filterValue, setFilterValue, handleFilterSubmit };
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,7 +7,7 @@ interface IProps {
|
|||||||
max?: number;
|
max?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function MaxTokenNumberFormField({ max = 2048 }: IProps) {
|
export function MaxTokenNumberFormField({ max = 2048, initialValue }: IProps) {
|
||||||
const { t } = useTranslate('knowledgeConfiguration');
|
const { t } = useTranslate('knowledgeConfiguration');
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -15,6 +15,7 @@ export function MaxTokenNumberFormField({ max = 2048 }: IProps) {
|
|||||||
name={'parser_config.chunk_token_num'}
|
name={'parser_config.chunk_token_num'}
|
||||||
label={t('chunkTokenNumber')}
|
label={t('chunkTokenNumber')}
|
||||||
max={max}
|
max={max}
|
||||||
|
defaultValue={initialValue ?? 0}
|
||||||
layout={FormLayout.Horizontal}
|
layout={FormLayout.Horizontal}
|
||||||
></SliderInputFormField>
|
></SliderInputFormField>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -1,24 +1,49 @@
|
|||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
|
|
||||||
import { cn } from '@/lib/utils';
|
import { cn } from '@/lib/utils';
|
||||||
|
type InputProps = React.ComponentProps<'input'> & {
|
||||||
|
icon?: React.ReactNode;
|
||||||
|
iconPosition?: 'left' | 'right';
|
||||||
|
};
|
||||||
|
|
||||||
function Input({ className, type, ...props }: React.ComponentProps<'input'>) {
|
function Input({
|
||||||
|
className,
|
||||||
|
type,
|
||||||
|
icon,
|
||||||
|
iconPosition = 'left',
|
||||||
|
...props
|
||||||
|
}: InputProps) {
|
||||||
return (
|
return (
|
||||||
<input
|
<div className="relative">
|
||||||
type={type}
|
{icon && (
|
||||||
data-slot="input"
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
'border-input file:text-foreground placeholder:text-muted-foreground/70 flex h-9 w-full min-w-0 rounded-md border bg-transparent px-3 py-1 text-sm shadow-xs transition-[color,box-shadow] outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50',
|
'absolute w-1 top-0 flex h-full items-center justify-center pointer-events-none',
|
||||||
'focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]',
|
iconPosition === 'left' ? 'left-5' : 'right-5',
|
||||||
'aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive',
|
iconPosition === 'left' ? 'pr-2' : 'pl-2',
|
||||||
type === 'search' &&
|
)}
|
||||||
'[&::-webkit-search-cancel-button]:appearance-none [&::-webkit-search-decoration]:appearance-none [&::-webkit-search-results-button]:appearance-none [&::-webkit-search-results-decoration]:appearance-none',
|
>
|
||||||
type === 'file' &&
|
{icon}
|
||||||
'text-muted-foreground/70 file:border-input file:text-foreground p-0 pr-3 italic file:me-3 file:h-full file:border-0 file:border-r file:border-solid file:bg-transparent file:px-3 file:text-sm file:font-medium file:not-italic',
|
</div>
|
||||||
className,
|
|
||||||
)}
|
)}
|
||||||
{...props}
|
<input
|
||||||
/>
|
type={type}
|
||||||
|
data-slot="input"
|
||||||
|
className={cn(
|
||||||
|
'border-input file:text-foreground placeholder:text-muted-foreground/70 flex h-9 w-full min-w-0 rounded-md border bg-transparent px-3 py-1 text-sm shadow-xs transition-[color,box-shadow] outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50',
|
||||||
|
'focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]',
|
||||||
|
'aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive',
|
||||||
|
type === 'search' &&
|
||||||
|
'[&::-webkit-search-cancel-button]:appearance-none [&::-webkit-search-decoration]:appearance-none [&::-webkit-search-results-button]:appearance-none [&::-webkit-search-results-decoration]:appearance-none',
|
||||||
|
type === 'file' &&
|
||||||
|
'text-muted-foreground/70 file:border-input file:text-foreground p-0 pr-3 italic file:me-3 file:h-full file:border-0 file:border-r file:border-solid file:bg-transparent file:px-3 file:text-sm file:font-medium file:not-italic',
|
||||||
|
icon && iconPosition === 'left' && 'pl-7',
|
||||||
|
icon && iconPosition === 'right' && 'pr-7',
|
||||||
|
className,
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -64,10 +64,10 @@ const RaptorFormFields = () => {
|
|||||||
control={form.control}
|
control={form.control}
|
||||||
name={UseRaptorField}
|
name={UseRaptorField}
|
||||||
render={({ field }) => {
|
render={({ field }) => {
|
||||||
if (typeof field.value === 'undefined') {
|
// if (typeof field.value === 'undefined') {
|
||||||
// default value set
|
// // default value set
|
||||||
form.setValue('parser_config.raptor.use_raptor', false);
|
// form.setValue('parser_config.raptor.use_raptor', false);
|
||||||
}
|
// }
|
||||||
return (
|
return (
|
||||||
<FormItem
|
<FormItem
|
||||||
defaultChecked={false}
|
defaultChecked={false}
|
||||||
@ -102,27 +102,33 @@ const RaptorFormFields = () => {
|
|||||||
<FormField
|
<FormField
|
||||||
control={form.control}
|
control={form.control}
|
||||||
name={'parser_config.raptor.prompt'}
|
name={'parser_config.raptor.prompt'}
|
||||||
render={({ field }) => (
|
render={({ field }) => {
|
||||||
<FormItem className=" items-center space-y-0 ">
|
return (
|
||||||
<div className="flex items-start">
|
<FormItem className=" items-center space-y-0 ">
|
||||||
<FormLabel
|
<div className="flex items-start">
|
||||||
tooltip={t('promptTip')}
|
<FormLabel
|
||||||
className="text-sm text-muted-foreground whitespace-nowrap w-1/4"
|
tooltip={t('promptTip')}
|
||||||
>
|
className="text-sm text-muted-foreground whitespace-nowrap w-1/4"
|
||||||
{t('prompt')}
|
>
|
||||||
</FormLabel>
|
{t('prompt')}
|
||||||
<div className="w-3/4">
|
</FormLabel>
|
||||||
<FormControl>
|
<div className="w-3/4">
|
||||||
<Textarea {...field} rows={8} />
|
<FormControl>
|
||||||
</FormControl>
|
<Textarea
|
||||||
|
{...field}
|
||||||
|
rows={8}
|
||||||
|
defaultValue={t('promptText')}
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div className="flex pt-1">
|
||||||
<div className="flex pt-1">
|
<div className="w-1/4"></div>
|
||||||
<div className="w-1/4"></div>
|
<FormMessage />
|
||||||
<FormMessage />
|
</div>
|
||||||
</div>
|
</FormItem>
|
||||||
</FormItem>
|
);
|
||||||
)}
|
}}
|
||||||
/>
|
/>
|
||||||
<SliderInputFormField
|
<SliderInputFormField
|
||||||
name={'parser_config.raptor.max_token'}
|
name={'parser_config.raptor.max_token'}
|
||||||
@ -164,7 +170,7 @@ const RaptorFormFields = () => {
|
|||||||
<div className="w-3/4">
|
<div className="w-3/4">
|
||||||
<FormControl defaultValue={0}>
|
<FormControl defaultValue={0}>
|
||||||
<div className="flex gap-4">
|
<div className="flex gap-4">
|
||||||
<Input {...field} />
|
<Input {...field} defaultValue={0} />
|
||||||
<Button
|
<Button
|
||||||
size={'sm'}
|
size={'sm'}
|
||||||
onClick={handleGenerate}
|
onClick={handleGenerate}
|
||||||
|
|||||||
@ -4,10 +4,12 @@ import { cn } from '@/lib/utils';
|
|||||||
import { Search } from 'lucide-react';
|
import { Search } from 'lucide-react';
|
||||||
|
|
||||||
export interface InputProps
|
export interface InputProps
|
||||||
extends React.InputHTMLAttributes<HTMLInputElement> {}
|
extends React.InputHTMLAttributes<HTMLInputElement> {
|
||||||
|
value?: string | number | readonly string[] | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
const Input = React.forwardRef<HTMLInputElement, InputProps>(
|
const Input = React.forwardRef<HTMLInputElement, InputProps>(
|
||||||
({ className, type, ...props }, ref) => {
|
({ className, type, value, ...props }, ref) => {
|
||||||
return (
|
return (
|
||||||
<input
|
<input
|
||||||
type={type}
|
type={type}
|
||||||
@ -16,6 +18,7 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>(
|
|||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
ref={ref}
|
ref={ref}
|
||||||
|
value={value ?? ''}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -5,7 +5,27 @@ import * as React from 'react';
|
|||||||
|
|
||||||
import { cn } from '@/lib/utils';
|
import { cn } from '@/lib/utils';
|
||||||
|
|
||||||
const Popover = PopoverPrimitive.Root;
|
const Popover = (props: PopoverPrimitive.PopoverProps) => {
|
||||||
|
const { children, open: openState, onOpenChange } = props;
|
||||||
|
const [open, setOpen] = React.useState(true);
|
||||||
|
React.useEffect(() => {
|
||||||
|
setOpen(!!openState);
|
||||||
|
}, [openState]);
|
||||||
|
const handleOnOpenChange = React.useCallback(
|
||||||
|
(e: boolean) => {
|
||||||
|
if (onOpenChange) {
|
||||||
|
onOpenChange?.(e);
|
||||||
|
}
|
||||||
|
setOpen(e);
|
||||||
|
},
|
||||||
|
[onOpenChange],
|
||||||
|
);
|
||||||
|
return (
|
||||||
|
<PopoverPrimitive.Root open={open} onOpenChange={handleOnOpenChange}>
|
||||||
|
{children}
|
||||||
|
</PopoverPrimitive.Root>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
const PopoverTrigger = PopoverPrimitive.Trigger;
|
const PopoverTrigger = PopoverPrimitive.Trigger;
|
||||||
|
|
||||||
|
|||||||
133
web/src/components/ui/radio.tsx
Normal file
133
web/src/components/ui/radio.tsx
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
import { cn } from '@/lib/utils';
|
||||||
|
import { Radio as LucideRadio } from 'lucide-react';
|
||||||
|
import React, { useContext, useState } from 'react';
|
||||||
|
|
||||||
|
const RadioGroupContext = React.createContext<{
|
||||||
|
value: string | number;
|
||||||
|
onChange: (value: string | number) => void;
|
||||||
|
disabled?: boolean;
|
||||||
|
} | null>(null);
|
||||||
|
|
||||||
|
type RadioProps = {
|
||||||
|
value: string | number;
|
||||||
|
checked?: boolean;
|
||||||
|
disabled?: boolean;
|
||||||
|
onChange?: (checked: boolean) => void;
|
||||||
|
children?: React.ReactNode;
|
||||||
|
};
|
||||||
|
|
||||||
|
function Radio({ value, checked, disabled, onChange, children }: RadioProps) {
|
||||||
|
const groupContext = useContext(RadioGroupContext);
|
||||||
|
const isControlled = checked !== undefined;
|
||||||
|
// const [internalChecked, setInternalChecked] = useState(false);
|
||||||
|
|
||||||
|
const isChecked = isControlled ? checked : groupContext?.value === value;
|
||||||
|
const mergedDisabled = disabled || groupContext?.disabled;
|
||||||
|
|
||||||
|
const handleClick = () => {
|
||||||
|
if (mergedDisabled) return;
|
||||||
|
|
||||||
|
// if (!isControlled) {
|
||||||
|
// setInternalChecked(!isChecked);
|
||||||
|
// }
|
||||||
|
|
||||||
|
if (onChange) {
|
||||||
|
onChange(!isChecked);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (groupContext && !groupContext.disabled) {
|
||||||
|
groupContext.onChange(value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<label
|
||||||
|
className={cn(
|
||||||
|
'flex items-center cursor-pointer gap-2 text-sm',
|
||||||
|
mergedDisabled && 'cursor-not-allowed opacity-50',
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
className={cn(
|
||||||
|
'flex h-4 w-4 items-center justify-center rounded-full border border-input transition-colors',
|
||||||
|
'peer ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2',
|
||||||
|
isChecked && 'border-primary bg-primary/10',
|
||||||
|
mergedDisabled && 'border-muted',
|
||||||
|
)}
|
||||||
|
onClick={handleClick}
|
||||||
|
>
|
||||||
|
{isChecked && (
|
||||||
|
<LucideRadio className="h-3 w-3 fill-primary text-primary" />
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
|
{children && <span className="text-foreground">{children}</span>}
|
||||||
|
</label>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
type RadioGroupProps = {
|
||||||
|
value?: string | number;
|
||||||
|
defaultValue?: string | number;
|
||||||
|
onChange?: (value: string | number) => void;
|
||||||
|
disabled?: boolean;
|
||||||
|
children: React.ReactNode;
|
||||||
|
className?: string;
|
||||||
|
direction?: 'horizontal' | 'vertical';
|
||||||
|
};
|
||||||
|
|
||||||
|
function Group({
|
||||||
|
value,
|
||||||
|
defaultValue,
|
||||||
|
onChange,
|
||||||
|
disabled,
|
||||||
|
children,
|
||||||
|
className,
|
||||||
|
direction = 'horizontal',
|
||||||
|
}: RadioGroupProps) {
|
||||||
|
const [internalValue, setInternalValue] = useState(defaultValue || '');
|
||||||
|
|
||||||
|
const isControlled = value !== undefined;
|
||||||
|
const mergedValue = isControlled ? value : internalValue;
|
||||||
|
|
||||||
|
const handleChange = (val: string | number) => {
|
||||||
|
if (disabled) return;
|
||||||
|
|
||||||
|
if (!isControlled) {
|
||||||
|
setInternalValue(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (onChange) {
|
||||||
|
onChange(val);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<RadioGroupContext.Provider
|
||||||
|
value={{
|
||||||
|
value: mergedValue,
|
||||||
|
onChange: handleChange,
|
||||||
|
disabled,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className={cn(
|
||||||
|
'flex gap-4',
|
||||||
|
direction === 'vertical' ? 'flex-col' : 'flex-row',
|
||||||
|
className,
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{React.Children.map(children, (child) =>
|
||||||
|
React.cloneElement(child as React.ReactElement, {
|
||||||
|
disabled: disabled || child?.props?.disabled,
|
||||||
|
}),
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</RadioGroupContext.Provider>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const RadioComponent = Object.assign(Radio, {
|
||||||
|
Group,
|
||||||
|
});
|
||||||
|
|
||||||
|
export { RadioComponent as Radio };
|
||||||
@ -31,6 +31,15 @@ export function Segmented({
|
|||||||
onChange,
|
onChange,
|
||||||
className,
|
className,
|
||||||
}: SegmentedProps) {
|
}: SegmentedProps) {
|
||||||
|
const [selectedValue, setSelectedValue] = React.useState<
|
||||||
|
SegmentedValue | undefined
|
||||||
|
>(value);
|
||||||
|
const handleOnChange = (e: SegmentedValue) => {
|
||||||
|
if (onChange) {
|
||||||
|
onChange(e);
|
||||||
|
}
|
||||||
|
setSelectedValue(e);
|
||||||
|
};
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
@ -48,11 +57,11 @@ export function Segmented({
|
|||||||
className={cn(
|
className={cn(
|
||||||
'inline-flex items-center px-6 py-2 text-base font-normal rounded-3xl cursor-pointer text-text-badge',
|
'inline-flex items-center px-6 py-2 text-base font-normal rounded-3xl cursor-pointer text-text-badge',
|
||||||
{
|
{
|
||||||
'bg-text-title': value === actualValue,
|
'bg-text-title': selectedValue === actualValue,
|
||||||
'text-text-title-invert': value === actualValue,
|
'text-text-title-invert': selectedValue === actualValue,
|
||||||
},
|
},
|
||||||
)}
|
)}
|
||||||
onClick={() => onChange?.(actualValue)}
|
onClick={() => handleOnChange(actualValue)}
|
||||||
>
|
>
|
||||||
{isObject ? option.label : option}
|
{isObject ? option.label : option}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -180,7 +180,9 @@ export const useCreateChunk = () => {
|
|||||||
const { data } = await service(payload);
|
const { data } = await service(payload);
|
||||||
if (data.code === 0) {
|
if (data.code === 0) {
|
||||||
message.success(t('message.created'));
|
message.success(t('message.created'));
|
||||||
queryClient.invalidateQueries({ queryKey: ['fetchChunkList'] });
|
setTimeout(() => {
|
||||||
|
queryClient.invalidateQueries({ queryKey: ['fetchChunkList'] });
|
||||||
|
}, 1000); // Delay to ensure the list is updated
|
||||||
}
|
}
|
||||||
return data?.code;
|
return data?.code;
|
||||||
},
|
},
|
||||||
|
|||||||
@ -122,10 +122,11 @@ export const useSetNextDocumentStatus = () => {
|
|||||||
documentId,
|
documentId,
|
||||||
}: {
|
}: {
|
||||||
status: boolean;
|
status: boolean;
|
||||||
documentId: string;
|
documentId: string | string[];
|
||||||
}) => {
|
}) => {
|
||||||
|
const ids = Array.isArray(documentId) ? documentId : [documentId];
|
||||||
const { data } = await kbService.document_change_status({
|
const { data } = await kbService.document_change_status({
|
||||||
doc_id: documentId,
|
doc_ids: ids,
|
||||||
status: Number(status),
|
status: Number(status),
|
||||||
});
|
});
|
||||||
if (data.code === 0) {
|
if (data.code === 0) {
|
||||||
|
|||||||
@ -25,13 +25,14 @@ import {
|
|||||||
import { useDebounce } from 'ahooks';
|
import { useDebounce } from 'ahooks';
|
||||||
import { message } from 'antd';
|
import { message } from 'antd';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { useSearchParams } from 'umi';
|
import { useParams, useSearchParams } from 'umi';
|
||||||
import { useHandleSearchChange } from './logic-hooks';
|
import { useHandleSearchChange } from './logic-hooks';
|
||||||
import { useSetPaginationParams } from './route-hook';
|
import { useSetPaginationParams } from './route-hook';
|
||||||
|
|
||||||
export const useKnowledgeBaseId = (): string => {
|
export const useKnowledgeBaseId = (): string => {
|
||||||
const [searchParams] = useSearchParams();
|
const [searchParams] = useSearchParams();
|
||||||
const knowledgeBaseId = searchParams.get('id');
|
const { id } = useParams();
|
||||||
|
const knowledgeBaseId = searchParams.get('id') || id;
|
||||||
|
|
||||||
return knowledgeBaseId || '';
|
return knowledgeBaseId || '';
|
||||||
};
|
};
|
||||||
|
|||||||
@ -37,20 +37,6 @@ export const useSetSelectedRecord = <T = IKnowledgeFile>() => {
|
|||||||
return { currentRecord, setRecord };
|
return { currentRecord, setRecord };
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useHandleSearchChange = () => {
|
|
||||||
const [searchString, setSearchString] = useState('');
|
|
||||||
|
|
||||||
const handleInputChange = useCallback(
|
|
||||||
(e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
|
|
||||||
const value = e.target.value;
|
|
||||||
setSearchString(value);
|
|
||||||
},
|
|
||||||
[],
|
|
||||||
);
|
|
||||||
|
|
||||||
return { handleInputChange, searchString };
|
|
||||||
};
|
|
||||||
|
|
||||||
export const useChangeLanguage = () => {
|
export const useChangeLanguage = () => {
|
||||||
const { i18n } = useTranslation();
|
const { i18n } = useTranslation();
|
||||||
const { saveSetting } = useSaveSetting();
|
const { saveSetting } = useSaveSetting();
|
||||||
@ -82,9 +68,12 @@ export const useGetPaginationWithRouter = () => {
|
|||||||
|
|
||||||
const setCurrentPagination = useCallback(
|
const setCurrentPagination = useCallback(
|
||||||
(pagination: { page: number; pageSize?: number }) => {
|
(pagination: { page: number; pageSize?: number }) => {
|
||||||
|
if (pagination.pageSize !== pageSize) {
|
||||||
|
pagination.page = 1; // Reset to first page if pageSize changes
|
||||||
|
}
|
||||||
setPaginationParams(pagination.page, pagination.pageSize);
|
setPaginationParams(pagination.page, pagination.pageSize);
|
||||||
},
|
},
|
||||||
[setPaginationParams],
|
[setPaginationParams, pageSize],
|
||||||
);
|
);
|
||||||
|
|
||||||
const pagination: PaginationProps = useMemo(() => {
|
const pagination: PaginationProps = useMemo(() => {
|
||||||
@ -106,6 +95,21 @@ export const useGetPaginationWithRouter = () => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const useHandleSearchChange = () => {
|
||||||
|
const [searchString, setSearchString] = useState('');
|
||||||
|
const { setPagination } = useGetPaginationWithRouter();
|
||||||
|
const handleInputChange = useCallback(
|
||||||
|
(e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
|
||||||
|
const value = e.target.value;
|
||||||
|
setSearchString(value);
|
||||||
|
setPagination({ page: 1 });
|
||||||
|
},
|
||||||
|
[setPagination],
|
||||||
|
);
|
||||||
|
|
||||||
|
return { handleInputChange, searchString };
|
||||||
|
};
|
||||||
|
|
||||||
export const useGetPagination = () => {
|
export const useGetPagination = () => {
|
||||||
const [pagination, setPagination] = useState({ page: 1, pageSize: 10 });
|
const [pagination, setPagination] = useState({ page: 1, pageSize: 10 });
|
||||||
const { t } = useTranslate('common');
|
const { t } = useTranslate('common');
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import { useNavigate, useParams, useSearchParams } from 'umi';
|
|||||||
|
|
||||||
export enum QueryStringMap {
|
export enum QueryStringMap {
|
||||||
KnowledgeId = 'knowledgeId',
|
KnowledgeId = 'knowledgeId',
|
||||||
|
id = 'id',
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useNavigatePage = () => {
|
export const useNavigatePage = () => {
|
||||||
@ -77,6 +78,7 @@ export const useNavigatePage = () => {
|
|||||||
[QueryStringMap.KnowledgeId]: searchParams.get(
|
[QueryStringMap.KnowledgeId]: searchParams.get(
|
||||||
QueryStringMap.KnowledgeId,
|
QueryStringMap.KnowledgeId,
|
||||||
),
|
),
|
||||||
|
[QueryStringMap.id]: searchParams.get(QueryStringMap.id),
|
||||||
};
|
};
|
||||||
if (queryStringKey) {
|
if (queryStringKey) {
|
||||||
return allQueryString[queryStringKey];
|
return allQueryString[queryStringKey];
|
||||||
|
|||||||
@ -204,10 +204,11 @@ export const useSetDocumentStatus = () => {
|
|||||||
documentId,
|
documentId,
|
||||||
}: {
|
}: {
|
||||||
status: boolean;
|
status: boolean;
|
||||||
documentId: string;
|
documentId: string | string[];
|
||||||
}) => {
|
}) => {
|
||||||
|
const ids = Array.isArray(documentId) ? documentId : [documentId];
|
||||||
const { data } = await kbService.document_change_status({
|
const { data } = await kbService.document_change_status({
|
||||||
doc_id: documentId,
|
doc_ids: ids,
|
||||||
status: Number(status),
|
status: Number(status),
|
||||||
});
|
});
|
||||||
if (data.code === 0) {
|
if (data.code === 0) {
|
||||||
|
|||||||
@ -1,18 +1,26 @@
|
|||||||
import { ReactComponent as FilterIcon } from '@/assets/filter.svg';
|
import { Input } from '@/components/originui/input';
|
||||||
import { useTranslate } from '@/hooks/common-hooks';
|
import { Button } from '@/components/ui/button';
|
||||||
import { PlusOutlined, SearchOutlined } from '@ant-design/icons';
|
|
||||||
import {
|
import {
|
||||||
Button,
|
|
||||||
Input,
|
|
||||||
Popover,
|
Popover,
|
||||||
Radio,
|
PopoverContent,
|
||||||
RadioChangeEvent,
|
PopoverTrigger,
|
||||||
Segmented,
|
} from '@/components/ui/popover';
|
||||||
SegmentedProps,
|
import { Radio } from '@/components/ui/radio';
|
||||||
Space,
|
import { useTranslate } from '@/hooks/common-hooks';
|
||||||
} from 'antd';
|
import { cn } from '@/lib/utils';
|
||||||
|
import { SearchOutlined } from '@ant-design/icons';
|
||||||
|
import { ListFilter, Plus } from 'lucide-react';
|
||||||
|
import { useState } from 'react';
|
||||||
import { ChunkTextMode } from '../../constant';
|
import { ChunkTextMode } from '../../constant';
|
||||||
|
interface ChunkResultBarProps {
|
||||||
|
changeChunkTextMode: React.Dispatch<React.SetStateAction<string | number>>;
|
||||||
|
available: number | undefined;
|
||||||
|
selectAllChunk: (value: boolean) => void;
|
||||||
|
handleSetAvailable: (value: number | undefined) => void;
|
||||||
|
createChunk: () => void;
|
||||||
|
handleInputChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
|
||||||
|
searchString: string;
|
||||||
|
}
|
||||||
export default ({
|
export default ({
|
||||||
changeChunkTextMode,
|
changeChunkTextMode,
|
||||||
available,
|
available,
|
||||||
@ -21,52 +29,75 @@ export default ({
|
|||||||
createChunk,
|
createChunk,
|
||||||
handleInputChange,
|
handleInputChange,
|
||||||
searchString,
|
searchString,
|
||||||
}) => {
|
}: ChunkResultBarProps) => {
|
||||||
const { t } = useTranslate('chunk');
|
const { t } = useTranslate('chunk');
|
||||||
|
const [textSelectValue, setTextSelectValue] = useState<string | number>(
|
||||||
const handleFilterChange = (e: RadioChangeEvent) => {
|
ChunkTextMode.Full,
|
||||||
|
);
|
||||||
|
const handleFilterChange = (e: string | number) => {
|
||||||
|
const value = e === -1 ? undefined : (e as number);
|
||||||
selectAllChunk(false);
|
selectAllChunk(false);
|
||||||
handleSetAvailable(e.target.value);
|
handleSetAvailable(value);
|
||||||
};
|
};
|
||||||
const filterContent = (
|
const filterContent = (
|
||||||
<Radio.Group onChange={handleFilterChange} value={available}>
|
<div className="w-[200px]">
|
||||||
<Space direction="vertical">
|
<Radio.Group onChange={handleFilterChange} value={available}>
|
||||||
<Radio value={undefined}>{t('all')}</Radio>
|
<div className="flex flex-col gap-2 p-4">
|
||||||
<Radio value={1}>{t('enabled')}</Radio>
|
<Radio value={-1}>{t('all')}</Radio>
|
||||||
<Radio value={0}>{t('disabled')}</Radio>
|
<Radio value={1}>{t('enabled')}</Radio>
|
||||||
</Space>
|
<Radio value={0}>{t('disabled')}</Radio>
|
||||||
</Radio.Group>
|
</div>
|
||||||
|
</Radio.Group>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
|
const textSelectOptions = [
|
||||||
|
{ label: t(ChunkTextMode.Full), value: ChunkTextMode.Full },
|
||||||
|
{ label: t(ChunkTextMode.Ellipse), value: ChunkTextMode.Ellipse },
|
||||||
|
];
|
||||||
|
|
||||||
|
const changeTextSelectValue = (value: string | number) => {
|
||||||
|
setTextSelectValue(value);
|
||||||
|
changeChunkTextMode(value);
|
||||||
|
};
|
||||||
return (
|
return (
|
||||||
<div className="flex pr-[25px]">
|
<div className="flex pr-[25px]">
|
||||||
<Segmented
|
<div className="flex items-center gap-4 bg-card text-muted-foreground w-fit h-[35px] rounded-md px-4 py-2 text-base">
|
||||||
options={[
|
{textSelectOptions.map((option) => (
|
||||||
{ label: t(ChunkTextMode.Full), value: ChunkTextMode.Full },
|
<div
|
||||||
{ label: t(ChunkTextMode.Ellipse), value: ChunkTextMode.Ellipse },
|
key={option.value}
|
||||||
]}
|
className={cn('flex items-center cursor-pointer', {
|
||||||
onChange={changeChunkTextMode as SegmentedProps['onChange']}
|
'text-white': option.value === textSelectValue,
|
||||||
/>
|
})}
|
||||||
|
onClick={() => changeTextSelectValue(option.value)}
|
||||||
|
>
|
||||||
|
{option.label}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
<div className="ml-auto"></div>
|
<div className="ml-auto"></div>
|
||||||
<Input
|
<Input
|
||||||
|
className="bg-card text-muted-foreground"
|
||||||
style={{ width: 200 }}
|
style={{ width: 200 }}
|
||||||
size="middle"
|
|
||||||
placeholder={t('search')}
|
placeholder={t('search')}
|
||||||
prefix={<SearchOutlined />}
|
icon={<SearchOutlined />}
|
||||||
allowClear
|
|
||||||
onChange={handleInputChange}
|
onChange={handleInputChange}
|
||||||
value={searchString}
|
value={searchString}
|
||||||
/>
|
/>
|
||||||
<div className="w-[20px]"></div>
|
<div className="w-[20px]"></div>
|
||||||
<Popover content={filterContent} placement="bottom" arrow={false}>
|
<Popover>
|
||||||
<Button icon={<FilterIcon />} />
|
<PopoverTrigger asChild>
|
||||||
|
<Button className="bg-card text-muted-foreground hover:bg-card">
|
||||||
|
<ListFilter />
|
||||||
|
</Button>
|
||||||
|
</PopoverTrigger>
|
||||||
|
<PopoverContent className="p-0 w-[200px]">
|
||||||
|
{filterContent}
|
||||||
|
</PopoverContent>
|
||||||
</Popover>
|
</Popover>
|
||||||
<div className="w-[20px]"></div>
|
<div className="w-[20px]"></div>
|
||||||
<Button
|
<Button onClick={() => createChunk()}>
|
||||||
icon={<PlusOutlined />}
|
<Plus size={44} />
|
||||||
type="primary"
|
</Button>
|
||||||
onClick={() => createChunk()}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -20,12 +20,17 @@ import ChunkResultBar from './components/chunk-result-bar';
|
|||||||
import CheckboxSets from './components/chunk-result-bar/checkbox-sets';
|
import CheckboxSets from './components/chunk-result-bar/checkbox-sets';
|
||||||
import DocumentHeader from './components/document-preview/document-header';
|
import DocumentHeader from './components/document-preview/document-header';
|
||||||
|
|
||||||
|
import { PageHeader } from '@/components/page-header';
|
||||||
import message from '@/components/ui/message';
|
import message from '@/components/ui/message';
|
||||||
import {
|
import {
|
||||||
RAGFlowPagination,
|
RAGFlowPagination,
|
||||||
RAGFlowPaginationType,
|
RAGFlowPaginationType,
|
||||||
} from '@/components/ui/ragflow-pagination';
|
} from '@/components/ui/ragflow-pagination';
|
||||||
import { Spin } from '@/components/ui/spin';
|
import { Spin } from '@/components/ui/spin';
|
||||||
|
import {
|
||||||
|
QueryStringMap,
|
||||||
|
useNavigatePage,
|
||||||
|
} from '@/hooks/logic-hooks/navigate-hooks';
|
||||||
import styles from './index.less';
|
import styles from './index.less';
|
||||||
|
|
||||||
const Chunk = () => {
|
const Chunk = () => {
|
||||||
@ -56,7 +61,7 @@ const Chunk = () => {
|
|||||||
chunkUpdatingVisible,
|
chunkUpdatingVisible,
|
||||||
documentId,
|
documentId,
|
||||||
} = useUpdateChunk();
|
} = useUpdateChunk();
|
||||||
|
const { navigateToDataset, getQueryString } = useNavigatePage();
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setChunkList(data);
|
setChunkList(data);
|
||||||
}, [data]);
|
}, [data]);
|
||||||
@ -159,6 +164,10 @@ const Chunk = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
<PageHeader
|
||||||
|
title="Back"
|
||||||
|
back={navigateToDataset(getQueryString(QueryStringMap.id) as string)}
|
||||||
|
></PageHeader>
|
||||||
<div className={styles.chunkPage}>
|
<div className={styles.chunkPage}>
|
||||||
<div className="flex flex-1 gap-8">
|
<div className="flex flex-1 gap-8">
|
||||||
<div className="w-2/5">
|
<div className="w-2/5">
|
||||||
|
|||||||
@ -61,9 +61,7 @@ export function useBulkOperateDataset({
|
|||||||
|
|
||||||
const onChangeStatus = useCallback(
|
const onChangeStatus = useCallback(
|
||||||
(enabled: boolean) => {
|
(enabled: boolean) => {
|
||||||
selectedRowKeys.forEach((id) => {
|
setDocumentStatus({ status: enabled, documentId: selectedRowKeys });
|
||||||
setDocumentStatus({ status: enabled, documentId: id });
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
[selectedRowKeys, setDocumentStatus],
|
[selectedRowKeys, setDocumentStatus],
|
||||||
);
|
);
|
||||||
|
|||||||
@ -10,7 +10,7 @@ export default ({
|
|||||||
tab: 'generalForm' | 'chunkMethodForm';
|
tab: 'generalForm' | 'chunkMethodForm';
|
||||||
parserId: string;
|
parserId: string;
|
||||||
}) => {
|
}) => {
|
||||||
const [visible, setVisible] = useState(true);
|
const [visible, setVisible] = useState(false);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
|
|||||||
@ -23,7 +23,7 @@ export function NaiveConfiguration() {
|
|||||||
<ChunkMethodItem></ChunkMethodItem>
|
<ChunkMethodItem></ChunkMethodItem>
|
||||||
<LayoutRecognizeFormField></LayoutRecognizeFormField>
|
<LayoutRecognizeFormField></LayoutRecognizeFormField>
|
||||||
<EmbeddingModelItem></EmbeddingModelItem>
|
<EmbeddingModelItem></EmbeddingModelItem>
|
||||||
<MaxTokenNumberFormField></MaxTokenNumberFormField>
|
<MaxTokenNumberFormField initialValue={512}></MaxTokenNumberFormField>
|
||||||
<DelimiterFormField></DelimiterFormField>
|
<DelimiterFormField></DelimiterFormField>
|
||||||
</ConfigurationFormContainer>
|
</ConfigurationFormContainer>
|
||||||
<ConfigurationFormContainer>
|
<ConfigurationFormContainer>
|
||||||
|
|||||||
@ -22,7 +22,6 @@ export function GeneralForm() {
|
|||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [avatarFile, setAvatarFile] = useState<File | null>(null);
|
const [avatarFile, setAvatarFile] = useState<File | null>(null);
|
||||||
const [avatarBase64Str, setAvatarBase64Str] = useState(''); // Avatar Image base64
|
const [avatarBase64Str, setAvatarBase64Str] = useState(''); // Avatar Image base64
|
||||||
// const [submitLoading, setSubmitLoading] = useState(false); // submit button loading
|
|
||||||
|
|
||||||
const { saveKnowledgeConfiguration, loading: submitLoading } =
|
const { saveKnowledgeConfiguration, loading: submitLoading } =
|
||||||
useUpdateKnowledge();
|
useUpdateKnowledge();
|
||||||
@ -94,7 +93,7 @@ export function GeneralForm() {
|
|||||||
<div className="w-[64px] h-[64px] grid place-content-center border border-dashed rounded-md">
|
<div className="w-[64px] h-[64px] grid place-content-center border border-dashed rounded-md">
|
||||||
<div className="flex flex-col items-center">
|
<div className="flex flex-col items-center">
|
||||||
<Upload />
|
<Upload />
|
||||||
<p>Upload</p>
|
<p>{t('common.upload')}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
|
|||||||
@ -131,22 +131,9 @@ export default function DatasetSettings() {
|
|||||||
<ChunkMethodForm></ChunkMethodForm>
|
<ChunkMethodForm></ChunkMethodForm>
|
||||||
</TabsContent>
|
</TabsContent>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
{/* <div className="text-right">
|
|
||||||
<ButtonLoading type="submit">Submit</ButtonLoading>
|
|
||||||
</div> */}
|
|
||||||
</form>
|
</form>
|
||||||
</Form>
|
</Form>
|
||||||
<ChunkMethodLearnMore tab={currentTab} parserId={parserId} />
|
<ChunkMethodLearnMore tab={currentTab} parserId={parserId} />
|
||||||
{/* <div
|
|
||||||
style={{
|
|
||||||
display: currentTab === 'chunkMethodForm' ? 'block' : 'none',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Button variant="outline">Learn More</Button>
|
|
||||||
<div className="bg-[#FFF]/10 p-[20px] rounded-[12px] mt-[10px]">
|
|
||||||
<CategoryPanel chunkMethod={parserId}></CategoryPanel>
|
|
||||||
</div>
|
|
||||||
</div> */}
|
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user