Skip to content

Commit bb3d3f9

Browse files
authored
Refa: Pdf 2 Slices page to new style (infiniflow#8386)
### What problem does this PR solve? Refactor Pdf 2 Slices page to new style ### Type of change - [X] Refactoring
1 parent 8695d60 commit bb3d3f9

File tree

22 files changed

+1629
-5
lines changed

22 files changed

+1629
-5
lines changed

web/src/hooks/logic-hooks/navigate-hooks.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,8 @@ export const useNavigatePage = () => {
6464
const navigateToChunkParsedResult = useCallback(
6565
(id: string, knowledgeId?: string) => () => {
6666
navigate(
67-
`${Routes.ParsedResult}/${id}?${QueryStringMap.KnowledgeId}=${knowledgeId}`,
67+
// `${Routes.ParsedResult}/${id}?${QueryStringMap.KnowledgeId}=${knowledgeId}`,
68+
`${Routes.ParsedResult}/chunks?id=${knowledgeId}&doc_id=${id}`,
6869
);
6970
},
7071
[navigate],

web/src/hooks/use-chunk-request.ts

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
import { ResponseGetType } from '@/interfaces/database/base';
2+
import { IChunk, IKnowledgeFile } from '@/interfaces/database/knowledge';
3+
import kbService from '@/services/knowledge-service';
4+
import { useQuery } from '@tanstack/react-query';
5+
import { useDebounce } from 'ahooks';
6+
import { useCallback, useState } from 'react';
7+
import { IChunkListResult } from './chunk-hooks';
8+
import {
9+
useGetPaginationWithRouter,
10+
useHandleSearchChange,
11+
} from './logic-hooks';
12+
import { useGetKnowledgeSearchParams } from './route-hook';
13+
14+
export const useFetchNextChunkList = (): ResponseGetType<{
15+
data: IChunk[];
16+
total: number;
17+
documentInfo: IKnowledgeFile;
18+
}> &
19+
IChunkListResult => {
20+
const { pagination, setPagination } = useGetPaginationWithRouter();
21+
const { documentId } = useGetKnowledgeSearchParams();
22+
const { searchString, handleInputChange } = useHandleSearchChange();
23+
const [available, setAvailable] = useState<number | undefined>();
24+
const debouncedSearchString = useDebounce(searchString, { wait: 500 });
25+
26+
const { data, isFetching: loading } = useQuery({
27+
queryKey: [
28+
'fetchChunkList',
29+
documentId,
30+
pagination.current,
31+
pagination.pageSize,
32+
debouncedSearchString,
33+
available,
34+
],
35+
placeholderData: (previousData: any) =>
36+
previousData ?? { data: [], total: 0, documentInfo: {} }, // https://github.com/TanStack/query/issues/8183
37+
gcTime: 0,
38+
queryFn: async () => {
39+
const { data } = await kbService.chunk_list({
40+
doc_id: documentId,
41+
page: pagination.current,
42+
size: pagination.pageSize,
43+
available_int: available,
44+
keywords: searchString,
45+
});
46+
if (data.code === 0) {
47+
const res = data.data;
48+
return {
49+
data: res.chunks,
50+
total: res.total,
51+
documentInfo: res.doc,
52+
};
53+
}
54+
55+
return (
56+
data?.data ?? {
57+
data: [],
58+
total: 0,
59+
documentInfo: {},
60+
}
61+
);
62+
},
63+
});
64+
65+
const onInputChange: React.ChangeEventHandler<HTMLInputElement> = useCallback(
66+
(e) => {
67+
setPagination({ page: 1 });
68+
handleInputChange(e);
69+
},
70+
[handleInputChange, setPagination],
71+
);
72+
73+
const handleSetAvailable = useCallback(
74+
(a: number | undefined) => {
75+
setPagination({ page: 1 });
76+
setAvailable(a);
77+
},
78+
[setAvailable, setPagination],
79+
);
80+
81+
return {
82+
data,
83+
loading,
84+
pagination,
85+
setPagination,
86+
searchString,
87+
handleInputChange: onInputChange,
88+
available,
89+
handleSetAvailable,
90+
};
91+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
.image {
2+
width: 100px !important;
3+
object-fit: contain;
4+
}
5+
6+
.imagePreview {
7+
max-width: 50vw;
8+
max-height: 50vh;
9+
object-fit: contain;
10+
}
11+
12+
.content {
13+
flex: 1;
14+
.chunkText;
15+
}
16+
17+
.contentEllipsis {
18+
.multipleLineEllipsis(3);
19+
}
20+
21+
.contentText {
22+
word-break: break-all !important;
23+
}
24+
25+
.chunkCard {
26+
width: 100%;
27+
}
28+
29+
.cardSelected {
30+
background-color: @selectedBackgroundColor;
31+
}
32+
.cardSelectedDark {
33+
background-color: #ffffff2f;
34+
}
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
import Image from '@/components/image';
2+
import { IChunk } from '@/interfaces/database/knowledge';
3+
import { Card, Checkbox, CheckboxProps, Flex, Popover, Switch } from 'antd';
4+
import classNames from 'classnames';
5+
import DOMPurify from 'dompurify';
6+
import { useEffect, useState } from 'react';
7+
8+
import { useTheme } from '@/components/theme-provider';
9+
import { ChunkTextMode } from '../../constant';
10+
import styles from './index.less';
11+
12+
interface IProps {
13+
item: IChunk;
14+
checked: boolean;
15+
switchChunk: (available?: number, chunkIds?: string[]) => void;
16+
editChunk: (chunkId: string) => void;
17+
handleCheckboxClick: (chunkId: string, checked: boolean) => void;
18+
selected: boolean;
19+
clickChunkCard: (chunkId: string) => void;
20+
textMode: ChunkTextMode;
21+
}
22+
23+
const ChunkCard = ({
24+
item,
25+
checked,
26+
handleCheckboxClick,
27+
editChunk,
28+
switchChunk,
29+
selected,
30+
clickChunkCard,
31+
textMode,
32+
}: IProps) => {
33+
const available = Number(item.available_int);
34+
const [enabled, setEnabled] = useState(false);
35+
const { theme } = useTheme();
36+
37+
const onChange = (checked: boolean) => {
38+
setEnabled(checked);
39+
switchChunk(available === 0 ? 1 : 0, [item.chunk_id]);
40+
};
41+
42+
const handleCheck: CheckboxProps['onChange'] = (e) => {
43+
handleCheckboxClick(item.chunk_id, e.target.checked);
44+
};
45+
46+
const handleContentDoubleClick = () => {
47+
editChunk(item.chunk_id);
48+
};
49+
50+
const handleContentClick = () => {
51+
clickChunkCard(item.chunk_id);
52+
};
53+
54+
useEffect(() => {
55+
setEnabled(available === 1);
56+
}, [available]);
57+
58+
return (
59+
<Card
60+
className={classNames(styles.chunkCard, {
61+
[`${theme === 'dark' ? styles.cardSelectedDark : styles.cardSelected}`]:
62+
selected,
63+
})}
64+
>
65+
<Flex gap={'middle'} justify={'space-between'}>
66+
<Checkbox onChange={handleCheck} checked={checked}></Checkbox>
67+
{item.image_id && (
68+
<Popover
69+
placement="right"
70+
content={
71+
<Image id={item.image_id} className={styles.imagePreview}></Image>
72+
}
73+
>
74+
<Image id={item.image_id} className={styles.image}></Image>
75+
</Popover>
76+
)}
77+
78+
<section
79+
onDoubleClick={handleContentDoubleClick}
80+
onClick={handleContentClick}
81+
className={styles.content}
82+
>
83+
<div
84+
dangerouslySetInnerHTML={{
85+
__html: DOMPurify.sanitize(item.content_with_weight),
86+
}}
87+
className={classNames(styles.contentText, {
88+
[styles.contentEllipsis]: textMode === ChunkTextMode.Ellipse,
89+
})}
90+
></div>
91+
</section>
92+
93+
<div>
94+
<Switch checked={enabled} onChange={onChange} />
95+
</div>
96+
</Flex>
97+
</Card>
98+
);
99+
};
100+
101+
export default ChunkCard;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
import EditTag from '@/components/edit-tag';
2+
import { useFetchChunk } from '@/hooks/chunk-hooks';
3+
import { IModalProps } from '@/interfaces/common';
4+
import { IChunk } from '@/interfaces/database/knowledge';
5+
import { DeleteOutlined } from '@ant-design/icons';
6+
import { Divider, Form, Input, Modal, Space, Switch } from 'antd';
7+
import React, { useCallback, useEffect, useState } from 'react';
8+
import { useTranslation } from 'react-i18next';
9+
import { useDeleteChunkByIds } from '../../hooks';
10+
import {
11+
transformTagFeaturesArrayToObject,
12+
transformTagFeaturesObjectToArray,
13+
} from '../../utils';
14+
import { TagFeatureItem } from './tag-feature-item';
15+
16+
type FieldType = Pick<
17+
IChunk,
18+
'content_with_weight' | 'tag_kwd' | 'question_kwd' | 'important_kwd'
19+
>;
20+
21+
interface kFProps {
22+
doc_id: string;
23+
chunkId: string | undefined;
24+
parserId: string;
25+
}
26+
27+
const ChunkCreatingModal: React.FC<IModalProps<any> & kFProps> = ({
28+
doc_id,
29+
chunkId,
30+
hideModal,
31+
onOk,
32+
loading,
33+
parserId,
34+
}) => {
35+
const [form] = Form.useForm();
36+
const [checked, setChecked] = useState(false);
37+
const { removeChunk } = useDeleteChunkByIds();
38+
const { data } = useFetchChunk(chunkId);
39+
const { t } = useTranslation();
40+
41+
const isTagParser = parserId === 'tag';
42+
43+
const handleOk = useCallback(async () => {
44+
try {
45+
const values = await form.validateFields();
46+
console.log('🚀 ~ handleOk ~ values:', values);
47+
48+
onOk?.({
49+
...values,
50+
tag_feas: transformTagFeaturesArrayToObject(values.tag_feas),
51+
available_int: checked ? 1 : 0, // available_int
52+
});
53+
} catch (errorInfo) {
54+
console.log('Failed:', errorInfo);
55+
}
56+
}, [checked, form, onOk]);
57+
58+
const handleRemove = useCallback(() => {
59+
if (chunkId) {
60+
return removeChunk([chunkId], doc_id);
61+
}
62+
}, [chunkId, doc_id, removeChunk]);
63+
64+
const handleCheck = useCallback(() => {
65+
setChecked(!checked);
66+
}, [checked]);
67+
68+
useEffect(() => {
69+
if (data?.code === 0) {
70+
const { available_int, tag_feas } = data.data;
71+
form.setFieldsValue({
72+
...(data.data || {}),
73+
tag_feas: transformTagFeaturesObjectToArray(tag_feas),
74+
});
75+
76+
setChecked(available_int !== 0);
77+
}
78+
}, [data, form, chunkId]);
79+
80+
return (
81+
<Modal
82+
title={`${chunkId ? t('common.edit') : t('common.create')} ${t('chunk.chunk')}`}
83+
open={true}
84+
onOk={handleOk}
85+
onCancel={hideModal}
86+
okButtonProps={{ loading }}
87+
destroyOnClose
88+
>
89+
<Form form={form} autoComplete="off" layout={'vertical'}>
90+
<Form.Item<FieldType>
91+
label={t('chunk.chunk')}
92+
name="content_with_weight"
93+
rules={[{ required: true, message: t('chunk.chunkMessage') }]}
94+
>
95+
<Input.TextArea autoSize={{ minRows: 4, maxRows: 10 }} />
96+
</Form.Item>
97+
98+
<Form.Item<FieldType> label={t('chunk.keyword')} name="important_kwd">
99+
<EditTag></EditTag>
100+
</Form.Item>
101+
<Form.Item<FieldType>
102+
label={t('chunk.question')}
103+
name="question_kwd"
104+
tooltip={t('chunk.questionTip')}
105+
>
106+
<EditTag></EditTag>
107+
</Form.Item>
108+
{isTagParser && (
109+
<Form.Item<FieldType>
110+
label={t('knowledgeConfiguration.tagName')}
111+
name="tag_kwd"
112+
>
113+
<EditTag></EditTag>
114+
</Form.Item>
115+
)}
116+
117+
{!isTagParser && <TagFeatureItem></TagFeatureItem>}
118+
</Form>
119+
120+
{chunkId && (
121+
<section>
122+
<Divider></Divider>
123+
<Space size={'large'}>
124+
<Switch
125+
checkedChildren={t('chunk.enabled')}
126+
unCheckedChildren={t('chunk.disabled')}
127+
onChange={handleCheck}
128+
checked={checked}
129+
/>
130+
131+
<span onClick={handleRemove}>
132+
<DeleteOutlined /> {t('common.delete')}
133+
</span>
134+
</Space>
135+
</section>
136+
)}
137+
</Modal>
138+
);
139+
};
140+
export default ChunkCreatingModal;

0 commit comments

Comments
 (0)