Fix:Some bugs (#12648)

### What problem does this PR solve?

Fix: Modified and optimized the metadata condition card component.
Fix: Use startOfDay and endOfDay to ensure the date range includes a
full day.

### Type of change

- [x] Bug Fix (non-breaking change which fixes an issue)
This commit is contained in:
chanx
2026-01-15 19:28:22 +08:00
committed by GitHub
parent cec06bfb5d
commit 8c1fbfb130
2 changed files with 131 additions and 77 deletions

View File

@ -1,4 +1,3 @@
import { SelectWithSearch } from '@/components/originui/select-with-search';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { import {
DropdownMenu, DropdownMenu,
@ -18,13 +17,16 @@ import { Separator } from '@/components/ui/separator';
import { SwitchLogicOperator, SwitchOperatorOptions } from '@/constants/agent'; import { SwitchLogicOperator, SwitchOperatorOptions } from '@/constants/agent';
import { useBuildSwitchOperatorOptions } from '@/hooks/logic-hooks/use-build-operator-options'; import { useBuildSwitchOperatorOptions } from '@/hooks/logic-hooks/use-build-operator-options';
import { useFetchKnowledgeMetadata } from '@/hooks/use-knowledge-request'; import { useFetchKnowledgeMetadata } from '@/hooks/use-knowledge-request';
import { cn } from '@/lib/utils';
import { PromptEditor } from '@/pages/agent/form/components/prompt-editor'; import { PromptEditor } from '@/pages/agent/form/components/prompt-editor';
import { Plus, X } from 'lucide-react'; import { Plus, X } from 'lucide-react';
import { useCallback, useMemo } from 'react'; import { useCallback, useMemo } from 'react';
import { useFieldArray, useFormContext, useWatch } from 'react-hook-form'; import { useFieldArray, useFormContext, useWatch } from 'react-hook-form';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { LogicalOperator } from '../logical-operator'; import { LogicalOperator } from '../logical-operator';
import { Card, CardContent } from '../ui/card';
import { InputSelect } from '../ui/input-select'; import { InputSelect } from '../ui/input-select';
import { RAGFlowSelect } from '../ui/select';
export function MetadataFilterConditions({ export function MetadataFilterConditions({
kbIds, kbIds,
@ -62,13 +64,14 @@ export function MetadataFilterConditions({
[append, fields.length, form, logic], [append, fields.length, form, logic],
); );
const RenderField = ({ function ConditionCards({
fieldName, fieldName,
index, index,
}: { }: {
fieldName: string; fieldName: string;
index: number; index: number;
}) => { }) {
const { t } = useTranslation();
const form = useFormContext(); const form = useFormContext();
const key = useWatch({ name: fieldName }); const key = useWatch({ name: fieldName });
const valueOptions = useMemo(() => { const valueOptions = useMemo(() => {
@ -83,14 +86,18 @@ export function MetadataFilterConditions({
}, [key]); }, [key]);
return ( return (
<section className="flex gap-2"> <div className="flex gap-1">
<div className="flex-1 flex flex-col gap-2 min-w-0"> <Card
<div className="flex items-center gap-1"> className={cn(
'relative bg-transparent border-input-border border flex-1 min-w-0',
)}
>
<section className="p-2 bg-bg-card flex justify-between items-center">
<FormField <FormField
control={form.control} control={form.control}
name={fieldName} name={fieldName}
render={({ field }) => ( render={({ field }) => (
<FormItem className="flex-1 overflow-hidden min-w-0"> <FormItem className="flex-1 min-w-0">
<FormControl> <FormControl>
<Input <Input
{...field} {...field}
@ -101,55 +108,61 @@ export function MetadataFilterConditions({
</FormItem> </FormItem>
)} )}
/> />
<Separator className="w-1 text-text-secondary" /> <div className="flex items-center">
<Separator orientation="vertical" className="h-2.5" />
<FormField
control={form.control}
name={`${name}.${index}.op`}
render={({ field }) => (
<FormItem>
<FormControl>
<RAGFlowSelect
{...field}
options={switchOperatorOptions}
onlyShowSelectedIcon
triggerClassName="w-30 bg-transparent border-none"
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
</div>
</section>
<CardContent className="p-4 ">
<FormField <FormField
control={form.control} control={form.control}
name={`${name}.${index}.op`} name={`${name}.${index}.value`}
render={({ field }) => ( render={({ field: valueField }) => (
<FormItem className="flex-1 overflow-hidden min-w-0"> <FormItem>
<FormControl> <FormControl>
<SelectWithSearch {canReference ? (
{...field} <PromptEditor
options={switchOperatorOptions} {...valueField}
></SelectWithSearch> multiLine={false}
showToolbar={false}
></PromptEditor>
) : (
<InputSelect
placeholder={t('common.pleaseInput')}
{...valueField}
options={valueOptions}
className="w-full"
/>
)}
</FormControl> </FormControl>
<FormMessage /> <FormMessage />
</FormItem> </FormItem>
)} )}
/> />
</div> </CardContent>
<FormField </Card>
control={form.control}
name={`${name}.${index}.value`}
render={({ field: valueField }) => (
<FormItem className="flex-1 overflow-hidden min-w-0">
<FormControl>
{canReference ? (
<PromptEditor
{...valueField}
multiLine={false}
showToolbar={false}
></PromptEditor>
) : (
<InputSelect
placeholder={t('common.pleaseInput')}
{...valueField}
options={valueOptions}
className="w-full"
/>
)}
</FormControl>
<FormMessage />
</FormItem>
)}
/>
</div>
<Button variant={'ghost'} onClick={() => remove(index)}> <Button variant={'ghost'} onClick={() => remove(index)}>
<X className="text-text-sub-title-invert " /> <X />
</Button> </Button>
</section> </div>
); );
}; }
return ( return (
<section className="flex flex-col gap-2"> <section className="flex flex-col gap-2">
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
@ -177,7 +190,11 @@ export function MetadataFilterConditions({
{fields.map((field, index) => { {fields.map((field, index) => {
const typeField = `${name}.${index}.key`; const typeField = `${name}.${index}.key`;
return ( return (
<RenderField key={field.id} fieldName={typeField} index={index} /> <ConditionCards
key={field.id}
fieldName={typeField}
index={index}
/>
); );
})} })}
</div> </div>

View File

@ -1,15 +1,3 @@
import {
endOfMonth,
endOfYear,
format,
startOfMonth,
startOfYear,
subDays,
subMonths,
subYears,
} from 'date-fns';
import { useEffect, useId, useState } from 'react';
import { Calendar, DateRange } from '@/components/originui/calendar'; import { Calendar, DateRange } from '@/components/originui/calendar';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { import {
@ -18,7 +6,20 @@ import {
PopoverTrigger, PopoverTrigger,
} from '@/components/ui/popover'; } from '@/components/ui/popover';
import { cn } from '@/lib/utils'; import { cn } from '@/lib/utils';
import {
endOfDay,
endOfMonth,
endOfYear,
format,
startOfDay,
startOfMonth,
startOfYear,
subDays,
subMonths,
subYears,
} from 'date-fns';
import { CalendarIcon } from 'lucide-react'; import { CalendarIcon } from 'lucide-react';
import { useEffect, useId, useState } from 'react';
const CalendarComp = ({ const CalendarComp = ({
selectDateRange, selectDateRange,
@ -27,20 +28,20 @@ const CalendarComp = ({
}: ITimeRangePickerProps) => { }: ITimeRangePickerProps) => {
const today = new Date(); const today = new Date();
const yesterday = { const yesterday = {
from: subDays(today, 1), from: startOfDay(subDays(today, 1)),
to: subDays(today, 1), to: endOfDay(subDays(today, 1)),
}; };
const last7Days = { const last7Days = {
from: subDays(today, 6), from: startOfDay(subDays(today, 6)),
to: today, to: endOfDay(today),
}; };
const last30Days = { const last30Days = {
from: subDays(today, 29), from: startOfDay(subDays(today, 29)),
to: today, to: endOfDay(today),
}; };
const monthToDate = { const monthToDate = {
from: startOfMonth(today), from: startOfMonth(today),
to: today, to: endOfDay(today),
}; };
const lastMonth = { const lastMonth = {
from: startOfMonth(subMonths(today, 1)), from: startOfMonth(subMonths(today, 1)),
@ -48,7 +49,7 @@ const CalendarComp = ({
}; };
const yearToDate = { const yearToDate = {
from: startOfYear(today), from: startOfYear(today),
to: today, to: endOfDay(today),
}; };
const lastYear = { const lastYear = {
from: startOfYear(subYears(today, 1)), from: startOfYear(subYears(today, 1)),
@ -65,9 +66,7 @@ const CalendarComp = ({
]; ];
const [month, setMonth] = useState(today); const [month, setMonth] = useState(today);
const [date, setDate] = useState<DateRange>(selectDateRange || last7Days); const [date, setDate] = useState<DateRange>(selectDateRange || last7Days);
useEffect(() => {
onSelect?.(date);
}, [date, onSelect]);
return ( return (
<div> <div>
<div className="rounded-md border"> <div className="rounded-md border">
@ -80,11 +79,13 @@ const CalendarComp = ({
size="sm" size="sm"
className="w-full justify-start" className="w-full justify-start"
onClick={() => { onClick={() => {
setDate({ const newDateRange = {
from: today, from: startOfDay(today),
to: today, to: endOfDay(today),
}); };
setDate(newDateRange);
setMonth(today); setMonth(today);
onSelect?.(newDateRange);
}} }}
> >
Today Today
@ -98,6 +99,7 @@ const CalendarComp = ({
onClick={() => { onClick={() => {
setDate(dateRange.value); setDate(dateRange.value);
setMonth(dateRange.value.to); setMonth(dateRange.value.to);
onSelect?.(dateRange.value);
}} }}
> >
{dateRange.key} {dateRange.key}
@ -111,7 +113,13 @@ const CalendarComp = ({
selected={date} selected={date}
onSelect={(newDate) => { onSelect={(newDate) => {
if (newDate) { if (newDate) {
setDate(newDate as DateRange); const dateRange = newDate as DateRange;
const newDateRange = {
from: startOfDay(dateRange.from),
to: dateRange.to ? endOfDay(dateRange.to) : undefined,
};
setDate(newDateRange);
onSelect?.(newDateRange);
} }
}} }}
month={month} month={month}
@ -130,7 +138,7 @@ const CalendarComp = ({
export type ITimeRangePickerProps = { export type ITimeRangePickerProps = {
onSelect: (e: DateRange) => void; onSelect: (e: DateRange) => void;
selectDateRange: DateRange; selectDateRange?: DateRange;
className?: string; className?: string;
}; };
const TimeRangePicker = ({ const TimeRangePicker = ({
@ -140,11 +148,40 @@ const TimeRangePicker = ({
}: ITimeRangePickerProps) => { }: ITimeRangePickerProps) => {
const id = useId(); const id = useId();
const today = new Date(); const today = new Date();
// Initialize without timezone conversion
const [date, setDate] = useState<DateRange | undefined>( const [date, setDate] = useState<DateRange | undefined>(
selectDateRange || { from: today, to: today }, selectDateRange
? {
from: startOfDay(selectDateRange.from),
to: selectDateRange.to ? endOfDay(selectDateRange.to) : undefined,
}
: {
from: startOfDay(today),
to: endOfDay(today),
},
); );
useEffect(() => { useEffect(() => {
setDate(selectDateRange); if (!selectDateRange || !selectDateRange.from) return;
try {
const fromDate = new Date(selectDateRange.from);
const toDate = selectDateRange.to
? new Date(selectDateRange.to)
: undefined;
if (isNaN(fromDate.getTime())) return;
if (toDate && isNaN(toDate.getTime())) return;
setDate({
from: startOfDay(fromDate),
to: toDate ? endOfDay(toDate) : undefined,
});
} catch (error) {
console.error('Error updating date range from props:', error);
}
}, [selectDateRange]); }, [selectDateRange]);
const onChange = (e: DateRange | undefined) => { const onChange = (e: DateRange | undefined) => {
if (!e) return; if (!e) return;