mirror of
https://github.com/infiniflow/ragflow.git
synced 2025-12-23 06:46:40 +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:
@ -4,10 +4,12 @@ import { cn } from '@/lib/utils';
|
||||
import { Search } from 'lucide-react';
|
||||
|
||||
export interface InputProps
|
||||
extends React.InputHTMLAttributes<HTMLInputElement> {}
|
||||
extends React.InputHTMLAttributes<HTMLInputElement> {
|
||||
value?: string | number | readonly string[] | undefined;
|
||||
}
|
||||
|
||||
const Input = React.forwardRef<HTMLInputElement, InputProps>(
|
||||
({ className, type, ...props }, ref) => {
|
||||
({ className, type, value, ...props }, ref) => {
|
||||
return (
|
||||
<input
|
||||
type={type}
|
||||
@ -16,6 +18,7 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>(
|
||||
className,
|
||||
)}
|
||||
ref={ref}
|
||||
value={value ?? ''}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
|
||||
@ -5,7 +5,27 @@ import * as React from 'react';
|
||||
|
||||
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;
|
||||
|
||||
|
||||
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,
|
||||
className,
|
||||
}: SegmentedProps) {
|
||||
const [selectedValue, setSelectedValue] = React.useState<
|
||||
SegmentedValue | undefined
|
||||
>(value);
|
||||
const handleOnChange = (e: SegmentedValue) => {
|
||||
if (onChange) {
|
||||
onChange(e);
|
||||
}
|
||||
setSelectedValue(e);
|
||||
};
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
@ -48,11 +57,11 @@ export function Segmented({
|
||||
className={cn(
|
||||
'inline-flex items-center px-6 py-2 text-base font-normal rounded-3xl cursor-pointer text-text-badge',
|
||||
{
|
||||
'bg-text-title': value === actualValue,
|
||||
'text-text-title-invert': value === actualValue,
|
||||
'bg-text-title': selectedValue === actualValue,
|
||||
'text-text-title-invert': selectedValue === actualValue,
|
||||
},
|
||||
)}
|
||||
onClick={() => onChange?.(actualValue)}
|
||||
onClick={() => handleOnChange(actualValue)}
|
||||
>
|
||||
{isObject ? option.label : option}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user