### What problem does this PR solve? Feat: Display the document configuration dialog with shadcn #3221 ### Type of change - [x] New Feature (non-breaking change which adds functionality)tags/v0.19.0
| import { useTranslate } from '@/hooks/common-hooks'; | |||||
| import { SliderInputFormField } from './slider-input-form-field'; | |||||
| export function AutoKeywordsFormField() { | |||||
| const { t } = useTranslate('knowledgeDetails'); | |||||
| return ( | |||||
| <SliderInputFormField | |||||
| name={'parser_config.auto_keywords'} | |||||
| label={t('autoKeywords')} | |||||
| max={30} | |||||
| min={0} | |||||
| tooltip={t('autoKeywordsTip')} | |||||
| ></SliderInputFormField> | |||||
| ); | |||||
| } | |||||
| export function AutoQuestionsFormField() { | |||||
| const { t } = useTranslate('knowledgeDetails'); | |||||
| return ( | |||||
| <SliderInputFormField | |||||
| name={'parser_config.auto_questions'} | |||||
| label={t('autoQuestions')} | |||||
| max={10} | |||||
| min={0} | |||||
| tooltip={t('autoQuestionsTip')} | |||||
| ></SliderInputFormField> | |||||
| ); | |||||
| } |
| FormLabel, | FormLabel, | ||||
| FormMessage, | FormMessage, | ||||
| } from '@/components/ui/form'; | } from '@/components/ui/form'; | ||||
| import { DocumentParserType } from '@/constants/knowledge'; | |||||
| import { useTranslate } from '@/hooks/common-hooks'; | import { useTranslate } from '@/hooks/common-hooks'; | ||||
| import { useFetchKnowledgeBaseConfiguration } from '@/hooks/use-knowledge-request'; | |||||
| import { IModalProps } from '@/interfaces/common'; | import { IModalProps } from '@/interfaces/common'; | ||||
| import { IParserConfig } from '@/interfaces/database/document'; | import { IParserConfig } from '@/interfaces/database/document'; | ||||
| import { IChangeParserConfigRequestBody } from '@/interfaces/request/document'; | import { IChangeParserConfigRequestBody } from '@/interfaces/request/document'; | ||||
| import { zodResolver } from '@hookform/resolvers/zod'; | import { zodResolver } from '@hookform/resolvers/zod'; | ||||
| import { useForm } from 'react-hook-form'; | |||||
| import {} from 'module'; | |||||
| import { useMemo } from 'react'; | |||||
| import { useForm, useWatch } from 'react-hook-form'; | |||||
| import { z } from 'zod'; | import { z } from 'zod'; | ||||
| import { | import { | ||||
| Select, | |||||
| SelectContent, | |||||
| SelectItem, | |||||
| SelectTrigger, | |||||
| SelectValue, | |||||
| } from '../ui/select'; | |||||
| import { useFetchParserListOnMount } from './hooks'; | |||||
| AutoKeywordsFormField, | |||||
| AutoQuestionsFormField, | |||||
| } from '../auto-keywords-form-field'; | |||||
| import { DatasetConfigurationContainer } from '../dataset-configuration-container'; | |||||
| import { DelimiterFormField } from '../delimiter-form-field'; | |||||
| import { EntityTypesFormField } from '../entity-types-form-field'; | |||||
| import { ExcelToHtmlFormField } from '../excel-to-html-form-field'; | |||||
| import { | |||||
| DocumentType, | |||||
| LayoutRecognizeFormField, | |||||
| } from '../layout-recognize-form-field'; | |||||
| import { MaxTokenNumberFormField } from '../max-token-number-from-field'; | |||||
| import { | |||||
| UseGraphRagFormField, | |||||
| showGraphRagItems, | |||||
| } from '../parse-configuration/graph-rag-form-fields'; | |||||
| import RaptorFormFields, { | |||||
| showRaptorParseConfiguration, | |||||
| } from '../parse-configuration/raptor-form-fields'; | |||||
| import { Input } from '../ui/input'; | |||||
| import { RAGFlowSelect } from '../ui/select'; | |||||
| import { useFetchParserListOnMount, useShowAutoKeywords } from './hooks'; | |||||
| const FormId = 'ChunkMethodDialogForm'; | |||||
| interface IProps | interface IProps | ||||
| extends IModalProps<{ | extends IModalProps<{ | ||||
| documentId: string; | documentId: string; | ||||
| } | } | ||||
| const hidePagesChunkMethods = [ | |||||
| DocumentParserType.Qa, | |||||
| DocumentParserType.Table, | |||||
| DocumentParserType.Picture, | |||||
| DocumentParserType.Resume, | |||||
| DocumentParserType.One, | |||||
| DocumentParserType.KnowledgeGraph, | |||||
| ]; | |||||
| export function ChunkMethodDialog({ | export function ChunkMethodDialog({ | ||||
| hideModal, | hideModal, | ||||
| onOk, | onOk, | ||||
| // form, | // form, | ||||
| ); | ); | ||||
| const { data: knowledgeDetails } = useFetchKnowledgeBaseConfiguration(); | |||||
| const useGraphRag = useMemo(() => { | |||||
| return knowledgeDetails.parser_config?.graphrag?.use_graphrag; | |||||
| }, [knowledgeDetails.parser_config?.graphrag?.use_graphrag]); | |||||
| const FormSchema = z.object({ | const FormSchema = z.object({ | ||||
| name: z | |||||
| parser_id: z | |||||
| .string() | .string() | ||||
| .min(1, { | .min(1, { | ||||
| message: 'namePlaceholder', | message: 'namePlaceholder', | ||||
| }) | }) | ||||
| .trim(), | .trim(), | ||||
| parser_config: z.object({ | |||||
| task_page_size: z.coerce.number(), | |||||
| layout_recognize: z.string(), | |||||
| }), | |||||
| }); | }); | ||||
| const form = useForm<z.infer<typeof FormSchema>>({ | const form = useForm<z.infer<typeof FormSchema>>({ | ||||
| resolver: zodResolver(FormSchema), | resolver: zodResolver(FormSchema), | ||||
| defaultValues: { name: '' }, | |||||
| defaultValues: { | |||||
| parser_id: parserId, | |||||
| parser_config: { | |||||
| task_page_size: 12, | |||||
| layout_recognize: DocumentType.DeepDOC, | |||||
| }, | |||||
| }, | |||||
| }); | |||||
| const layoutRecognize = useWatch({ | |||||
| name: 'parser_config.layout_recognize', | |||||
| control: form.control, | |||||
| }); | |||||
| const selectedTag = useWatch({ | |||||
| name: 'parser_id', | |||||
| control: form.control, | |||||
| }); | }); | ||||
| const isPdf = documentExtension === 'pdf'; | |||||
| const showPages = useMemo(() => { | |||||
| return isPdf && hidePagesChunkMethods.every((x) => x !== selectedTag); | |||||
| }, [selectedTag, isPdf]); | |||||
| const showOne = useMemo(() => { | |||||
| return ( | |||||
| isPdf && | |||||
| hidePagesChunkMethods | |||||
| .filter((x) => x !== DocumentParserType.One) | |||||
| .every((x) => x !== selectedTag) | |||||
| ); | |||||
| }, [selectedTag, isPdf]); | |||||
| const showMaxTokenNumber = | |||||
| selectedTag === DocumentParserType.Naive || | |||||
| selectedTag === DocumentParserType.KnowledgeGraph; | |||||
| const showEntityTypes = selectedTag === DocumentParserType.KnowledgeGraph; | |||||
| const showExcelToHtml = | |||||
| selectedTag === DocumentParserType.Naive && documentExtension === 'xlsx'; | |||||
| const showAutoKeywords = useShowAutoKeywords(); | |||||
| async function onSubmit(data: z.infer<typeof FormSchema>) { | async function onSubmit(data: z.infer<typeof FormSchema>) { | ||||
| const ret = await onOk?.(); | |||||
| if (ret) { | |||||
| hideModal?.(); | |||||
| } | |||||
| console.log('🚀 ~ onSubmit ~ data:', data); | |||||
| // const ret = await onOk?.(); | |||||
| // if (ret) { | |||||
| // hideModal?.(); | |||||
| // } | |||||
| } | } | ||||
| return ( | return ( | ||||
| <Dialog open onOpenChange={hideModal}> | <Dialog open onOpenChange={hideModal}> | ||||
| <DialogContent> | |||||
| <DialogContent className="max-w-[50vw]"> | |||||
| <DialogHeader> | <DialogHeader> | ||||
| <DialogTitle>{t('chunkMethod')}</DialogTitle> | <DialogTitle>{t('chunkMethod')}</DialogTitle> | ||||
| </DialogHeader> | </DialogHeader> | ||||
| <Form {...form}> | <Form {...form}> | ||||
| <form onSubmit={form.handleSubmit(onSubmit)} className="space-y-6"> | |||||
| <form | |||||
| onSubmit={form.handleSubmit(onSubmit)} | |||||
| className="space-y-6" | |||||
| id={FormId} | |||||
| > | |||||
| <FormField | <FormField | ||||
| control={form.control} | control={form.control} | ||||
| name="name" | |||||
| name="parser_id" | |||||
| render={({ field }) => ( | render={({ field }) => ( | ||||
| <FormItem> | <FormItem> | ||||
| <FormLabel>{t('name')}</FormLabel> | <FormLabel>{t('name')}</FormLabel> | ||||
| <FormControl> | <FormControl> | ||||
| <Select | |||||
| <RAGFlowSelect | |||||
| {...field} | {...field} | ||||
| autoComplete="off" | |||||
| onValueChange={field.onChange} | |||||
| > | |||||
| <FormControl> | |||||
| <SelectTrigger> | |||||
| <SelectValue placeholder="Select a verified email to display" /> | |||||
| </SelectTrigger> | |||||
| </FormControl> | |||||
| <SelectContent> | |||||
| {parserList.map((x) => ( | |||||
| <SelectItem value={x.value} key={x.value}> | |||||
| {x.label} | |||||
| </SelectItem> | |||||
| ))} | |||||
| </SelectContent> | |||||
| </Select> | |||||
| options={parserList} | |||||
| ></RAGFlowSelect> | |||||
| </FormControl> | </FormControl> | ||||
| <FormMessage /> | <FormMessage /> | ||||
| </FormItem> | </FormItem> | ||||
| )} | )} | ||||
| /> | /> | ||||
| {showPages && layoutRecognize && ( | |||||
| <FormField | |||||
| control={form.control} | |||||
| name="parser_config.task_page_size" | |||||
| render={({ field }) => ( | |||||
| <FormItem> | |||||
| <FormLabel tooltip={t('taskPageSizeTip')}> | |||||
| {t('taskPageSize')} | |||||
| </FormLabel> | |||||
| <FormControl> | |||||
| <Input | |||||
| {...field} | |||||
| type={'number'} | |||||
| min={1} | |||||
| max={128} | |||||
| ></Input> | |||||
| </FormControl> | |||||
| <FormMessage /> | |||||
| </FormItem> | |||||
| )} | |||||
| /> | |||||
| )} | |||||
| <DatasetConfigurationContainer show={showOne || showMaxTokenNumber}> | |||||
| {showOne && <LayoutRecognizeFormField></LayoutRecognizeFormField>} | |||||
| {showMaxTokenNumber && ( | |||||
| <> | |||||
| <MaxTokenNumberFormField | |||||
| max={ | |||||
| selectedTag === DocumentParserType.KnowledgeGraph | |||||
| ? 8192 * 2 | |||||
| : 2048 | |||||
| } | |||||
| ></MaxTokenNumberFormField> | |||||
| <DelimiterFormField></DelimiterFormField> | |||||
| </> | |||||
| )} | |||||
| </DatasetConfigurationContainer> | |||||
| <DatasetConfigurationContainer | |||||
| show={showAutoKeywords(selectedTag) || showExcelToHtml} | |||||
| > | |||||
| {showAutoKeywords(selectedTag) && ( | |||||
| <> | |||||
| <AutoKeywordsFormField></AutoKeywordsFormField> | |||||
| <AutoQuestionsFormField></AutoQuestionsFormField> | |||||
| </> | |||||
| )} | |||||
| {showExcelToHtml && <ExcelToHtmlFormField></ExcelToHtmlFormField>} | |||||
| </DatasetConfigurationContainer> | |||||
| {showRaptorParseConfiguration( | |||||
| selectedTag as DocumentParserType, | |||||
| ) && ( | |||||
| <DatasetConfigurationContainer> | |||||
| <RaptorFormFields></RaptorFormFields> | |||||
| </DatasetConfigurationContainer> | |||||
| )} | |||||
| {showGraphRagItems(selectedTag as DocumentParserType) && | |||||
| useGraphRag && <UseGraphRagFormField></UseGraphRagFormField>} | |||||
| {showEntityTypes && <EntityTypesFormField></EntityTypesFormField>} | |||||
| </form> | </form> | ||||
| </Form> | </Form> | ||||
| <DialogFooter> | <DialogFooter> | ||||
| <Button type="submit">Save changes</Button> | |||||
| <Button type="submit" form={FormId}> | |||||
| Save changes | |||||
| </Button> | |||||
| </DialogFooter> | </DialogFooter> | ||||
| </DialogContent> | </DialogContent> | ||||
| </Dialog> | </Dialog> |
| import { forwardRef } from 'react'; | |||||
| import { useFormContext } from 'react-hook-form'; | |||||
| import { useTranslation } from 'react-i18next'; | |||||
| import { | |||||
| FormControl, | |||||
| FormField, | |||||
| FormItem, | |||||
| FormLabel, | |||||
| FormMessage, | |||||
| } from './ui/form'; | |||||
| import { Input, InputProps } from './ui/input'; | |||||
| interface IProps { | |||||
| value?: string | undefined; | |||||
| onChange?: (val: string | undefined) => void; | |||||
| } | |||||
| export const DelimiterInput = forwardRef<HTMLInputElement, InputProps & IProps>( | |||||
| ({ value, onChange, maxLength, defaultValue }, ref) => { | |||||
| const nextValue = value?.replaceAll('\n', '\\n'); | |||||
| const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => { | |||||
| const val = e.target.value; | |||||
| const nextValue = val.replaceAll('\\n', '\n'); | |||||
| onChange?.(nextValue); | |||||
| }; | |||||
| return ( | |||||
| <Input | |||||
| value={nextValue} | |||||
| onChange={handleInputChange} | |||||
| maxLength={maxLength} | |||||
| defaultValue={defaultValue} | |||||
| ref={ref} | |||||
| ></Input> | |||||
| ); | |||||
| }, | |||||
| ); | |||||
| export function DelimiterFormField() { | |||||
| const { t } = useTranslation(); | |||||
| const form = useFormContext(); | |||||
| return ( | |||||
| <FormField | |||||
| control={form.control} | |||||
| name={'parser_config.delimiter'} | |||||
| render={({ field }) => ( | |||||
| <FormItem> | |||||
| <FormLabel tooltip={t('knowledgeDetails.delimiterTip')}> | |||||
| {t('knowledgeDetails.delimiter')} | |||||
| </FormLabel> | |||||
| <FormControl defaultValue={`\n`}> | |||||
| <DelimiterInput {...field}></DelimiterInput> | |||||
| </FormControl> | |||||
| <FormMessage /> | |||||
| </FormItem> | |||||
| )} | |||||
| /> | |||||
| ); | |||||
| } |
| import { useTranslate } from '@/hooks/common-hooks'; | |||||
| import { useFormContext } from 'react-hook-form'; | |||||
| import EditTag from './edit-tag'; | |||||
| import { | |||||
| FormControl, | |||||
| FormField, | |||||
| FormItem, | |||||
| FormLabel, | |||||
| FormMessage, | |||||
| } from './ui/form'; | |||||
| type EntityTypesFormFieldProps = { | |||||
| name?: string; | |||||
| }; | |||||
| export function EntityTypesFormField({ | |||||
| name = 'parser_config.entity_types', | |||||
| }: EntityTypesFormFieldProps) { | |||||
| const { t } = useTranslate('knowledgeConfiguration'); | |||||
| const form = useFormContext(); | |||||
| return ( | |||||
| <FormField | |||||
| control={form.control} | |||||
| name={name} | |||||
| render={({ field }) => ( | |||||
| <FormItem> | |||||
| <FormLabel>{t('entityTypes')}</FormLabel> | |||||
| <FormControl> | |||||
| <EditTag {...field}></EditTag> | |||||
| </FormControl> | |||||
| <FormMessage /> | |||||
| </FormItem> | |||||
| )} | |||||
| /> | |||||
| ); | |||||
| } |
| import { useTranslate } from '@/hooks/common-hooks'; | |||||
| import { useFormContext } from 'react-hook-form'; | |||||
| import { | |||||
| FormControl, | |||||
| FormField, | |||||
| FormItem, | |||||
| FormLabel, | |||||
| FormMessage, | |||||
| } from './ui/form'; | |||||
| import { Switch } from './ui/switch'; | |||||
| export function ExcelToHtmlFormField() { | |||||
| const form = useFormContext(); | |||||
| const { t } = useTranslate('knowledgeDetails'); | |||||
| return ( | |||||
| <FormField | |||||
| control={form.control} | |||||
| name="parser_config.html4excel" | |||||
| render={({ field }) => ( | |||||
| <FormItem defaultChecked={false}> | |||||
| <FormLabel tooltip={t('html4excelTip')}>{t('html4excel')}</FormLabel> | |||||
| <FormControl> | |||||
| <Switch | |||||
| checked={field.value} | |||||
| onCheckedChange={field.onChange} | |||||
| ></Switch> | |||||
| </FormControl> | |||||
| <FormMessage /> | |||||
| </FormItem> | |||||
| )} | |||||
| /> | |||||
| ); | |||||
| } |
| import { LlmModelType } from '@/constants/knowledge'; | |||||
| import { useTranslate } from '@/hooks/common-hooks'; | |||||
| import { useSelectLlmOptionsByModelType } from '@/hooks/llm-hooks'; | |||||
| import { camelCase } from 'lodash'; | |||||
| import { useMemo } from 'react'; | |||||
| import { useFormContext } from 'react-hook-form'; | |||||
| import { | |||||
| FormControl, | |||||
| FormField, | |||||
| FormItem, | |||||
| FormLabel, | |||||
| FormMessage, | |||||
| } from './ui/form'; | |||||
| import { RAGFlowSelect } from './ui/select'; | |||||
| export const enum DocumentType { | |||||
| DeepDOC = 'DeepDOC', | |||||
| PlainText = 'Plain Text', | |||||
| } | |||||
| export function LayoutRecognizeFormField() { | |||||
| const form = useFormContext(); | |||||
| const { t } = useTranslate('knowledgeDetails'); | |||||
| const allOptions = useSelectLlmOptionsByModelType(); | |||||
| const options = useMemo(() => { | |||||
| const list = [DocumentType.DeepDOC, DocumentType.PlainText].map((x) => ({ | |||||
| label: x === DocumentType.PlainText ? t(camelCase(x)) : 'DeepDoc', | |||||
| value: x, | |||||
| })); | |||||
| const image2TextList = allOptions[LlmModelType.Image2text].map((x) => { | |||||
| return { | |||||
| ...x, | |||||
| options: x.options.map((y) => { | |||||
| return { | |||||
| ...y, | |||||
| label: ( | |||||
| <div className="flex justify-between items-center gap-2"> | |||||
| {y.label} | |||||
| <span className="text-red-500 text-sm">Experimental</span> | |||||
| </div> | |||||
| ), | |||||
| }; | |||||
| }), | |||||
| }; | |||||
| }); | |||||
| return [...list, ...image2TextList]; | |||||
| }, [allOptions, t]); | |||||
| return ( | |||||
| <FormField | |||||
| control={form.control} | |||||
| name="parser_config.layout_recognize" | |||||
| render={({ field }) => ( | |||||
| <FormItem> | |||||
| <FormLabel tooltip={t('layoutRecognizeTip')}> | |||||
| {t('layoutRecognize')} | |||||
| </FormLabel> | |||||
| <FormControl> | |||||
| <RAGFlowSelect {...field} options={options}></RAGFlowSelect> | |||||
| </FormControl> | |||||
| <FormMessage /> | |||||
| </FormItem> | |||||
| )} | |||||
| /> | |||||
| ); | |||||
| } |
| import { useTranslate } from '@/hooks/common-hooks'; | |||||
| import { SliderInputFormField } from './slider-input-form-field'; | |||||
| interface IProps { | |||||
| initialValue?: number; | |||||
| max?: number; | |||||
| } | |||||
| export function MaxTokenNumberFormField({ max = 2048 }: IProps) { | |||||
| const { t } = useTranslate('knowledgeConfiguration'); | |||||
| return ( | |||||
| <SliderInputFormField | |||||
| name={'parser_config.chunk_token_num'} | |||||
| label={t('chunkTokenNumber')} | |||||
| max={max} | |||||
| ></SliderInputFormField> | |||||
| ); | |||||
| } |
| import { DocumentParserType } from '@/constants/knowledge'; | |||||
| import { useTranslate } from '@/hooks/common-hooks'; | |||||
| import { cn } from '@/lib/utils'; | |||||
| import { Switch as AntSwitch, Form, Select } from 'antd'; | |||||
| import { upperFirst } from 'lodash'; | |||||
| import { useCallback, useMemo } from 'react'; | |||||
| import { useFormContext } from 'react-hook-form'; | |||||
| import { DatasetConfigurationContainer } from '../dataset-configuration-container'; | |||||
| import EntityTypesItem from '../entity-types-item'; | |||||
| import { | |||||
| FormControl, | |||||
| FormField, | |||||
| FormItem, | |||||
| FormLabel, | |||||
| FormMessage, | |||||
| } from '../ui/form'; | |||||
| import { Switch } from '../ui/switch'; | |||||
| const excludedTagParseMethods = [ | |||||
| DocumentParserType.Table, | |||||
| DocumentParserType.KnowledgeGraph, | |||||
| DocumentParserType.Tag, | |||||
| ]; | |||||
| export const showTagItems = (parserId: DocumentParserType) => { | |||||
| return !excludedTagParseMethods.includes(parserId); | |||||
| }; | |||||
| const enum MethodValue { | |||||
| General = 'general', | |||||
| Light = 'light', | |||||
| } | |||||
| export const excludedParseMethods = [ | |||||
| DocumentParserType.Table, | |||||
| DocumentParserType.Resume, | |||||
| DocumentParserType.Picture, | |||||
| DocumentParserType.KnowledgeGraph, | |||||
| DocumentParserType.Qa, | |||||
| DocumentParserType.Tag, | |||||
| ]; | |||||
| export const showGraphRagItems = (parserId: DocumentParserType | undefined) => { | |||||
| return !excludedParseMethods.some((x) => x === parserId); | |||||
| }; | |||||
| type GraphRagItemsProps = { | |||||
| marginBottom?: boolean; | |||||
| }; | |||||
| export function UseGraphRagItem() { | |||||
| const { t } = useTranslate('knowledgeConfiguration'); | |||||
| return ( | |||||
| <Form.Item | |||||
| name={['parser_config', 'graphrag', 'use_graphrag']} | |||||
| label={t('useGraphRag')} | |||||
| initialValue={false} | |||||
| valuePropName="checked" | |||||
| tooltip={t('useGraphRagTip')} | |||||
| > | |||||
| <AntSwitch /> | |||||
| </Form.Item> | |||||
| ); | |||||
| } | |||||
| export function UseGraphRagFormField() { | |||||
| const form = useFormContext(); | |||||
| const { t } = useTranslate('knowledgeConfiguration'); | |||||
| return ( | |||||
| <FormField | |||||
| control={form.control} | |||||
| name="parser_config.graphrag.use_graphrag" | |||||
| render={({ field }) => ( | |||||
| <FormItem defaultChecked={false}> | |||||
| <FormLabel tooltip={t('useGraphRagTip')}> | |||||
| {t('useGraphRag')} | |||||
| </FormLabel> | |||||
| <FormControl> | |||||
| <Switch | |||||
| checked={field.value} | |||||
| onCheckedChange={field.onChange} | |||||
| ></Switch> | |||||
| </FormControl> | |||||
| <FormMessage /> | |||||
| </FormItem> | |||||
| )} | |||||
| /> | |||||
| ); | |||||
| } | |||||
| // The three types "table", "resume" and "one" do not display this configuration. | |||||
| const GraphRagItems = ({ marginBottom = false }: GraphRagItemsProps) => { | |||||
| const { t } = useTranslate('knowledgeConfiguration'); | |||||
| const methodOptions = useMemo(() => { | |||||
| return [MethodValue.Light, MethodValue.General].map((x) => ({ | |||||
| value: x, | |||||
| label: upperFirst(x), | |||||
| })); | |||||
| }, []); | |||||
| const renderWideTooltip = useCallback( | |||||
| (title: React.ReactNode | string) => { | |||||
| return { | |||||
| title: typeof title === 'string' ? t(title) : title, | |||||
| overlayInnerStyle: { width: '32vw' }, | |||||
| }; | |||||
| }, | |||||
| [t], | |||||
| ); | |||||
| return ( | |||||
| <DatasetConfigurationContainer className={cn({ 'mb-4': marginBottom })}> | |||||
| <UseGraphRagItem></UseGraphRagItem> | |||||
| <Form.Item | |||||
| shouldUpdate={(prevValues, curValues) => | |||||
| prevValues.parser_config.graphrag.use_graphrag !== | |||||
| curValues.parser_config.graphrag.use_graphrag | |||||
| } | |||||
| > | |||||
| {({ getFieldValue }) => { | |||||
| const useRaptor = getFieldValue([ | |||||
| 'parser_config', | |||||
| 'graphrag', | |||||
| 'use_graphrag', | |||||
| ]); | |||||
| return ( | |||||
| useRaptor && ( | |||||
| <> | |||||
| <EntityTypesItem | |||||
| field={['parser_config', 'graphrag', 'entity_types']} | |||||
| ></EntityTypesItem> | |||||
| <Form.Item | |||||
| name={['parser_config', 'graphrag', 'method']} | |||||
| label={t('graphRagMethod')} | |||||
| tooltip={renderWideTooltip( | |||||
| <div | |||||
| dangerouslySetInnerHTML={{ | |||||
| __html: t('graphRagMethodTip'), | |||||
| }} | |||||
| ></div>, | |||||
| )} | |||||
| initialValue={MethodValue.Light} | |||||
| > | |||||
| <Select options={methodOptions} /> | |||||
| </Form.Item> | |||||
| <Form.Item | |||||
| name={['parser_config', 'graphrag', 'resolution']} | |||||
| label={t('resolution')} | |||||
| tooltip={renderWideTooltip('resolutionTip')} | |||||
| > | |||||
| <AntSwitch /> | |||||
| </Form.Item> | |||||
| <Form.Item | |||||
| name={['parser_config', 'graphrag', 'community']} | |||||
| label={t('community')} | |||||
| tooltip={renderWideTooltip('communityTip')} | |||||
| > | |||||
| <AntSwitch /> | |||||
| </Form.Item> | |||||
| </> | |||||
| ) | |||||
| ); | |||||
| }} | |||||
| </Form.Item> | |||||
| </DatasetConfigurationContainer> | |||||
| ); | |||||
| }; | |||||
| export default GraphRagItems; |
| import { DocumentParserType } from '@/constants/knowledge'; | |||||
| import { useTranslate } from '@/hooks/common-hooks'; | |||||
| import random from 'lodash/random'; | |||||
| import { Plus } from 'lucide-react'; | |||||
| import { useCallback } from 'react'; | |||||
| import { useFormContext, useWatch } from 'react-hook-form'; | |||||
| import { SliderInputFormField } from '../slider-input-form-field'; | |||||
| import { Button } from '../ui/button'; | |||||
| import { | |||||
| FormControl, | |||||
| FormField, | |||||
| FormItem, | |||||
| FormLabel, | |||||
| FormMessage, | |||||
| } from '../ui/form'; | |||||
| import { Input } from '../ui/input'; | |||||
| import { Switch } from '../ui/switch'; | |||||
| import { Textarea } from '../ui/textarea'; | |||||
| export const excludedParseMethods = [ | |||||
| DocumentParserType.Table, | |||||
| DocumentParserType.Resume, | |||||
| DocumentParserType.One, | |||||
| DocumentParserType.Picture, | |||||
| DocumentParserType.KnowledgeGraph, | |||||
| DocumentParserType.Qa, | |||||
| DocumentParserType.Tag, | |||||
| ]; | |||||
| export const showRaptorParseConfiguration = ( | |||||
| parserId: DocumentParserType | undefined, | |||||
| ) => { | |||||
| return !excludedParseMethods.some((x) => x === parserId); | |||||
| }; | |||||
| export const excludedTagParseMethods = [ | |||||
| DocumentParserType.Table, | |||||
| DocumentParserType.KnowledgeGraph, | |||||
| DocumentParserType.Tag, | |||||
| ]; | |||||
| export const showTagItems = (parserId: DocumentParserType) => { | |||||
| return !excludedTagParseMethods.includes(parserId); | |||||
| }; | |||||
| const UseRaptorField = 'parser_config.raptor.use_raptor'; | |||||
| const RandomSeedField = 'parser_config.raptor.random_seed'; | |||||
| // The three types "table", "resume" and "one" do not display this configuration. | |||||
| const RaptorFormFields = () => { | |||||
| const form = useFormContext(); | |||||
| const { t } = useTranslate('knowledgeConfiguration'); | |||||
| const useRaptor = useWatch({ name: UseRaptorField }); | |||||
| const handleGenerate = useCallback(() => { | |||||
| form.setValue(RandomSeedField, random(10000)); | |||||
| }, [form]); | |||||
| return ( | |||||
| <> | |||||
| <FormField | |||||
| control={form.control} | |||||
| name={UseRaptorField} | |||||
| render={({ field }) => ( | |||||
| <FormItem defaultChecked={false}> | |||||
| <FormLabel tooltip={t('useRaptorTip')}>{t('useRaptor')}</FormLabel> | |||||
| <FormControl> | |||||
| <Switch | |||||
| checked={field.value} | |||||
| onCheckedChange={field.onChange} | |||||
| ></Switch> | |||||
| </FormControl> | |||||
| <FormMessage /> | |||||
| </FormItem> | |||||
| )} | |||||
| /> | |||||
| {useRaptor && ( | |||||
| <> | |||||
| <FormField | |||||
| control={form.control} | |||||
| name={'parser_config.raptor.prompt'} | |||||
| render={({ field }) => ( | |||||
| <FormItem> | |||||
| <FormLabel tooltip={t('promptTip')}>{t('prompt')}</FormLabel> | |||||
| <FormControl defaultValue={t('promptText')}> | |||||
| <Textarea {...field} rows={8} /> | |||||
| </FormControl> | |||||
| <FormMessage /> | |||||
| </FormItem> | |||||
| )} | |||||
| /> | |||||
| <SliderInputFormField | |||||
| name={'parser_config.raptor.max_token'} | |||||
| label={t('maxToken')} | |||||
| tooltip={t('maxTokenTip')} | |||||
| defaultValue={256} | |||||
| max={2048} | |||||
| min={0} | |||||
| ></SliderInputFormField> | |||||
| <SliderInputFormField | |||||
| name={'parser_config.raptor.threshold'} | |||||
| label={t('threshold')} | |||||
| tooltip={t('thresholdTip')} | |||||
| defaultValue={0.1} | |||||
| step={0.01} | |||||
| max={1} | |||||
| min={0} | |||||
| ></SliderInputFormField> | |||||
| <SliderInputFormField | |||||
| name={'parser_config.raptor.max_cluster'} | |||||
| label={t('maxCluster')} | |||||
| tooltip={t('maxClusterTip')} | |||||
| defaultValue={64} | |||||
| max={1024} | |||||
| min={1} | |||||
| ></SliderInputFormField> | |||||
| <FormField | |||||
| control={form.control} | |||||
| name={'parser_config.raptor.random_seed'} | |||||
| render={({ field }) => ( | |||||
| <FormItem> | |||||
| <FormLabel>{t('randomSeed')}</FormLabel> | |||||
| <FormControl defaultValue={0}> | |||||
| <div className="flex gap-4"> | |||||
| <Input {...field} /> | |||||
| <Button size={'sm'} onClick={handleGenerate}> | |||||
| <Plus /> | |||||
| </Button> | |||||
| </div> | |||||
| </FormControl> | |||||
| <FormMessage /> | |||||
| </FormItem> | |||||
| )} | |||||
| /> | |||||
| </> | |||||
| )} | |||||
| </> | |||||
| ); | |||||
| }; | |||||
| export default RaptorFormFields; |
| import { ReactNode } from 'react'; | |||||
| import { useFormContext } from 'react-hook-form'; | |||||
| import { SingleFormSlider } from './ui/dual-range-slider'; | |||||
| import { | |||||
| FormControl, | |||||
| FormField, | |||||
| FormItem, | |||||
| FormLabel, | |||||
| FormMessage, | |||||
| } from './ui/form'; | |||||
| import { Input } from './ui/input'; | |||||
| type SliderInputFormFieldProps = { | |||||
| max?: number; | |||||
| min?: number; | |||||
| step?: number; | |||||
| name: string; | |||||
| label: string; | |||||
| tooltip?: ReactNode; | |||||
| defaultValue?: number; | |||||
| }; | |||||
| export function SliderInputFormField({ | |||||
| max, | |||||
| min, | |||||
| step, | |||||
| label, | |||||
| name, | |||||
| tooltip, | |||||
| defaultValue, | |||||
| }: SliderInputFormFieldProps) { | |||||
| const form = useFormContext(); | |||||
| return ( | |||||
| <FormField | |||||
| control={form.control} | |||||
| name={name} | |||||
| defaultValue={defaultValue} | |||||
| render={({ field }) => ( | |||||
| <FormItem> | |||||
| <div className="flex items-center justify-between"> | |||||
| <FormLabel tooltip={tooltip}>{label}</FormLabel> | |||||
| <FormControl> | |||||
| <Input | |||||
| type={'number'} | |||||
| className="h-7 w-20" | |||||
| max={max} | |||||
| min={min} | |||||
| step={step} | |||||
| {...field} | |||||
| // defaultValue={defaultValue} | |||||
| ></Input> | |||||
| </FormControl> | |||||
| </div> | |||||
| <FormControl> | |||||
| <SingleFormSlider | |||||
| {...field} | |||||
| max={max} | |||||
| min={min} | |||||
| step={step} | |||||
| // defaultValue={ | |||||
| // typeof defaultValue === 'number' ? [defaultValue] : undefined | |||||
| // } | |||||
| ></SingleFormSlider> | |||||
| </FormControl> | |||||
| <FormMessage /> | |||||
| </FormItem> | |||||
| )} | |||||
| /> | |||||
| ); | |||||
| } |
| allowClear, | allowClear, | ||||
| placeholder, | placeholder, | ||||
| contentProps = {}, | contentProps = {}, | ||||
| defaultValue, | |||||
| }, | }, | ||||
| ref, | ref, | ||||
| ) { | ) { | ||||
| const [key, setKey] = React.useState(+new Date()); | const [key, setKey] = React.useState(+new Date()); | ||||
| const [value, setValue] = React.useState<string | undefined>(undefined); | |||||
| const [value, setValue] = React.useState<string | undefined>(defaultValue); | |||||
| const FormControlWidget = FormControlComponent | const FormControlWidget = FormControlComponent | ||||
| ? FormControlComponent | ? FormControlComponent |
| import { IDocumentInfo } from '@/interfaces/database/document'; | import { IDocumentInfo } from '@/interfaces/database/document'; | ||||
| import { IChangeParserConfigRequestBody } from '@/interfaces/request/document'; | |||||
| import i18n from '@/locales/config'; | import i18n from '@/locales/config'; | ||||
| import kbService from '@/services/knowledge-service'; | import kbService from '@/services/knowledge-service'; | ||||
| import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; | import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; | ||||
| RunDocumentByIds = 'runDocumentByIds', | RunDocumentByIds = 'runDocumentByIds', | ||||
| RemoveDocument = 'removeDocument', | RemoveDocument = 'removeDocument', | ||||
| SaveDocumentName = 'saveDocumentName', | SaveDocumentName = 'saveDocumentName', | ||||
| SetDocumentParser = 'setDocumentParser', | |||||
| } | } | ||||
| export const useUploadNextDocument = () => { | export const useUploadNextDocument = () => { | ||||
| return { loading, saveName: mutateAsync, data }; | return { loading, saveName: mutateAsync, data }; | ||||
| }; | }; | ||||
| export const useSetDocumentParser = () => { | |||||
| const queryClient = useQueryClient(); | |||||
| const { | |||||
| data, | |||||
| isPending: loading, | |||||
| mutateAsync, | |||||
| } = useMutation({ | |||||
| mutationKey: [DocumentApiAction.SetDocumentParser], | |||||
| mutationFn: async ({ | |||||
| parserId, | |||||
| documentId, | |||||
| parserConfig, | |||||
| }: { | |||||
| parserId: string; | |||||
| documentId: string; | |||||
| parserConfig: IChangeParserConfigRequestBody; | |||||
| }) => { | |||||
| const { data } = await kbService.document_change_parser({ | |||||
| parser_id: parserId, | |||||
| doc_id: documentId, | |||||
| parser_config: parserConfig, | |||||
| }); | |||||
| if (data.code === 0) { | |||||
| queryClient.invalidateQueries({ | |||||
| queryKey: [DocumentApiAction.FetchDocumentList], | |||||
| }); | |||||
| message.success(i18n.t('message.modified')); | |||||
| } | |||||
| return data.code; | |||||
| }, | |||||
| }); | |||||
| return { setDocumentParser: mutateAsync, data, loading }; | |||||
| }; |
| import { | import { | ||||
| IKnowledge, | |||||
| IKnowledgeResult, | IKnowledgeResult, | ||||
| INextTestingResult, | INextTestingResult, | ||||
| } from '@/interfaces/database/knowledge'; | } from '@/interfaces/database/knowledge'; | ||||
| CreateKnowledge = 'createKnowledge', | CreateKnowledge = 'createKnowledge', | ||||
| DeleteKnowledge = 'deleteKnowledge', | DeleteKnowledge = 'deleteKnowledge', | ||||
| SaveKnowledge = 'saveKnowledge', | SaveKnowledge = 'saveKnowledge', | ||||
| FetchKnowledgeDetail = 'fetchKnowledgeDetail', | |||||
| } | } | ||||
| export const useKnowledgeBaseId = () => { | export const useKnowledgeBaseId = () => { | ||||
| return { data, loading, saveKnowledgeConfiguration: mutateAsync }; | return { data, loading, saveKnowledgeConfiguration: mutateAsync }; | ||||
| }; | }; | ||||
| export const useFetchKnowledgeBaseConfiguration = () => { | |||||
| const { id } = useParams(); | |||||
| const { data, isFetching: loading } = useQuery<IKnowledge>({ | |||||
| queryKey: [KnowledgeApiAction.FetchKnowledgeDetail], | |||||
| initialData: {} as IKnowledge, | |||||
| gcTime: 0, | |||||
| queryFn: async () => { | |||||
| const { data } = await kbService.get_kb_detail({ | |||||
| kb_id: id, | |||||
| }); | |||||
| return data?.data ?? {}; | |||||
| }, | |||||
| }); | |||||
| return { data, loading }; | |||||
| }; |
| import { IDocumentInfo } from '@/interfaces/database/document'; | import { IDocumentInfo } from '@/interfaces/database/document'; | ||||
| import { getExtension } from '@/utils/document-util'; | import { getExtension } from '@/utils/document-util'; | ||||
| import { useMemo } from 'react'; | import { useMemo } from 'react'; | ||||
| import { useChangeDocumentParser } from './hooks'; | |||||
| import { useChangeDocumentParser } from './use-change-document-parser'; | |||||
| import { useDatasetTableColumns } from './use-dataset-table-columns'; | import { useDatasetTableColumns } from './use-dataset-table-columns'; | ||||
| import { useRenameDocument } from './use-rename-document'; | import { useRenameDocument } from './use-rename-document'; | ||||
| changeParserVisible, | changeParserVisible, | ||||
| hideChangeParserModal, | hideChangeParserModal, | ||||
| showChangeParserModal, | showChangeParserModal, | ||||
| } = useChangeDocumentParser(currentRecord.id); | |||||
| changeParserRecord, | |||||
| } = useChangeDocumentParser(); | |||||
| const { | const { | ||||
| renameLoading, | renameLoading, | ||||
| </div> | </div> | ||||
| {changeParserVisible && ( | {changeParserVisible && ( | ||||
| <ChunkMethodDialog | <ChunkMethodDialog | ||||
| documentId={currentRecord.id} | |||||
| parserId={currentRecord.parser_id} | |||||
| parserConfig={currentRecord.parser_config} | |||||
| documentExtension={getExtension(currentRecord.name)} | |||||
| documentId={changeParserRecord.id} | |||||
| parserId={changeParserRecord.parser_id} | |||||
| parserConfig={changeParserRecord.parser_config} | |||||
| documentExtension={getExtension(changeParserRecord.name)} | |||||
| onOk={onChangeParserOk} | onOk={onChangeParserOk} | ||||
| visible={changeParserVisible} | visible={changeParserVisible} | ||||
| hideModal={hideChangeParserModal} | hideModal={hideChangeParserModal} |
| import { useSetModalState } from '@/hooks/common-hooks'; | import { useSetModalState } from '@/hooks/common-hooks'; | ||||
| import { | |||||
| useCreateNextDocument, | |||||
| useNextWebCrawl, | |||||
| useSetNextDocumentParser, | |||||
| } from '@/hooks/document-hooks'; | |||||
| import { useCreateNextDocument, useNextWebCrawl } from '@/hooks/document-hooks'; | |||||
| import { useGetKnowledgeSearchParams } from '@/hooks/route-hook'; | import { useGetKnowledgeSearchParams } from '@/hooks/route-hook'; | ||||
| import { IChangeParserConfigRequestBody } from '@/interfaces/request/document'; | |||||
| import { useCallback, useState } from 'react'; | import { useCallback, useState } from 'react'; | ||||
| import { useNavigate } from 'umi'; | import { useNavigate } from 'umi'; | ||||
| }; | }; | ||||
| }; | }; | ||||
| export const useChangeDocumentParser = (documentId: string) => { | |||||
| const { setDocumentParser, loading } = useSetNextDocumentParser(); | |||||
| const { | |||||
| visible: changeParserVisible, | |||||
| hideModal: hideChangeParserModal, | |||||
| showModal: showChangeParserModal, | |||||
| } = useSetModalState(); | |||||
| const onChangeParserOk = useCallback( | |||||
| async ({ | |||||
| parserId, | |||||
| parserConfig, | |||||
| }: { | |||||
| parserId: string; | |||||
| parserConfig: IChangeParserConfigRequestBody; | |||||
| }) => { | |||||
| const ret = await setDocumentParser({ | |||||
| parserId, | |||||
| documentId, | |||||
| parserConfig, | |||||
| }); | |||||
| if (ret === 0) { | |||||
| hideChangeParserModal(); | |||||
| } | |||||
| }, | |||||
| [hideChangeParserModal, setDocumentParser, documentId], | |||||
| ); | |||||
| return { | |||||
| changeParserLoading: loading, | |||||
| onChangeParserOk, | |||||
| changeParserVisible, | |||||
| hideChangeParserModal, | |||||
| showChangeParserModal, | |||||
| }; | |||||
| }; | |||||
| export const useGetRowSelection = () => { | export const useGetRowSelection = () => { | ||||
| const [selectedRowKeys, setSelectedRowKeys] = useState<React.Key[]>([]); | const [selectedRowKeys, setSelectedRowKeys] = useState<React.Key[]>([]); | ||||
| import { ConfirmDeleteDialog } from '@/components/confirm-delete-dialog'; | import { ConfirmDeleteDialog } from '@/components/confirm-delete-dialog'; | ||||
| import { Button } from '@/components/ui/button'; | import { Button } from '@/components/ui/button'; | ||||
| import { | |||||
| HoverCard, | |||||
| HoverCardContent, | |||||
| HoverCardTrigger, | |||||
| } from '@/components/ui/hover-card'; | |||||
| import { Progress } from '@/components/ui/progress'; | import { Progress } from '@/components/ui/progress'; | ||||
| import { Separator } from '@/components/ui/separator'; | import { Separator } from '@/components/ui/separator'; | ||||
| import { IDocumentInfo } from '@/interfaces/database/document'; | import { IDocumentInfo } from '@/interfaces/database/document'; | ||||
| import { cn } from '@/lib/utils'; | |||||
| import { CircleX, Play, RefreshCw } from 'lucide-react'; | import { CircleX, Play, RefreshCw } from 'lucide-react'; | ||||
| import { PropsWithChildren, useCallback } from 'react'; | |||||
| import { useTranslation } from 'react-i18next'; | import { useTranslation } from 'react-i18next'; | ||||
| import { RunningStatus } from './constant'; | import { RunningStatus } from './constant'; | ||||
| import { ParsingCard } from './parsing-card'; | import { ParsingCard } from './parsing-card'; | ||||
| import { UseChangeDocumentParserShowType } from './use-change-document-parser'; | |||||
| import { useHandleRunDocumentByIds } from './use-run-document'; | import { useHandleRunDocumentByIds } from './use-run-document'; | ||||
| import { isParserRunning } from './utils'; | import { isParserRunning } from './utils'; | ||||
| [RunningStatus.FAIL]: <RefreshCw />, | [RunningStatus.FAIL]: <RefreshCw />, | ||||
| }; | }; | ||||
| export function ParsingStatusCell({ record }: { record: IDocumentInfo }) { | |||||
| function MenuItem({ | |||||
| children, | |||||
| onClick, | |||||
| }: PropsWithChildren & { onClick?(): void }) { | |||||
| return ( | |||||
| <div | |||||
| onClick={onClick} | |||||
| className={cn( | |||||
| 'relative flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0', | |||||
| )} | |||||
| > | |||||
| {children} | |||||
| </div> | |||||
| ); | |||||
| } | |||||
| export function ParsingStatusCell({ | |||||
| record, | |||||
| showChangeParserModal, | |||||
| }: { record: IDocumentInfo } & UseChangeDocumentParserShowType) { | |||||
| const { t } = useTranslation(); | const { t } = useTranslation(); | ||||
| const { run, parser_id, progress, chunk_num, id } = record; | const { run, parser_id, progress, chunk_num, id } = record; | ||||
| const operationIcon = IconMap[run]; | const operationIcon = IconMap[run]; | ||||
| handleRunDocumentByIds(record.id, isRunning, shouldDelete); | handleRunDocumentByIds(record.id, isRunning, shouldDelete); | ||||
| }; | }; | ||||
| const handleShowChangeParserModal = useCallback(() => { | |||||
| showChangeParserModal(record); | |||||
| }, [record, showChangeParserModal]); | |||||
| return ( | return ( | ||||
| <section className="flex gap-2 items-center "> | <section className="flex gap-2 items-center "> | ||||
| <div> | <div> | ||||
| <Button variant={'ghost'} size={'sm'}> | |||||
| {parser_id} | |||||
| </Button> | |||||
| <HoverCard> | |||||
| <HoverCardTrigger> | |||||
| <Button variant={'ghost'} size={'sm'}> | |||||
| {parser_id} | |||||
| </Button> | |||||
| </HoverCardTrigger> | |||||
| <HoverCardContent> | |||||
| <MenuItem onClick={handleShowChangeParserModal}> | |||||
| {t('knowledgeDetails.chunkMethod')} | |||||
| </MenuItem> | |||||
| <MenuItem>{t('knowledgeDetails.setMetaData')}</MenuItem> | |||||
| </HoverCardContent> | |||||
| </HoverCard> | |||||
| <Separator orientation="vertical" /> | <Separator orientation="vertical" /> | ||||
| </div> | </div> | ||||
| <ConfirmDeleteDialog | <ConfirmDeleteDialog |
| import { useSetModalState } from '@/hooks/common-hooks'; | |||||
| import { useSetDocumentParser } from '@/hooks/use-document-request'; | |||||
| import { IDocumentInfo } from '@/interfaces/database/document'; | |||||
| import { IChangeParserConfigRequestBody } from '@/interfaces/request/document'; | |||||
| import { useCallback, useState } from 'react'; | |||||
| export const useChangeDocumentParser = () => { | |||||
| const { setDocumentParser, loading } = useSetDocumentParser(); | |||||
| const [record, setRecord] = useState<IDocumentInfo>({} as IDocumentInfo); | |||||
| const { | |||||
| visible: changeParserVisible, | |||||
| hideModal: hideChangeParserModal, | |||||
| showModal: showChangeParserModal, | |||||
| } = useSetModalState(); | |||||
| const onChangeParserOk = useCallback( | |||||
| async (parserId: string, parserConfig: IChangeParserConfigRequestBody) => { | |||||
| if (record?.id) { | |||||
| const ret = await setDocumentParser({ | |||||
| parserId, | |||||
| documentId: record?.id, | |||||
| parserConfig, | |||||
| }); | |||||
| if (ret === 0) { | |||||
| hideChangeParserModal(); | |||||
| } | |||||
| } | |||||
| }, | |||||
| [record?.id, setDocumentParser, hideChangeParserModal], | |||||
| ); | |||||
| const handleShowChangeParserModal = useCallback( | |||||
| (row: IDocumentInfo) => { | |||||
| setRecord(row); | |||||
| showChangeParserModal(); | |||||
| }, | |||||
| [showChangeParserModal], | |||||
| ); | |||||
| return { | |||||
| changeParserLoading: loading, | |||||
| onChangeParserOk, | |||||
| changeParserVisible, | |||||
| hideChangeParserModal, | |||||
| showChangeParserModal: handleShowChangeParserModal, | |||||
| changeParserRecord: record, | |||||
| }; | |||||
| }; | |||||
| export type UseChangeDocumentParserShowType = Pick< | |||||
| ReturnType<typeof useChangeDocumentParser>, | |||||
| 'showChangeParserModal' | |||||
| >; |
| import { getExtension } from '@/utils/document-util'; | import { getExtension } from '@/utils/document-util'; | ||||
| import { ColumnDef } from '@tanstack/table-core'; | import { ColumnDef } from '@tanstack/table-core'; | ||||
| import { ArrowUpDown } from 'lucide-react'; | import { ArrowUpDown } from 'lucide-react'; | ||||
| import { useCallback } from 'react'; | |||||
| import { useTranslation } from 'react-i18next'; | import { useTranslation } from 'react-i18next'; | ||||
| import { DatasetActionCell } from './dataset-action-cell'; | import { DatasetActionCell } from './dataset-action-cell'; | ||||
| import { useChangeDocumentParser } from './hooks'; | |||||
| import { ParsingStatusCell } from './parsing-status-cell'; | import { ParsingStatusCell } from './parsing-status-cell'; | ||||
| import { UseChangeDocumentParserShowType } from './use-change-document-parser'; | |||||
| import { UseRenameDocumentShowType } from './use-rename-document'; | import { UseRenameDocumentShowType } from './use-rename-document'; | ||||
| type UseDatasetTableColumnsType = Pick< | |||||
| ReturnType<typeof useChangeDocumentParser>, | |||||
| 'showChangeParserModal' | |||||
| > & { | |||||
| type UseDatasetTableColumnsType = UseChangeDocumentParserShowType & { | |||||
| setCurrentRecord: (record: IDocumentInfo) => void; | setCurrentRecord: (record: IDocumentInfo) => void; | ||||
| } & UseRenameDocumentShowType; | } & UseRenameDocumentShowType; | ||||
| // setCurrentRecord(record); | // setCurrentRecord(record); | ||||
| // showRenameModal(); | // showRenameModal(); | ||||
| // }; | // }; | ||||
| const onShowChangeParserModal = useCallback( | |||||
| (record: IDocumentInfo) => () => { | |||||
| setCurrentRecord(record); | |||||
| showChangeParserModal(); | |||||
| }, | |||||
| [setCurrentRecord, showChangeParserModal], | |||||
| ); | |||||
| // const onShowSetMetaModal = useCallback(() => { | // const onShowSetMetaModal = useCallback(() => { | ||||
| // setRecord(); | // setRecord(); | ||||
| header: t('parsingStatus'), | header: t('parsingStatus'), | ||||
| // meta: { cellClassName: 'min-w-[20vw]' }, | // meta: { cellClassName: 'min-w-[20vw]' }, | ||||
| cell: ({ row }) => { | cell: ({ row }) => { | ||||
| return <ParsingStatusCell record={row.original}></ParsingStatusCell>; | |||||
| return ( | |||||
| <ParsingStatusCell | |||||
| record={row.original} | |||||
| showChangeParserModal={showChangeParserModal} | |||||
| ></ParsingStatusCell> | |||||
| ); | |||||
| }, | }, | ||||
| }, | }, | ||||
| { | { |