chore: replace all cn comments of fe to en version by volc api (#320)

This commit is contained in:
tecvan
2025-07-31 10:32:15 +08:00
committed by GitHub
parent 716ec0cba8
commit 71f6245a01
2960 changed files with 15545 additions and 15545 deletions

View File

@@ -42,7 +42,7 @@ const options = {
`//lf-cdn.coze.cn/obj/unpkg/pdfjs-dist/${pdfjs.version}/cmaps/`
: // cp-disable-next-line
`//sf-cdn.coze.com/obj/unpkg-va/pdfjs-dist/${pdfjs.version}/cmaps/`,
// 提升性能
// Boost performance
cMapPacked: true,
};

View File

@@ -43,61 +43,61 @@ import styles from './common-file-picker.module.less';
export interface CommonFilePickerProps
extends Omit<TreeProps, 'onChange' | 'onSelect'> {
/** 渲染使用的树数据 */
/** Tree data used for rendering */
treeData: FileNode[];
/** 提供一个定制化的 render tree node */
/** Provide a customized render tree node */
customTreeDataRenderer?: (
renderProps: RenderFullLabelProps,
) => React.ReactNode;
/** 是否只能选中叶子结点 如果传入 customRenderTreeData 则失效 */
/** Whether only leaf nodes can be selected, invalid if customRenderTreeData is passed in */
onlySelectLeaf?: boolean;
/** 是否多选 如果自定义 customTreeDataRenderer 一定要传入, 选项会影响 customTreeDataRenderer 的入参 */
/** Whether to multi-select, if the custom customTreeDataRenderer must be passed in, the option will affect customTreeDataRenderer imported parameter */
multiple?: boolean;
/**
* 是否开启虚拟化
* Whether to enable virtualization
*/
enableVirtualize?: boolean;
/** 虚拟化选项 */
/** 虚拟化容器高度 */
/** virtualization options */
/** virtualized container height */
virtualizeHeight?: number;
/** 每个 item 高度 */
/** Height of each item */
virtualizeItemSize?: number;
/** 默认已经选中的内容 可以作为 initValue 使用,也可以作为 value 的代替者使用 */
/** The content already selected by default can be used as initValue or as a substitute for value */
defaultValue?: FileNode[] | FileId[];
/** 样式渲染特性 */
/** style rendering feature */
normalLabelStyle?: React.CSSProperties;
selectedLabelStyle?: React.CSSProperties;
halfSelectedLabelStyle?: React.CSSProperties;
/** 缩进大小 默认大小 25px 如果 backgroundMode position 将会反应为 left 如果为 padding 将会反应成 padding-left */
/** Indent size, default size 25px If backgroundMode is position, it will react to left If it is padding, it will react to padding-left. */
indentSize?: number;
/** 树组件展开的 icon */
/** Tree component expansion icon */
expandIcon?: React.ReactNode;
/** onChange 业务层可以透传 */
/** onChange business layer can be passed through */
onChange?: (args?: FileNode[]) => void;
/** onSelect 业务层可以透传 */
/** onSelect business layer can pass through */
onSelect?: (key: string, selected: boolean, node: FileNode) => void;
/** 用来转换 selectedFiles, 发生在 设置选中态 到 提交给上层组件 之间 注意 处理有先后顺序,前一个中间件的返回将作为后一个的输入 */
/** Used to convert selectedFiles, occurs in, sets the selected state, to submit to the upper component, between, note that there is a sequence of processing, the return of the previous middleware will be used as the input of the latter */
transSelectedFilesMiddlewares?: TransSelectedFilesMiddleware[];
/** 设置选择态的钩子 发生在 点击选中框 到 设置选择态 之间 处理有先后顺序 */
/** The hook for setting the selection state occurs between clicking the check box and setting the selection state, and the processing is in sequence */
selectFilesMiddlewares?: CalcCurrentSelectFilesMiddleware[];
/** disable select 禁止选择 */
/** Disable select disable select */
disableSelect?: boolean;
/** checkRelation: 父子节点选中态是否关联 */
/** checkRelation: Whether the selected state of the parent and child nodes is related */
checkRelation?: 'related' | 'unRelated';
/** 默认展开的节点 key */
/** Default expanded node key */
defaultExpandKeys?: FileId[];
}
@@ -145,7 +145,7 @@ function transDefaultValueToFileNodes(
const treeDataMap = levelMapTreeNodesToMap(treeData);
return (
defaultValue?.map(element => {
// 因为开了 onChangeWithObject 所以这里选中态要用 object 存储
// Because onChangeWithObject is opened, the selected state here should be stored with object.
if (typeof element === 'string') {
return (
treeDataMap.get(element) ?? {
@@ -161,7 +161,7 @@ function transDefaultValueToFileNodes(
function transDefaultValueToRenderNode(defaultValue?: FileId[] | FileNode[]) {
return (
defaultValue?.map(element => {
// 因为开了 onChangeWithObject 所以这里选中态要用 object 存储
// Because onChangeWithObject is opened, the selected state here should be stored with object.
if (typeof element === 'string') {
return {
key: element,
@@ -175,10 +175,10 @@ function transDefaultValueToRenderNode(defaultValue?: FileId[] | FileNode[]) {
/**
* ------------------
* common file picker
* 用于数据上传选择文件
* Select file for data upload
* ------------------
* useImperativeHandle:
* search: 提供树搜索能力
* Search: Provides tree search capability
* ------------------
* props: FilePickerProps
* ------------------
@@ -205,7 +205,7 @@ export const CommonFilePicker = React.forwardRef(
} = props;
const treeRef = useRef<Tree>(null);
// 使用受控模式
// Use controlled mode
const [selectValue, setSelectValue] = useState<FileNode[]>(
transDefaultValueToRenderNode(defaultValue),
);
@@ -287,13 +287,13 @@ export const CommonFilePicker = React.forwardRef(
transedChangeNodes = [changeNodes as unknown as FileNode];
}
// 计算 diff
// Calculate diff
const [addNodes, removeNodes, retainNodes] = diffChangeNodes(
prevChangeNodes.current,
transedChangeNodes as FileNode[],
);
// 这里的中间件更多用在定制化选中态的场景 比如想要反选所有子节点但是保持父亲节点选中
// The middleware here is more used in scenarios where the selected state is customized, such as wanting to unselect all sub-nodes but keep the parent node selected
transedChangeNodes = distinctFileNodes(
selectFilesMiddlewares.reduce(
(selectedElements, middleware) =>
@@ -313,10 +313,10 @@ export const CommonFilePicker = React.forwardRef(
key: transedNode.key,
})),
);
// 虽然这里返回的是父节点带 children 但是因为都是后端一次接口的快照
// 具体上报什么数据交给业务方
// 这里的中间件主要用在定制化上报给上层组件的选中数据的场景,比如 checkRelation 'related' 模式下 上面返回的只有父亲节点的数据,但是父组件想要所有数据
// 警告:这里如果使用 loadData 时拿不到没请求的子节点(换句话说拿到的最后一层的数据不一定是叶子结点, 同样的在这里选中之后交回给后端的其实也只是一个父节点 不能保证在一个快照里
// Although the parent node with children is returned here, because they are all snapshots of the backend interface
// What data to report to the business party?
// The middleware here is mainly used in scenarios where the selected data is reported to the upper component, such as checkRelation'related 'mode, where only the data of the parent node is returned, but the parent component wants all the data
// Warning: If you can't get the unrequested sub-node when using loadData here (in other words, the last layer of data you get is not necessarily a leaf node), the same is true here. After selecting it, it is only a parent node, and it cannot be guaranteed to be in a snapshot.
if (transSelectedFilesMiddlewares) {
transedChangeNodes = transSelectedFilesMiddlewares.reduce(
(selectedElements, middleware) => middleware(selectedElements),

View File

@@ -14,9 +14,9 @@
* limitations under the License.
*/
// 缩进相关数据
// Indent related data
export const DEFAULT_FILENODE_LEVEL_INDENT = 24;
// 虚拟化配置相关数据
// Virtualization configuration related data
export const DEFAULT_VIRTUAL_CONTAINER_HEIGHT = 540;
export const DEFAULT_VIRTUAL_ITEM_HEIGHT = 28;

View File

@@ -80,7 +80,7 @@ const ActionComponent = (props: {
<span className="action-placeholder file-selector"></span>
);
// 当前整棵树是多选 并且 只能选中叶子结点
// At present, the entire tree is multi-selected, and only leaf nodes can be selected
if (multiple && onlySelectLeaf) {
return isLeaf && !unCheckable ? (
<>
@@ -94,7 +94,7 @@ const ActionComponent = (props: {
);
}
// 当前整棵树是多选 并且 能选中所有结点
// The current entire tree is multi-selected, and all nodes can be selected
if (multiple && !onlySelectLeaf) {
if (unCheckable) {
return (
@@ -111,7 +111,7 @@ const ActionComponent = (props: {
);
}
// 当前整棵树是单选 并且 只能选中叶子结点
// The current entire tree is radio-selected, and only leaf nodes can be selected
if (!multiple && onlySelectLeaf) {
return isLeaf && !unCheckable ? (
<>
@@ -126,7 +126,7 @@ const ActionComponent = (props: {
);
}
// 当前整棵树是单选 并且 能选中所有结点
// The current entire tree is radio-selected, and all nodes can be selected
if (!multiple && !onlySelectLeaf) {
if (unCheckable) {
return (
@@ -195,12 +195,12 @@ const LabelContent = (props: {
/**
* -----------------------------
* 获取默认的文件树 label renderer 这层不感知平台信息
* Get the default file tree label renderer layer that is not platform aware
* -----------------------------
* @param {boolean} multiple 是否多选
* @param {boolean} onlySelectLeaf 是否只能选中叶子结点
* @param {{indentSize: 树组件缩进尺寸, expandIcon: 树组件可展开节点 展开图标, disableSelect: 选择的 disable 状态}} renderOption 渲染相关的自定义选项
* @returns label render 函数
* @param {boolean} multiple or not
* @param {boolean} onlySelectLeaf Whether only leaf nodes can be selected
* @param {{indentSize: tree component indent size, expandIcon: tree component expandable node, expand icon, disableSelect: selected disabled state}} renderOption Render-related customization options
* @Returns label rendering function
*/
export function useDefaultLabelRenderer(
multiple: boolean,
@@ -243,10 +243,10 @@ export function useDefaultLabelRenderer(
}`;
/**
* 在整行点击的处理函数 不是点击 checkbox 或者 radio 或者 expandIcon 的处理函数
* @param isLeaf: 是否是叶子结点
* @param onExpand: 展开行 处理函数
* @param onCheck: 选中状态的 toggle
* The handler that clicks on the entire line, not the handler that clicks on checkbox or radio or expandIcon
* @Param isLeaf: whether it is a leaf node
* @Param onExpand: expand the line, handle function
* @param onCheck: toggle in selected state
**/
const getItemAction = (params: {
isLeaf: boolean;
@@ -256,8 +256,8 @@ export function useDefaultLabelRenderer(
}) => {
const { onExpand, onCheck, isLeaf, unCheckable } = params;
return function (e: React.MouseEvent<Element, MouseEvent>) {
// 如果只能选中叶子结点 那么无论 多选 / 单选 父节点只能展开,叶子结点可以选中
// 反之 父节点子节点 都是选中 无论多选单选,想要展开就点击 expand icon
// If only the leaf node can be selected, then no matter whether it is multi-select/single-select, the parent node can only be expanded, and the leaf node can be selected
// On the contrary, the parent node sub-node is selected, regardless of the multi-select radio, if you want to expand, click the expand icon.
if (onlySelectLeaf) {
if (!isLeaf) {
onExpand(e);
@@ -301,14 +301,14 @@ export function useDefaultLabelRenderer(
readonly,
unCheckable = false,
} = data;
// 单选选中选项的 key
// Radio select the key of the selected option
const singleSelectCheckStatus = singleSelectedKey === key;
const rowCheckStatus = multiple
? checkStatus
: {
checked: singleSelectCheckStatus,
};
// 只要 data isLeaf 不是空 永远先看 data.isLeaf
// As long as data isLeaf is not empty, always look at data.isLeaf first
const isLeaf = data?.isLeaf ?? !(data.children && data.children.length);
const checkItem = multiple
? (e: React.MouseEvent<Element, MouseEvent>) => {

View File

@@ -30,53 +30,53 @@ export interface PickerRef {
}
/**
* 文件选择树节点
* file selection tree node
*/
export interface FileNode extends TreeNodeData {
/** 独一无二的 key 标识 可以用 文件 id */
/** Unique key identifier, can be used, file id */
key: string;
value?: string;
label?: React.ReactNode;
type?: TreeNodeType;
// icon 的 URL
// URL of the icon
icon?: string;
children?: FileNode[];
/** 标识当前节点是不是叶子结点 loadData 时必备 */
/** Required when identifying whether the current node is a leaf node loadData */
isLeaf?: boolean;
/** 该节点是否可以选中 */
/** Can the node be selected? */
selectable?: boolean;
/** 节点的 loading 状态,开启后 loading 默认替换 icon展示 loadingInfo
* 注意这个和 semi 本身带的 loading 不一样semi 的 loading 指的是 展开的 loading 状态 */
/** The loading status of the node, after opening, the loading default replaces the icon, and displays the loadingInfo.
* Note that this is different from the loading of the semi itself. The loading of the semi refers to the unfolded loading state. */
isLoading?: boolean;
/** 节点 loading 的提示,默认是 `获取中` */
/** Node loading prompt, the default is "getting" */
loadingInfo?: string;
/** 具体的文档类型 比如 doc docx txt */
/** Specific document types, such as doc docx txt, etc */
file_type?: string;
/** 三方文档链接 */
/** Three-way document link */
file_url?: string;
/** 【飞书场景】wiki 空间id,*/
/** [Feishu scene] wiki space id,*/
space_id?: string;
/** 【飞书场景】wiki 叶子id,*/
/** [Feishu scene] wiki leaf id,*/
obj_token?: string;
/** 自定义渲染 Item */
/** Custom Rendering Items */
render?: () => ReactNode;
/** 只读,不可交互 */
/** Read-only, not interactive */
readonly?: boolean;
/** 节点是否不可选择,默认为 false */
/** Whether the node is not selectable, the default is false */
unCheckable?: boolean;
}
export type FileId = string;
/**
* 文件选择树 节点选择状态
* File selection tree, node selection status
*/
export interface FileSelectCheckStatus {
checked: boolean;
halfChecked: boolean;
}
// 三部分 当前选中的 新增选中的 较上次不选中的 较上次不变的
// Three parts, currently selected, newly selected, unselected from last time, unchanged from last time
export type TransSelectedFilesMiddleware = (
fileNodes: FileNode[],
) => FileNode[];
@@ -88,12 +88,12 @@ export type CalcCurrentSelectFilesMiddleware = (
retainNodes?: FileNode[],
) => FileNode[];
/** 类型断言 节点是不是 fileNode */
/** Type assertion, node is not fileNode */
export function isFileNode(fileNode: unknown): fileNode is FileNode {
return !!fileNode && isObject(fileNode) && !!(fileNode as FileNode).key;
}
/** 类型断言 数组是不是 fileNode 数组 */
/** Type assertion, array is not a fileNode array */
export function isFileNodeArray(fileNodes: unknown[]): fileNodes is FileNode[] {
return fileNodes.every(fileNode => isFileNode(fileNode));
}

View File

@@ -74,7 +74,7 @@ const SegmentMenu: React.FC<ISegmentMenuProps> = props => {
) : null}
<div className="pl-2 h-6 mt-4 mb-1 flex items-center">
<div className="coz-fg-secondary text-[12px] font-[400] leading-4 shrink-0">
{/**文档列表 */}
{/**document list */}
{I18n.t('knowledge_level_012')}
</div>
</div>
@@ -114,7 +114,7 @@ const SegmentMenu: React.FC<ISegmentMenuProps> = props => {
<div className="flex flex-col gap-1 !overflow-auto">
<div className="w-full pl-2 h-6 items-center flex gap-[4px]">
<div className="coz-fg-secondary text-[12px] font-[400] leading-4 shrink-0">
{/**分段层级 */}
{/**segment hierarchy */}
{I18n.t('knowledge_level_adjust')}
</div>
{treeDisabled ? null : (

View File

@@ -48,10 +48,10 @@ export const SegmentTree: React.FC<ISegmentTreeProps> = ({
disabled,
}) => {
/**
* 选中功能
* select function
*/
const [selected, setSelected] = useState(new Set<string>());
// 分片 id
// Sharding id
const [selectedThroughParent, setSelectedThroughParent] = useState(
new Set<string>(),
);

View File

@@ -114,8 +114,8 @@ export function useSegmentContextMenu({
onContextMenu: (e, node: NodeApi<LevelDocumentTree>) => {
e.preventDefault();
setTreeNode(node);
/** project ide 里面ide 容器设置了 contain: strict, 会导致 fixed position
* 的偏移基础不对,所以这里需要减去 ide 容器的 left top
/** In the project ide, the ide container is set to contain: strict, which will cause a fixed position.
* The base of the offset is wrong, so you need to subtract the left and top values of the ide container here
*/
let clickX = e.pageX;
let clickY = e.pageY;

View File

@@ -140,7 +140,7 @@ export const handleTreeNodeMove = (
};
}
// 如果是同一个 parent且拖动的位置在当前位置之前dropIndex 减 1
// If it is the same parent and the dragged position is before the current position, the dropIndex is reduced by 1.
const originalIndex = parentSegment.children.indexOf(dragSegment.id);
const dropIndex =
originalIndex < positions.dropIndex &&
@@ -224,7 +224,7 @@ export const handleMergeNodes = (
};
}
// 从原父节点的 children 中移除该节点
// Remove the node from the children of the original parent
const parentSegment = resSegments.find(
item => item.id === segmentToMerge.parent,
);
@@ -235,7 +235,7 @@ export const handleMergeNodes = (
}
if (!['table', 'image', 'title'].includes(segmentToMerge?.type ?? '')) {
// 合并文本内容并删除节点
// Merge text content and delete nodes
mergedSegment.text += segmentToMerge.text;
const index = resSegments.findIndex(
item => item.id === segmentToMerge.id,
@@ -244,7 +244,7 @@ export const handleMergeNodes = (
resSegments.splice(index, 1);
}
} else {
// 非section-text类型的节点将其移动到合并后节点的children中
// Nodes of type non-section-text, move them to the children of the merged node
segmentToMerge.parent = mergedSegment.id;
mergedSegment.children.push(segmentToMerge.id);
}

View File

@@ -33,33 +33,33 @@ export const DocumentChunkPreview = ({
<div
id={locateId}
className={classNames(
// 布局
// layout
'relative',
// 间距
// spacing
'mb-2 p-2',
// 文字样式
// Text Style
'text-sm leading-5',
// 颜色
// color
'coz-fg-primary hover:coz-mg-hglt-secondary-hovered coz-mg-secondary',
// 边框
// border
'border border-solid coz-stroke-primary rounded-lg',
// 表格样式
// table style
getEditorTableClassname(),
// 图片样式
// image style
getEditorImgClassname(),
// 换行
// line feed
getEditorWordsCls(),
)}
>
<p
// 已使用 DOMPurify 过滤 xss
// Filtered xss with DOMPurify
// eslint-disable-next-line risxss/catch-potential-xss-react
dangerouslySetInnerHTML={{
__html:
DOMPurify.sanitize(getRenderHtmlContent(chunk.content ?? ''), {
/**
* 1. 防止CSS注入攻击
* 2. 防止用户误写入style标签导致全局样式被修改页面展示异常
* 1. Prevent CSS injection attacks
* 2. Prevent users from writing the style tag by mistake, resulting in the global style being modified and the page display being abnormal
*/
FORBID_TAGS: ['style'],
}) ?? '',

View File

@@ -21,16 +21,16 @@ import type { Emitter, Handler, EventType } from 'mitt';
import { type Chunk } from '../types/chunk';
// 定义事件名称字面量类型
// Define event name literal type
export type EventTypeName =
| 'previewContextMenuItemAction'
| 'hoverEditBarAction';
/**
* 事件类型定义
* event type definition
*/
export interface EventTypes extends Record<EventType, unknown> {
// 右键菜单相关事件
// right-click menu related events
previewContextMenuItemAction: {
type: 'add-after' | 'add-before' | 'delete' | 'edit';
targetChunk: Chunk;
@@ -38,7 +38,7 @@ export interface EventTypes extends Record<EventType, unknown> {
chunks?: Chunk[];
};
// 悬浮编辑栏相关事件
// Floating edit bar related events
hoverEditBarAction: {
type: 'add-after' | 'add-before' | 'delete' | 'edit';
targetChunk: Chunk;
@@ -48,32 +48,32 @@ export interface EventTypes extends Record<EventType, unknown> {
}
/**
* 事件处理函数类型
* event handler type
*/
export type EventHandler<T extends EventTypeName> = Handler<EventTypes[T]>;
/**
* 创建事件总线实例
* Create an event bus instance
*/
export const createEventBus = (): Emitter<EventTypes> => mitt<EventTypes>();
/**
* 全局事件总线实例
* Global Event Bus instance
*/
export const eventBus = createEventBus();
/**
* 事件总线钩子
* 用于在组件中使用事件总线
* event bus hook
* Used to use the event bus in components
*/
export const useEventBus = () => eventBus;
/**
* 监听事件钩子
* 用于在组件中监听事件
* @param eventName 事件名称
* @param handler 事件处理函数
* @param deps 依赖数组,当依赖变化时重新绑定事件
* listen event hook
* Used to listen for events in a component
* @param eventName
* @param handler event handler
* @Param deps dependency arrays, rebind events when dependencies change
*/
export const useEventListener = <T extends EventTypeName>(
eventName: T,
@@ -81,10 +81,10 @@ export const useEventListener = <T extends EventTypeName>(
deps: React.DependencyList = [],
) => {
useEffect(() => {
// 绑定事件
// binding event
eventBus.on(eventName, handler as Handler<unknown>);
// 组件卸载时解绑事件
// Unbind event when component is unmounted
return () => {
eventBus.off(eventName, handler as Handler<unknown>);
};

View File

@@ -37,7 +37,7 @@ export const BaseUploadImage = ({
showTooltip,
renderUI,
}: BaseUploadImageProps) => {
// 处理图片上传
// Handle image upload
const handleImageUpload = (object: customRequestArgs) => {
if (!editor) {
return;
@@ -53,7 +53,7 @@ export const BaseUploadImage = ({
options: {
onFinish: (result: { url?: string; tosKey?: string }) => {
if (result.url && editor) {
// 插入图片到编辑器
// Insert pictures into the editor
editor.chain().focus().setImage({ src: result.url }).run();
}
},

View File

@@ -79,7 +79,7 @@ export const handleCustomUploadRequest = async ({
}
try {
// 业务逻辑
// business logic
onBeforeUpload?.();
const { name, fileInstance } = file;

View File

@@ -49,14 +49,14 @@ export const DocumentEditor: React.FC<DocumentEditorProps> = props => {
const contextMenuRef = useRef<HTMLDivElement>(null);
/**
* 当右键点击编辑器时,显示上下文菜单
* When right-clicking on the editor, the context menu is displayed
*/
const { contextMenuPosition, openContextMenu } = useControlContextMenu({
contextMenuRef,
});
/**
* 当点击编辑器外部时
* When clicking outside the editor
*/
useOutEditorMode({
editorRef,
@@ -76,26 +76,26 @@ export const DocumentEditor: React.FC<DocumentEditorProps> = props => {
<div
ref={editorRef}
className={classNames(
// 布局
// layout
'relative',
// 间距
// spacing
'mb-2 p-2',
// 文字样式
// Text Style
'text-sm leading-5',
// 颜色
// color
'coz-fg-primary coz-bg-max',
// 边框
// border
'border border-solid coz-stroke-hglt rounded-lg',
)}
onContextMenu={openContextMenu}
>
<div
className={classNames(
// 表格样式
// table style
getEditorTableClassname(),
// 图片样式
// image style
getEditorImgClassname(),
// 换行
// line feed
getEditorWordsCls(),
)}
>
@@ -104,7 +104,7 @@ export const DocumentEditor: React.FC<DocumentEditorProps> = props => {
</div>
</div>
{/* 右键菜单 */}
{/* right-click menu */}
{contextMenuPosition && editorContextMenuItemsRegistry ? (
<EditorContextMenu
x={contextMenuPosition.x}

View File

@@ -31,7 +31,7 @@ export const AddAfterAction: React.FC<HoverEditBarActionProps> = ({
chunks,
disabled,
}) => {
// 在特定分片后添加新分片
// Add new shardings after specific shardings
const { addEmptyChunkAfter } = useAddEmptyChunkAction({
chunks: chunks || [],
onChunksChange: ({ newChunk, chunks: newChunks }) => {

View File

@@ -27,14 +27,14 @@ import { eventBus } from '@/text-knowledge-editor/event';
import { type HoverEditBarActionProps } from './module';
/**
* 在特定分片前添加新分片的操作组件
* Add the action component of a new sharding before a specific sharding
*/
export const AddBeforeAction: React.FC<HoverEditBarActionProps> = ({
chunk,
chunks = [],
disabled,
}) => {
// 在特定分片前添加新分片
// Add new shardings before specific shardings
const { addEmptyChunkBefore } = useAddEmptyChunkAction({
chunks,
onChunksChange: ({ newChunk, chunks: newChunks }) => {

View File

@@ -26,19 +26,19 @@ import { eventBus } from '@/text-knowledge-editor/event';
import { type HoverEditBarActionProps } from './module';
/**
* 删除特定分片的操作组件
* Remove the action component for specific shardings
*
* 内部实现了删除特定分片的逻辑
* 如果传入了 onDelete 回调,则会在点击时调用
* 如果提供了 chunksonChunksChange,则会在内部处理删除逻辑,
* 无需依赖外部的 usePreviewContextMenu
* The logic to remove specific shardings is implemented internally
* If an onDelete callback is passed, it will be called on click
* If chunks, onChunksChange are provided, the deletion logic is handled internally.
* No need to rely on external usePreviewContextMenu
*/
export const DeleteAction: React.FC<HoverEditBarActionProps> = ({
chunk,
chunks = [],
disabled,
}) => {
// 删除特定分片
// Remove specific shardings
const { deleteChunk } = useDeleteAction({
chunks,
onChunksChange: ({ chunks: newChunks }) => {

View File

@@ -26,10 +26,10 @@ import { eventBus } from '@/text-knowledge-editor/event';
import { type HoverEditBarActionProps } from './module';
/**
* 编辑操作组件
* Edit action component
*
* 内部实现了激活特定分片的编辑模式的逻辑
* 如果传入了 onEdit 回调,则会在点击时调用
* The logic to activate the edit mode for specific shardings is implemented internally
* If an onEdit callback is passed, it will be called on click
*/
export const EditAction: React.FC<HoverEditBarActionProps> = ({
chunk,

View File

@@ -27,7 +27,7 @@ import { eventBus } from '@/text-knowledge-editor/event';
import { type PreviewContextMenuItemProps } from './module';
/**
* 在特定分片后添加新分片的菜单项组件
* Add a new sharding's menu item component after a specific sharding
*/
export const AddAfterAction: React.FC<PreviewContextMenuItemProps> = ({
chunk,
@@ -44,11 +44,11 @@ export const AddAfterAction: React.FC<PreviewContextMenuItemProps> = ({
'cursor-not-allowed': isDisabled,
});
// 在特定分片后添加新分片
// Add new shardings after specific shardings
const { addEmptyChunkAfter } = useAddEmptyChunkAction({
chunks,
onChunksChange: ({ newChunk, chunks: newChunks }) => {
// 发出在特定分片后添加新分片的事件
// Issue an event to add a new sharding after a specific sharding
eventBus.emit('previewContextMenuItemAction', {
type: 'add-after',
newChunk,

View File

@@ -27,7 +27,7 @@ import { eventBus } from '@/text-knowledge-editor/event';
import { type PreviewContextMenuItemProps } from './module';
/**
* 在特定分片前添加新分片的菜单项组件
* Add a new sharding's menu item component before a specific sharding
*/
export const AddBeforeAction: React.FC<PreviewContextMenuItemProps> = ({
chunk,
@@ -44,7 +44,7 @@ export const AddBeforeAction: React.FC<PreviewContextMenuItemProps> = ({
'cursor-not-allowed': isDisabled,
});
// 在特定分片前添加新分片
// Add new shardings before specific shardings
const { addEmptyChunkBefore } = useAddEmptyChunkAction({
chunks,
onChunksChange: ({ newChunk, chunks: newChunks }) => {

View File

@@ -27,7 +27,7 @@ import { eventBus } from '@/text-knowledge-editor/event';
import { type PreviewContextMenuItemProps } from './module';
/**
* 删除特定分片的菜单项组件
* Remove a specific sharding menu item component
*/
export const DeleteAction: React.FC<PreviewContextMenuItemProps> = ({
chunk,
@@ -44,7 +44,7 @@ export const DeleteAction: React.FC<PreviewContextMenuItemProps> = ({
'cursor-not-allowed': isDisabled,
});
// 删除特定分片
// Remove specific shardings
const { deleteChunk } = useDeleteAction({
chunks,
onChunksChange: ({ chunks: newChunks }) => {

View File

@@ -26,10 +26,10 @@ import { eventBus } from '@/text-knowledge-editor/event';
import { type PreviewContextMenuItemProps } from './module';
/**
* 编辑操作菜单项组件
* Edit Action Menu Item Component
*
* 内部实现了激活特定分片的编辑模式的逻辑
* 如果传入了 onEdit 回调,则会在点击时调用
* The logic to activate the edit mode for specific shardings is implemented internally
* If an onEdit callback is passed, it will be called on click
*/
export const EditAction: React.FC<PreviewContextMenuItemProps> = ({
chunk,

View File

@@ -58,7 +58,7 @@ const DocumentPreviewComponent: React.FC<DocumentPreviewProps> = props => {
<div className="relative">
<div
className={classNames(
// 布局
// layout
'relative overflow-hidden',
)}
onContextMenu={readonly ? undefined : e => openContextMenu(e)}
@@ -70,7 +70,7 @@ const DocumentPreviewComponent: React.FC<DocumentPreviewProps> = props => {
onMouseLeave={readonly ? undefined : handleMouseLeave}
onDoubleClick={readonly ? undefined : () => onActivateEditMode?.(chunk)}
>
{/* 悬停时显示的操作栏 */}
{/* The action bar displayed when hovering */}
{hoveredChunk === chunk.text_knowledge_editor_chunk_uuid &&
!readonly ? (
<HoverEditBar
@@ -83,7 +83,7 @@ const DocumentPreviewComponent: React.FC<DocumentPreviewProps> = props => {
<DocumentChunkPreview chunk={chunk} locateId={locateId || ''} />
</div>
{/* 右键菜单 */}
{/* right-click menu */}
{contextMenuPosition ? (
<PreviewContextMenu
previewContextMenuItemsRegistry={previewContextMenuItemsRegistry}
@@ -99,16 +99,16 @@ const DocumentPreviewComponent: React.FC<DocumentPreviewProps> = props => {
);
};
// 使用React.memo包装组件避免不必要的重新渲染
// Wrap components with React.memo to avoid unnecessary re-rendering
export const DocumentPreview = React.memo(
DocumentPreviewComponent,
(prevProps, nextProps) => {
// 如果分片内容变化,需要重新渲染
// If the sharding content changes, it needs to be re-rendered
if (prevProps.chunk.content !== nextProps.chunk.content) {
return false;
}
// 其他情况下不需要重新渲染
// In other cases, no re-rendering is required
return true;
},
);

View File

@@ -28,11 +28,11 @@ export const useControlContextMenu = ({
y: number;
} | null>(null);
// 处理右键菜单
// Handle right-click menus
const openContextMenu = (e: React.MouseEvent) => {
e.preventDefault();
// 计算相对于事件目标元素的位置
// Calculate the position relative to the event target element
const rect = e.currentTarget.getBoundingClientRect();
const relativeX = e.clientX - rect.left;
const relativeY = e.clientY - rect.top;
@@ -43,15 +43,15 @@ export const useControlContextMenu = ({
});
};
// 关闭右键菜单
// Close the right-click menu
const closeContextMenu = () => {
setContextMenuPosition(null);
};
// 处理点击文档其他位置
// Process Click Document Other Locations
useEffect(() => {
const handleClickOutside = (event: MouseEvent) => {
// 如果点击的是右键菜单外部,则关闭菜单
// If you click outside the right-click menu, close the menu
if (
contextMenuRef.current &&
!contextMenuRef.current.contains(event.target as Node)

View File

@@ -28,7 +28,7 @@ export const useControlEditorContextMenu = ({
y: number;
} | null>(null);
// 处理右键菜单
// Handle right-click menus
const openContextMenu = (e: React.MouseEvent) => {
e.preventDefault();
setContextMenuPosition({
@@ -37,15 +37,15 @@ export const useControlEditorContextMenu = ({
});
};
// 关闭右键菜单
// Close the right-click menu
const closeContextMenu = () => {
setContextMenuPosition(null);
};
// 处理点击文档其他位置
// Process Click Document Other Locations
useEffect(() => {
const handleClickOutside = (event: MouseEvent) => {
// 如果点击的是右键菜单外部,则关闭菜单
// If you click outside the right-click menu, close the menu
if (
contextMenuRef.current &&
!contextMenuRef.current.contains(event.target as Node)

View File

@@ -26,7 +26,7 @@ export const useControlPreviewContextMenu = () => {
} | null>(null);
const contextMenuRef = useRef<HTMLDivElement>(null);
// 处理右键点击事件
// Handling right-click events
const openContextMenu = (e: React.MouseEvent, chunk: Chunk) => {
e.preventDefault();
setContextMenuInfo({
@@ -36,12 +36,12 @@ export const useControlPreviewContextMenu = () => {
});
};
// 关闭右键菜单
// Close the right-click menu
const closeContextMenu = () => {
setContextMenuInfo(null);
};
// 点击文档其他位置关闭右键菜单
// Click elsewhere in the document to close the right-click menu
useEffect(() => {
const handleClickOutside = (event: MouseEvent) => {
if (

View File

@@ -19,12 +19,12 @@ import { useState } from 'react';
export const useHoverEffect = () => {
const [hoveredChunk, setHoveredChunk] = useState<string | null>(null);
// 处理鼠标悬停事件
// Handling mouse hover events
const handleMouseEnter = (chunkId: string) => {
setHoveredChunk(chunkId);
};
// 处理鼠标离开事件
// Handling mouse away events
const handleMouseLeave = () => {
setHoveredChunk(null);
};

View File

@@ -27,10 +27,10 @@ export const useOutEditorMode = ({
exclude,
onExitEditMode,
}: UseOutEditorModeProps) => {
// 处理点击文档其他位置
// Process Click Document Other Locations
useEffect(() => {
const handleClickOutside = (event: MouseEvent) => {
// 如果点击的是编辑器外部,则退出编辑模式
// If you click outside the editor, exit editing mode
if (
editorRef.current &&
!editorRef.current.contains(event.target as Node) &&

View File

@@ -24,28 +24,28 @@ interface UseAddEmptyChunkActionProps {
onChunksChange?: (params: { newChunk: Chunk; chunks: Chunk[] }) => void;
}
/**
* 在特定分片后添加新分片的 hook
* Add new sharding hook after specific sharding
*
* 提供在特定分片后添加新分片的功能
* Provides the ability to add new shardings after specific shardings
*/
export const useAddEmptyChunkAction = ({
chunks,
onChunksChange,
}: UseAddEmptyChunkActionProps) => {
// 使用ref保存最新的chunks引用
// Use ref to save the latest chunks reference
const chunksRef = useRef<Chunk[]>(chunks);
// 每次props.chunks更新时,更新ref
// Every time props.chunks is updated, update the ref.
useEffect(() => {
chunksRef.current = chunks;
}, [chunks]);
/**
* 在特定分片后添加新分片
* @returns 包含新分片和更新后的分片列表的结果对象
* Add new shardings after specific shardings
* @Returns the result object containing the new sharding and the updated sharding list
*/
const handleAddEmptyChunkAfter = (chunk: Chunk) => {
// 从ref中获取最新的chunks
// Get the latest chunks from the ref
const currentChunks = chunksRef.current;
const index = currentChunks.findIndex(
c =>
@@ -79,10 +79,10 @@ export const useAddEmptyChunkAction = ({
};
/**
* 在特定分片前添加新分片
* Add new shardings before specific shardings
*/
const handleAddEmptyChunkBefore = (chunk: Chunk) => {
// 从ref中获取最新的chunks
// Get the latest chunks from the ref
const currentChunks = chunksRef.current;
const index = currentChunks.findIndex(
c =>

View File

@@ -25,29 +25,29 @@ interface UseDeleteActionProps {
}
/**
* 删除分片的 hook
* Remove sharding hook
*
* 提供删除特定分片的功能
* Provides the ability to remove specific shardings
*/
export const useDeleteAction = ({
chunks,
onChunksChange,
}: UseDeleteActionProps) => {
// 使用ref保存最新的chunks引用
// Use ref to save the latest chunks reference
const chunksRef = useRef<Chunk[]>(chunks);
const { deleteSlice } = useDeleteChunk();
// 每次props.chunks更新时,更新ref
// Every time props.chunks is updated, update the ref.
useEffect(() => {
chunksRef.current = chunks;
}, [chunks]);
/**
* 删除特定分片
* Remove specific shardings
*/
const handleDeleteChunk = useCallback(
(chunk: Chunk) => {
// 从ref中获取最新的chunks
// Get the latest chunks from the ref
const currentChunks = chunksRef.current;
const updatedChunks = currentChunks.filter(
c =>

View File

@@ -36,7 +36,7 @@ export const useCreateLocalChunk = ({
});
/**
* 处理本地分片的创建操作
* Handle the creation of local shardings
*/
const createLocalChunk = async (chunk: Chunk) => {
if (!chunk.local_slice_id) {

View File

@@ -27,7 +27,7 @@ export const useDeleteLocalChunk = ({
onChunksChange,
}: UseDeleteLocalChunkProps) => {
/**
* 处理本地分片的删除操作
* Handle deletion of local shardings
*/
const deleteLocalChunk = (chunk: Chunk) => {
if (!chunk.local_slice_id) {

View File

@@ -32,7 +32,7 @@ export const useDeleteRemoteChunk = ({
const { deleteSlice } = useDeleteChunk();
/**
* 处理远程分片的删除操作
* Handling remotely sharding deletion operations
*/
const deleteRemoteChunk = async (chunk: Chunk) => {
if (!chunk.slice_id) {

View File

@@ -40,16 +40,16 @@ export const useInitEditor = ({
editorProps,
onChange,
}: UseDocumentEditorProps) => {
// 创建编辑器实例
// Create an editor instance
const editor: Editor | null = useEditor({
extensions: [
StarterKit.configure({
hardBreak: {
// 强制换行
// force wrap
keepMarks: false,
},
paragraph: {
// 配置段落,避免生成多余的空段落
// Configure paragraphs to avoid generating extra empty paragraphs
HTMLAttributes: {
class: 'text-knowledge-tiptap-editor-paragraph',
},
@@ -88,30 +88,30 @@ export const useInitEditor = ({
}
const text = event.clipboardData?.getData('text/plain');
// 如果粘贴的纯文本中包含换行符
// If the pasted plain text contains a newline character
if (text?.includes('\n')) {
event.preventDefault(); // 阻止默认粘贴行为
event.preventDefault(); // Block default paste behavior
const html = getRenderHtmlContent(text);
// 将转换后的 HTML 插入编辑器
// Insert the converted HTML into the editor
editor.chain().focus().insertContent(html).run();
return true; // 表示我们已处理
return true; // It means we have dealt with it.
}
return false; // 使用默认行为
return false; // Use default behavior
},
},
});
// 当激活的分片改变时,更新编辑器内容
// Update editor content when active sharding changes
useEffect(() => {
if (!editor || !chunk) {
return;
}
const htmlContent = getRenderHtmlContent(chunk.content || '');
// 设置内容,保留换行符
// Set content, keep newlines
editor.commands.setContent(htmlContent || '', false, {
preserveWhitespace: 'full',
});

View File

@@ -37,16 +37,16 @@ export const usePreviewContextMenu = ({
onActiveChunkChange,
onAddChunk,
}: UsePreviewContextMenuProps) => {
// 使用ref保存最新的chunks引用
// Use ref to save the latest chunks reference
const chunksRef = useRef(chunks);
const { deleteSlice } = useDeleteChunk();
// 每次props.chunks更新时,更新ref
// Every time props.chunks is updated, update the ref.
useEffect(() => {
chunksRef.current = chunks;
}, [chunks]);
// 激活特定分片的编辑模式
// Activate edit mode for specific shardings
const handleActivateEditMode = useCallback(
(chunk: Chunk) => {
onActiveChunkChange?.(chunk);
@@ -54,10 +54,10 @@ export const usePreviewContextMenu = ({
[onActiveChunkChange],
);
// 在特定分片前添加新分片
// Add new shardings before specific shardings
const handleAddChunkBefore = useCallback(
(chunk: Chunk) => {
// 从ref中获取最新的chunks
// Get the latest chunks from the ref
const currentChunks = chunksRef.current;
const index = currentChunks.findIndex(
c =>
@@ -86,17 +86,17 @@ export const usePreviewContextMenu = ({
onChunksChange?.(updatedChunks);
// 自动激活新分片的编辑模式
// Automatically activate editing mode for new shardings
onActiveChunkChange?.(newChunk);
onAddChunk?.(newChunk);
},
[onChunksChange, onActiveChunkChange, documentId, onAddChunk],
);
// 在特定分片后添加新分片
// Add new shardings after specific shardings
const handleAddChunkAfter = useCallback(
(chunk: Chunk) => {
// 从ref中获取最新的chunks
// Get the latest chunks from the ref
const currentChunks = chunksRef.current;
const index = currentChunks.findIndex(
c =>
@@ -123,7 +123,7 @@ export const usePreviewContextMenu = ({
...currentChunks.slice(index + 1),
];
// 自动激活新分片的编辑模式
// Automatically activate editing mode for new shardings
onActiveChunkChange?.(newChunk);
onChunksChange?.(updatedChunks);
onAddChunk?.(newChunk);
@@ -131,10 +131,10 @@ export const usePreviewContextMenu = ({
[onChunksChange, onActiveChunkChange, documentId, onAddChunk],
);
// 删除特定分片
// Remove specific shardings
const handleDeleteChunk = useCallback(
(chunk: Chunk) => {
// 从ref中获取最新的chunks
// Get the latest chunks from the ref
const currentChunks = chunksRef.current;
const updatedChunks = currentChunks.filter(
c =>

View File

@@ -63,7 +63,7 @@ export const useSaveChunk = ({
});
/**
* 处理远程分片的保存逻辑
* Handling save logic for remote shardings
*/
const saveRemoteChunk = async (chunk: Chunk) => {
if (chunk.content === '') {
@@ -74,7 +74,7 @@ export const useSaveChunk = ({
};
/**
* 处理本地分片的保存逻辑
* Save logic for handling local shardings
*/
const saveLocalChunk = async (chunk: Chunk) => {
if (chunk.content === '') {
@@ -85,7 +85,7 @@ export const useSaveChunk = ({
};
/**
* 保存分片的主函数
* Save the main function of sharding
*/
const saveChunk = async (chunk: Chunk) => {
if (!chunk.local_slice_id) {

View File

@@ -35,7 +35,7 @@ export const useUpdateRemoteChunk = ({
const { updateSlice } = useUpdateChunk();
/**
* 处理远程分片的更新操作
* Handling updates for remote sharding
*/
const updateRemoteChunk = async (chunk: Chunk) => {
if (!chunk.slice_id) {

View File

@@ -28,7 +28,7 @@ export {
export { BaseTextKnowledgeEditor } from './scenes/base';
export type { Editor } from '@tiptap/react';
// 新增组件导出
// Add component export
export { HoverEditBar } from './features/hover-edit-bar/hover-edit-bar';
export {
EditAction,
@@ -37,7 +37,7 @@ export {
DeleteAction,
} from './features/hover-edit-bar-actions';
// 事件总线相关导出
// Event Bus Dependent Export
export {
eventBus,
createEventBus,

View File

@@ -46,12 +46,12 @@ export const BaseTextKnowledgeEditor = ({
const [chunks, setChunks] = useState<DocumentChunk[]>(initialChunks);
const [activeChunk, setActiveChunk] = useState<DocumentChunk | null>(null);
// 使用编辑器核心功能
// Using the core editor functions
const { editor } = useInitEditor({
chunk: activeChunk,
});
// 退出新增分片功能
// Exit the new sharding feature
const { saveChunk } = useSaveChunk({
chunks,
documentId,
@@ -63,7 +63,7 @@ export const BaseTextKnowledgeEditor = ({
onDeleteChunk,
});
// 监听右键菜单事件
// Monitor right-click menu events
useEventListener(
'previewContextMenuItemAction',
useCallback(
@@ -88,7 +88,7 @@ export const BaseTextKnowledgeEditor = ({
),
);
// 监听悬浮编辑栏事件
// Monitor floating edit bar events
useEventListener(
'hoverEditBarAction',
useCallback(

View File

@@ -24,18 +24,18 @@ export interface ActiveChunkInfo {
}
/**
* 管理文档中活动的chunk
* 使用renderLevel字段来唯一标识chunk的渲染位置
* Manage active chunks in documents
* Use the renderLevel field to uniquely identify the render location of the chunk
*/
export const useActiveChunk = () => {
// 存储活动的chunk和它的renderLevel
// Store the active chunk and its renderLevel
const [activeChunkInfo, setActiveChunkInfo] = useState<ActiveChunkInfo>({
chunk: null,
renderLevel: null,
});
/**
* 清除活动chunk信息
* Clear active chunks
*/
const clearActiveChunk = () => {
setActiveChunkInfo({
@@ -45,8 +45,8 @@ export const useActiveChunk = () => {
};
/**
* 设置活动chunk和它的renderLevel
* 在用户交互(如双击)时使用
* Set the active chunk and its renderLevel
* Use during user interaction (e.g. double-clicking)
*/
const setActiveChunkWithLevel = (chunk: LevelDocumentTreeNode) => {
if (!chunk.renderLevel) {
@@ -61,7 +61,7 @@ export const useActiveChunk = () => {
};
/**
* 检查给定的chunk是否是当前活动的chunk
* Checks whether the given chunk is the currently active chunk
*/
const isActiveChunk = (renderLevel: string | undefined) => {
if (!renderLevel) {

View File

@@ -24,19 +24,19 @@ export interface ActiveChunkInfo {
}
/**
* 管理文档中具有相同ID的chunk的渲染路径
* 通过为每个chunk实例分配唯一的渲染路径解决重复ID的问题
* Manage the rendering path for chunks with the same ID in a document
* Solve the problem of duplicate IDs by assigning a unique render path to each chunk instance
*/
export const useChunkRenderPath = () => {
// 存储活动的chunk和它的渲染路径
// Store the active chunk and its render path
const [activeChunkInfo, setActiveChunkInfo] = useState<ActiveChunkInfo>({
chunk: null,
renderPath: null,
});
/**
* 设置活动chunk但不设置渲染路径
* 通常在外部逻辑中使用,如usePreviewContextMenu
* Set the active chunk, but not the render path
* Usually used in external logic, such as usePreviewContextMenu
*/
const setActiveChunk = (chunk: LevelDocumentChunk | null) => {
setActiveChunkInfo(prev => ({
@@ -46,7 +46,7 @@ export const useChunkRenderPath = () => {
};
/**
* 清除活动chunk信息
* Clear active chunks
*/
const clearActiveChunk = () => {
setActiveChunkInfo({
@@ -56,8 +56,8 @@ export const useChunkRenderPath = () => {
};
/**
* 设置活动chunk和它的渲染路径
* 在用户交互(如双击)时使用
* Set the active chunk and its rendering path
* Use during user interaction (e.g. double-clicking)
*/
const setActiveChunkWithPath = (
chunk: LevelDocumentChunk,
@@ -70,14 +70,14 @@ export const useChunkRenderPath = () => {
};
/**
* 检查给定的chunk和渲染路径是否匹配当前活动的chunk
* Checks whether the given chunk and rendering path match the currently active chunk
*/
const isActiveChunk = (chunkId: string, renderPath: string) =>
chunkId === activeChunkInfo.chunk?.text_knowledge_editor_chunk_uuid &&
renderPath === activeChunkInfo.renderPath;
/**
* 为chunk生成唯一的渲染路径
* Generate a unique render path for chunks
*/
const generateRenderPath = (basePath: string, chunkId: string) =>
`${basePath}-${chunkId}`;

View File

@@ -19,8 +19,8 @@ import { useEffect } from 'react';
import { createLocateChunkId } from '../../services/locate-segment';
/**
* 滚动到选中的元素
* @param selectionIDs 选中的元素ID数组
* Scroll to the selected element
* @Param selectionIDs array of selected element IDs
*/
export const useScrollToSelection = (selectionIDs?: string[]) => {
useEffect(() => {

View File

@@ -66,7 +66,7 @@ export const LevelTextKnowledgeEditor: React.FC<
[chunks],
);
// 使用活动chunk hook
// Using active chunk hooks
const {
activeChunkInfo,
clearActiveChunk,
@@ -74,12 +74,12 @@ export const LevelTextKnowledgeEditor: React.FC<
isActiveChunk,
} = useActiveChunk();
// 使用编辑器核心功能
// Using the core editor functions
const { editor } = useInitEditor({
chunk: activeChunkInfo.chunk,
});
// 分片功能
// Sharding function
const { saveChunk } = useSaveChunk({
chunks: initialChunks,
documentId,
@@ -92,10 +92,10 @@ export const LevelTextKnowledgeEditor: React.FC<
},
});
// 使用滚动到选中元素的hook
// Use the hook that scrolls to the selected element
useScrollToSelection(selectionIDs);
// 监听右键菜单事件
// Monitor right-click menu events
useEventListener(
'previewContextMenuItemAction',
useCallback(({ type, targetChunk, chunks: newChunks }) => {
@@ -109,7 +109,7 @@ export const LevelTextKnowledgeEditor: React.FC<
}, []),
);
// 监听悬浮编辑栏事件
// Monitor floating edit bar events
useEventListener(
'hoverEditBarAction',
useCallback(({ type, targetChunk, chunks: newChunks }) => {
@@ -231,7 +231,7 @@ const RenderContent = ({
].includes(levelDocumentTree.type) ? (
<div key={levelDocumentTree.text_knowledge_editor_chunk_uuid}>
{(() => {
// 检查这个chunk是否是当前活动的chunk使用renderLevel字段
// Check whether this chunk is the currently active chunk, using the renderLevel field
const chunkIsActive = isActiveChunk(levelDocumentTree.renderLevel);
if (chunkIsActive) {
@@ -261,7 +261,7 @@ const RenderContent = ({
previewContextMenuItemsContributes
}
onActivateEditMode={activedChunk => {
// 设置活动chunk使用chunk自身的renderLevel
// Set the active chunk, using the renderLevel of the chunk itself
setActiveChunkWithLevel(
activedChunk as LevelDocumentTreeNode,
);

View File

@@ -71,7 +71,7 @@ const getChildren = (
}
}, []);
/** 兜底情况,如果 idp 的结果没有标题,则补上标题 */
/** Bottom line, if the result of idp has no title, add the title */
export const withTitle = (
segments: LevelDocumentChunk[],
title?: string,

View File

@@ -24,7 +24,7 @@ export type LevelDocumentTreeNode = Omit<ILevelSegment, 'children' | 'parent'> &
Chunk & {
parent?: string;
children?: LevelDocumentTreeNode[];
renderLevel?: string; // 用于唯一标识chunk的渲染路径
renderLevel?: string; // Rendering path used to uniquely identify chunks
};
export type LevelDocumentTree = LevelDocumentTreeNode[];

View File

@@ -31,7 +31,7 @@ export const createLocalChunk = (props: { sequence: string }): Chunk => {
};
/**
* 更新本地分片
* Update local sharding
*/
export const updateLocalChunk = ({
chunks,
@@ -44,34 +44,34 @@ export const updateLocalChunk = ({
}): Chunk[] =>
chunks.map(c => (c.local_slice_id === localChunkSliceId ? newChunk : c));
// 删除本地分片
// Delete local sharding
export const deleteLocalChunk = (
chunks: Chunk[],
localChunkSliceId: string,
): Chunk[] => chunks.filter(c => c.local_slice_id !== localChunkSliceId);
/**
* 更新文档分片内容
* Update document sharding content
*/
export const updateChunkContent = (chunk: Chunk, content: string): Chunk => ({
...chunk,
content,
});
// 删除远程分片
// Delete remote sharding
export const deleteRemoteChunk = (
chunks: Chunk[],
remoteChunkSliceId: string,
): Chunk[] => chunks.filter(c => c.slice_id !== remoteChunkSliceId);
/**
* 更新chunks
* Update chunks
*/
export const updateChunks = (chunks: Chunk[], chunk: Chunk): Chunk[] =>
chunks.map(c => (c.slice_id === chunk.slice_id ? chunk : c));
/**
* 创建远程分片
* Create remote sharding
*/
export const createRemoteChunk = (props: {
sequence: string;

View File

@@ -17,7 +17,7 @@
import { type Chunk } from '@/text-knowledge-editor/types/chunk';
/**
* 更新文档分片内容
* Update document sharding content
*/
export const updateChunkContent = (chunk: Chunk, content: string): Chunk => ({
...chunk,
@@ -25,13 +25,13 @@ export const updateChunkContent = (chunk: Chunk, content: string): Chunk => ({
});
/**
* 更新chunks
* Update chunks
*/
export const updateChunks = (chunks: Chunk[], chunk: Chunk): Chunk[] =>
chunks.map(c => (c.slice_id === chunk.slice_id ? chunk : c));
/**
* 获取激活的分片
* Get active sharding
*/
export const getActiveChunk = (
chunks: Chunk[],
@@ -44,15 +44,15 @@ export const getActiveChunk = (
};
/**
* 处理编辑器输出的HTML内容
* 移除不必要的外层<p>标签,保持与原始内容格式一致
* Process the HTML content output by the editor
* Remove unnecessary outer < p > tags to maintain the original content format
*/
export const processEditorContent = (content: string): string => {
if (!content) {
return '';
}
// 如果内容被<p>标签包裹,并且只有一个<p>标签
// If the content is wrapped with < p > tags, and there is only one < p > tag
const singleParagraphMatch = content.match(/^<p>(.*?)<\/p>$/s);
if (singleParagraphMatch) {
return singleParagraphMatch[1];

View File

@@ -18,7 +18,7 @@ import classNames from 'classnames';
export const getEditorTableClassname = () =>
classNames(
// 表格样式
// table style
'[&_table]:border-collapse [&_table]:m-0 [&_table]:w-full [&_table]:table-fixed [&_table]:overflow-hidden [&_table]:text-[0.9em]',
'[&_table_td]:border [&_table_th]:border [&_table_td]:border-[#ddd] [&_table_th]:border-[#ddd]',
'[&_table_td]:p-2 [&_table_th]:p-2',

View File

@@ -18,12 +18,12 @@ import classNames from 'classnames';
export const getEditorWordsCls = () =>
classNames(
// 换行
// line feed
'[&_p]:break-words [&_p]:whitespace-pre-wrap',
// 保留所有空格和换行符
// Keep all spaces and line breaks
'[&_.ProseMirror_*]:break-words [&_.ProseMirror_*]:whitespace-pre-wrap',
// 段落
// paragraph
'[&_.editor-paragraph]:min-h-[1.5em] [&_.editor-paragraph]:leading-normal',
// 空段落
// Empty paragraph
'[&_.editor-paragraph:empty]:min-h-[1.5em] [&_.editor-paragraph:empty]:block',
);

View File

@@ -17,8 +17,8 @@
import { type Editor } from '@tiptap/react';
/**
* 获取编辑器内容
* 返回用户真实编辑的内容移除TipTap自动添加的外层<p>标签
* Get editor content
* Return the user's actual edited content and remove the outer < p > tag automatically added by TipTap
*/
export const getEditorContent = (editor: Editor | null) => {
if (!editor) {
@@ -29,38 +29,38 @@ export const getEditorContent = (editor: Editor | null) => {
const doc = removeEditorWrapperParagraph(content);
// 返回处理后的HTML
// Returns the processed HTML.
return doc;
};
/**
* 处理编辑器输出的HTML内容
* 移除不必要的外层<p>标签,保持与原始内容格式一致
* Process the HTML content output by the editor
* Remove unnecessary outer < p > tags to maintain the original content format
*/
export const removeEditorWrapperParagraph = (content: string): string => {
if (!content) {
return '';
}
// 使用DOM解析器来处理HTML
// Using a DOM parser to process HTML
const parser = new DOMParser();
const doc = parser.parseFromString(content, 'text/html');
// 找到所有编辑器生成的p标签
// Find all editor-generated p tags
const generatedParagraphs = doc.querySelectorAll(
'p.text-knowledge-tiptap-editor-paragraph',
);
// 替换这些p标签为它们的内容
// Replace these p tags with their content
generatedParagraphs.forEach(p => {
const parent = p.parentNode;
if (parent) {
// 创建一个文档片段来存储p标签的内容
// Create a document fragment to store the contents of the p tag
const fragment = document.createDocumentFragment();
while (p.firstChild) {
fragment.appendChild(p.firstChild);
}
// 用内容替换p标签
// Replace p tags with content
parent.replaceChild(fragment, p);
}
});

View File

@@ -15,7 +15,7 @@
*/
/**
* 编辑器对/n不会换行所以需要转换为<br />标签
* The editor doesn't wrap/n, so it needs to be converted to a < br/> tag
*/
export const getInitEditorContent = (content: string) => {
if (content === '') {

View File

@@ -17,16 +17,16 @@
import { escapeHtml } from '@/text-knowledge-editor/utils/escape-html';
/**
* 获取渲染后的HTML内容
* Get the rendered HTML content
*/
export const getRenderHtmlContent = (content: string) => {
if (content === '') {
return '';
}
// 转义HTML只允许白名单中的标签
// Escape HTML, allowing only whitelisted tags
const htmlContent = escapeHtml(content);
// 编辑器对/n不会换行所以需要转换为<br />标签
// The editor doesn't wrap/n, so it needs to be converted to a < br/> tag
return htmlContent.replace(/\n/g, '<br />');
};

View File

@@ -19,7 +19,7 @@ import { type Chunk } from '@/text-knowledge-editor/types/chunk';
import { processEditorContent } from '../inner/document-editor.service';
/**
* 判断内容是否改变
* Determine whether the content has changed
*/
export const isEditorContentChange = (
chunks: Chunk[],

View File

@@ -15,10 +15,10 @@
*/
/**
* html白名单防止XSS攻击
* HTML whitelist to prevent XSS attacks
*/
// 默认允许的HTML标签白名单
// Whitelist of HTML tags allowed by default
const DEFAULT_ALLOWED_TAGS = [
'img',
'table',
@@ -35,10 +35,10 @@ const DEFAULT_ALLOWED_TAGS = [
];
/**
* 转义HTML只允许白名单中的标签
* @param unsafe 不安全的HTML字符串
* @param allowedTags 允许的HTML标签数组默认为DEFAULT_ALLOWED_TAGS
* @returns 转义后的HTML字符串
* Escape HTML, allowing only whitelisted tags
* @param unsafe HTML string
* @Param allowedTags Array of HTML tags allowed, default to DEFAULT_ALLOWED_TAGS
* @Returns the escaped HTML string
*/
export function escapeHtml(
unsafe: string,
@@ -48,7 +48,7 @@ export function escapeHtml(
return '';
}
// 构建正则表达式模式
// Building regular expression patterns
const allowedTagsPattern = allowedTags.join('|');
const tagRegex = new RegExp(
`<(?!(${allowedTagsPattern})\\b[^>]*>|\\/(?:${allowedTagsPattern})>)`,

View File

@@ -23,7 +23,7 @@ import {
import { getKnowledgeIDEQuery } from '@coze-data/knowledge-common-services/use-case';
/** knowledge 模块专用的 useNavigate用于持久化公共 query 参数 */
/** useNavigate dedicated to the knowledge module for persisting common query parameters */
export const useKnowledgeNavigate: typeof useNavigate = () => {
const navigate = useNavigate();
const knowledgePageQuery = getKnowledgeIDEQuery();

View File

@@ -30,6 +30,6 @@ export const getKnowledgeIDEQuery = (): KnowledgeIDEQuery => {
agent_id: queryParams.get('agent_id'),
page_mode: queryParams.get('page_mode') as KnowledgeIDEQuery['page_mode'],
};
// 过滤掉空值,避免产生多余的 querystring
// Filter out null values to avoid generating extra querystrings.
return Object.fromEntries(Object.entries(knowledgeQuery).filter(e => !!e[1]));
};

View File

@@ -26,15 +26,15 @@ import {
export enum FilterPhotoType {
/**
* 全部
* all
*/
All = 'All',
/**
* 已标注
* marked
*/
HasCaption = 'HasCaption',
/**
* 未标注
* unmarked
*/
NoCaption = 'NoCaption',
}
@@ -46,7 +46,7 @@ export interface KnowledgePreviewState {
searchValue: string;
curDocId: string;
/**
* 图片类型是否已标注
* Is the image type marked?
*/
photoFilterValue: FilterPhotoType;
}

View File

@@ -43,7 +43,7 @@ export interface IParams {
agentID?: string;
actionType?: ActionType;
initialTab?: 'structure' | 'draft' | 'online';
/** 作用是跳转上传页时能在 url 里带上抖音标记,以在上传页做视图区分 */
/** The function is to bring the Douyin mark in the url when jumping to the upload page to distinguish the views on the upload page */
isDouyinBot?: boolean;
pageMode?: 'modal' | 'normal';

View File

@@ -24,7 +24,7 @@ interface DatasetStore {
}
/**
* 只适用于 bot 单 agent 模式
* Only works in bot single agent mode
*/
export const useDatasetStore = create<DatasetStore>()(
devtools(

View File

@@ -61,17 +61,17 @@ export const AutoGenerateButton: React.FC<AutoGenerateButtonProps> = ({
onProgress(false);
}
};
// 如果没有 caption则不用confirm
// If there is no caption, do not confirm
if (!currentValue) {
await generateCaption();
return;
}
UIModal.warning({
// 必填参数,统一 confirm modal 的样式
// Required parameters to confirm modal style
className: styles['confirm-modal'],
closeIcon: <IconCloseKnowledge />,
// 自定义参数
// custom parameters
title: I18n.t('knowledge_photo_021'),
content: I18n.t('knowledge_photo_022'),
icon: <IconWarningSize24 />,

View File

@@ -94,14 +94,14 @@ export const HeaderTags = ({
</Tag>
)}
{/* 图片来源 */}
{/* Image source */}
{formatType === FormatType.Image && (
<Tag size="mini" color="primary">
{I18n.t('dataset_detail_source_local')}
</Tag>
)}
{/* 图片数量 */}
{/* number of pictures */}
{formatType === FormatType.Image && !!dataSetDetail?.doc_count && (
<Tag size="mini" color="primary">
{I18n.t('knowledge_photo_015', {
@@ -110,7 +110,7 @@ export const HeaderTags = ({
</Tag>
)}
{/* 未添加文档时不展示 */}
{/* Do not display when no document is added */}
{formatType !== FormatType.Image && !!dataSetDetail?.doc_count && (
<>
{/* slice count */}

View File

@@ -111,7 +111,7 @@ export const KnowledgeModalNavBar: React.FC<KnowledgeModalNavBarProps> = ({
<div className={styles.toolbar}>
<Space spacing={12}>
{isImageFormat ? <PhotoFilter /> : null}
{/* 导入按钮 */}
{/* import button */}
{canEdit ? importKnowledgeSourceButton : null}
{actionButtons}
</Space>

View File

@@ -124,7 +124,7 @@ export const KnowledgeIDENavBar = ({
].includes(unitType),
[unitType],
);
// link 或者 action 二选一存在时才展示
// Link or action will only be displayed when one exists
const showTableConfigButton =
(isShowLinkUrl || canEdit) && isTableFormat && documentList?.length;

View File

@@ -73,7 +73,7 @@ export const usePhotoDetailModal = (params: UsePhotoDetailModalParams) => {
const status = progressMap[document_id || '']?.status || originStatus;
// 处理中获处理失败的photo不允许更新 caption
// The photo that failed to be processed is not allowed to update the caption.
const disableUpdate =
status === DocumentStatus.Processing ||
status === DocumentStatus.Failed ||
@@ -86,7 +86,7 @@ export const usePhotoDetailModal = (params: UsePhotoDetailModalParams) => {
}
}, [
visible,
// 切换图片时需要更新初始状态
// The initial state needs to be updated when switching pictures.
document_id,
]);
@@ -136,12 +136,12 @@ export const usePhotoDetailModal = (params: UsePhotoDetailModalParams) => {
<div className={styles['modal-content']}>
<div className={styles['photo-large']}>
<Image
// 仅设置高度,宽度会按图片原比例自动缩放
// Only set the height, and the width will be automatically scaled according to the original scale of the picture.
height={300}
src={photo.url}
/>
{
// 未找到,或者为第一个,不展示 pre 按钮
// Not found, or for the first one, the pre button is not displayed
currentIndex < 1 ? null : (
<IconButton
icon={<Icon svg={<SvgArrowLeft />} />}
@@ -158,7 +158,7 @@ export const usePhotoDetailModal = (params: UsePhotoDetailModalParams) => {
)
}
{
// 未找到,或者为最后一个,不展示 pre 按钮
// Not found, or for the last one, the pre button is not displayed
currentIndex === -1 ||
currentIndex === photoList.length - 1 ? null : (
<IconButton

View File

@@ -20,7 +20,7 @@ import { IconUnitsTable, IconUnitsFile } from '@coze-arch/bot-icons';
import { IconWithSuffix } from './suffix';
// 获取 icon
// Get icon
export const RenderDocumentIcon = ({
formatType,
sourceType,

View File

@@ -121,7 +121,7 @@ export const ImageKnowledgeWorkspace: FC<
setCurrentPhotoId,
reload: reloadAsync,
onCancel: () => {
// 重置url参数
// Reset url parameters
resetUrlQueryParams();
},
onSubmit: () => {
@@ -129,12 +129,12 @@ export const ImageKnowledgeWorkspace: FC<
},
});
// 手动控制 data 加载时机
// Manually control data loading timing
useEffect(() => {
if (dataSetDetail?.dataset_id) {
reloadAsync();
// 重新加载时,回到最顶部
// When reloading, return to the top
ref.current?.scrollTo?.({
top: 0,
behavior: 'smooth',
@@ -142,7 +142,7 @@ export const ImageKnowledgeWorkspace: FC<
}
}, [searchValue, photoFilterValue, dataSetDetail?.dataset_id]);
// 自动打开编辑弹窗
// Automatically open the editing pop-up window
useEffect(() => {
if (shouldAutoOpenDetailModal) {
if (firstAutoOpenEditDocumentId) {
@@ -182,10 +182,10 @@ export const ImageKnowledgeWorkspace: FC<
caption: originCaption,
status: originStatus,
} = item;
// 此处使用 progressMap 可以保持不断刷新直至完成
// Use progressMap here to keep refreshing until completion
// @ts-expect-error -- linter-disable-autofix
const status = progressMap[document_id]?.status || originStatus;
// 使用 progressMap 获取最新的caption
// Use progressMap to get the latest caption
const caption =
// @ts-expect-error -- linter-disable-autofix
(progressMap[document_id] as ProgressItem & PhotoInfo)
@@ -202,11 +202,11 @@ export const ImageKnowledgeWorkspace: FC<
const handleDelete = () => {
UIModal.error({
// 必填参数,统一 confirm modal 的样式
// Required parameters to confirm modal style
className: styles['confirm-modal'],
closeIcon: <IconCloseKnowledge />,
// 自定义参数
// custom parameters
title: I18n.t('kl2_007'),
content: I18n.t(
'dataset_detail_table_deleteModel_description',
@@ -247,7 +247,7 @@ export const ImageKnowledgeWorkspace: FC<
const isAudiFailed =
originStatus === DocumentStatus.AuditFailed;
const getCaption = () => {
// 违规图片
// Illegal pictures
if (isAudiFailed) {
return (
<span>
@@ -256,7 +256,7 @@ export const ImageKnowledgeWorkspace: FC<
);
}
// 处理失败
// Processing failed
if (status === DocumentStatus.Failed) {
return (
<span className={styles['failed-tag']}>
@@ -265,7 +265,7 @@ export const ImageKnowledgeWorkspace: FC<
);
}
// 处理中
// Processing
if (status === DocumentStatus.Processing) {
return (
<span className={styles['processing-tag']}>
@@ -274,12 +274,12 @@ export const ImageKnowledgeWorkspace: FC<
);
}
// 已标注
// marked
if (hasCaption) {
return caption;
}
// 未标注
// unmarked
return I18n.t('knowledge_photo_016');
};
@@ -295,7 +295,7 @@ export const ImageKnowledgeWorkspace: FC<
) : (
<Image
src={url}
// 仅设置宽度,高度会按图片原比例自动缩放
// Only set the width, and the height will be automatically scaled according to the original scale of the picture.
width={222}
preview={false}
onClick={handleEdit}

View File

@@ -60,7 +60,7 @@ export const usePhotoList = (
? true
: filterPhotoType === FilterPhotoType.NoCaption
? false
: // undefined 代表返回全部
: // Pass undefined to return all
undefined,
},
});

View File

@@ -78,7 +78,7 @@ export const ImportKnowledgeSourceButton = ({
onSourceChange(unitType);
return;
}
/** 默认跳转到upload */
/** Default jump to upload */
const formatType = dataSetDetail?.format_type;
const docID = documentList?.[0]?.document_id;
const params: Record<string, string> = {

View File

@@ -23,7 +23,7 @@ import { type Dataset, type DocumentInfo } from '@coze-arch/bot-api/knowledge';
import { DocumentStatus, FormatType } from '@coze-arch/bot-api/knowledge';
/**
* 处理表格类型数据集的禁用提示
* Disable hints for working with table-type datasets
*/
export const getTableFormatTooltip = (documentList: DocumentInfo[]): string => {
const docInfo = documentList?.[0];
@@ -44,7 +44,7 @@ export const getTableFormatTooltip = (documentList: DocumentInfo[]): string => {
};
/**
* 处理默认类型数据集的禁用提示
* Disable hints for handling default type datasets
*/
export const getDefaultFormatTooltip = (dataSetDetail: Dataset): string => {
// @ts-expect-error -- linter-disable-autofix
@@ -60,10 +60,10 @@ export const getDefaultFormatTooltip = (dataSetDetail: Dataset): string => {
};
/**
* 创建按钮禁用时的提示文本
* @param dataSetDetail - 数据集详情
* @param documentList - 文档列表
* @returns 提示文本
* Create prompt text when button is disabled
* @param dataSetDetail - Dataset Details
* @param documentList - Document List
* @Returns prompt text
*/
export const createBtnDisableToolTip = (
dataSetDetail: Dataset,

View File

@@ -121,12 +121,12 @@ export const getUpdatedDataset = (
actionType: ActionType,
dataSetDetail: Dataset,
): KnowledgeInfo[] => {
// 更新后的bot知识库
// Updated bot knowledge base
let updatedDatasetList: KnowledgeInfo[] = [];
// 原本的bot知识库内容
// The original bot knowledge base content
let originDataset: KnowledgeInfo[] = [];
// 兼容json版本的datasetFG全量后删除
// Compatible with the json version of dataset, delete it after FG is full
if ('dataset' in dataset) {
originDataset = dataset?.dataset ?? [];
} else {
@@ -147,7 +147,7 @@ export const getUpdatedDataset = (
return updatedDatasetList;
};
// 更新bot知识库逻辑
// Update bot knowledge base logic
export const handleDatasetUpdate = async ({
botInfo,
botId,
@@ -181,7 +181,7 @@ export const handleDatasetUpdate = async ({
updateSuccess();
};
// 根据不同botInfo信息 获取不同的bot原有的dataset
// Get the original dataset of different bots according to different botInfo information
export const getDatasetInfo = (
botInfo: GetDraftBotInfoAgwData | undefined,
agentId: string,

View File

@@ -96,7 +96,7 @@ export const useBeforeKnowledgeIDEClose = ({
};
const handleBotIdeBack = () => {
// Bot IDE检查是否有绑定knowledge如果有绑定知识库正常关闭没有绑定确认提示处理
// Bot IDE checks whether there is binding knowledge. If there is binding knowledge base, it will be closed normally, and there is no binding confirmation prompt.
if (hasAddDataset) {
Modal.confirm({
title: I18n.t('bot_ide_knowledge_confirm_title'),
@@ -124,17 +124,17 @@ export const useBeforeKnowledgeIDEClose = ({
console.error(error);
} finally {
setLoading(false);
// 无论成功无论都跳转一次
// Jump once regardless of success
handleFullModalBack();
}
},
onCancel: () => {
// 取消,正常跳转
// Cancel, jump normally
handleFullModalBack();
},
});
} else {
// 正常绑定不做弹窗拦截
// Normal binding does not do pop-up interception
handleFullModalBack();
}
};

View File

@@ -92,7 +92,7 @@ export const TableKnowledgeWorkspace = ({
slices,
]);
// 创建 UI Context
// Creating UI Context Values
const uiContextValue = {
tableViewRef,
isLoadingMoreSliceList,
@@ -100,7 +100,7 @@ export const TableKnowledgeWorkspace = ({
isShowAddBtn,
};
// 创建数据 Context
// Creating Data Context Values
const dataContextValue = {
sliceListData: sliceListData || { list: [], total: 0 },
curIndex,
@@ -108,7 +108,7 @@ export const TableKnowledgeWorkspace = ({
delSliceIds,
};
// 创建操作 Context
// Create Action Context Value
const actionsContextValue = {
setCurIndex,
setCurSliceId,

View File

@@ -38,7 +38,7 @@ import { useTableUI } from '../context/table-ui-context';
import { useTableData } from '../context/table-data-context';
import { useTableActions } from '../context/table-actions-context';
// 表格内容组件
// Table Content Component
const TableContent = () => {
const knowledgeIDEBiz = useKnowledgeParamsStore(state => state.params.biz);
const documentList = useKnowledgeStore(state => state.documentList);
@@ -55,14 +55,14 @@ const TableContent = () => {
const canEdit = Boolean(useKnowledgeStore(state => state.canEdit));
// 删除切片弹窗
// Delete slice pop-up
const { deleteSliceModalNode, openDeleteSliceModal } = useDeleteSliceModal();
// 编辑slice弹窗
// Edit slice pop-up
const { tableSegmentModalNode, openTableSegmentModal } =
useTableSegmentModal();
// 获取表格操作方法
// Get table manipulation method
const { deleteSlice, rowUpdateSliceData, modalEditSlice } =
useTableSliceOperations({
openDeleteSliceModal,
@@ -71,7 +71,7 @@ const TableContent = () => {
const { tableH } = useTableHeight();
// 如果没有数据,直接返回空
// If there is no data, return to empty directly
if (!slices?.length) {
return null;
}
@@ -132,7 +132,7 @@ const TableContent = () => {
);
};
// 添加行按钮组件
// Add line button component
const AddRowButton = () => {
const { isShowAddBtn } = useTableUI();
const documentList = useKnowledgeStore(state => state.documentList);
@@ -164,12 +164,12 @@ const AddRowButton = () => {
);
};
// 主组件
// main component
export const TableDataView = () => {
const { sliceListData } = useTableData();
const slices = sliceListData?.list;
// 如果没有数据,只显示添加按钮
// If there is no data, only the add button is displayed.
if (!slices?.length) {
return <AddRowButton />;
}

View File

@@ -18,7 +18,7 @@ import { createContext, useContext } from 'react';
import { type DatasetDataScrollList } from '@/service';
// 表格操作相关的 Context
// Context related to table manipulation
interface TableActionsContextType {
setCurIndex: (index: number | ((prev: number) => number)) => void;
setCurSliceId: (id: string | ((prev: string) => string)) => void;

View File

@@ -18,7 +18,7 @@ import { createContext, useContext } from 'react';
import { type DatasetDataScrollList } from '@/service';
// 表格数据相关的 Context
// Context related to tabular data
interface TableDataContextType {
sliceListData: DatasetDataScrollList;
curIndex: number;

View File

@@ -19,7 +19,7 @@ import { type MutableRefObject } from 'react';
import { type TableViewMethods } from '@coze-common/table-view';
// 表格 UI 相关的 Context
// Context related to table UI
interface TableUIContextType {
tableViewRef: MutableRefObject<TableViewMethods | null>;
isLoadingMoreSliceList: boolean;

View File

@@ -30,7 +30,7 @@ export const useCreateSlice = () => {
const documentList = useKnowledgeStore(state => state.documentList);
const curDoc = documentList?.[0];
// 创建切片
// Create slice
const { createSlice } = useCreateSliceService({
onReload: (createItem: ISliceInfo) => {
const list =

View File

@@ -25,7 +25,7 @@ import { useScrollListSliceReq } from '@/service';
export const useGetSliceListData = () => {
const documentList = useKnowledgeStore(state => state.documentList);
const curDocId = documentList?.[0]?.document_id;
// 加载数据
// load data
const {
data: sliceListData,
mutate: mutateSliceListData,

View File

@@ -20,7 +20,7 @@ const ADD_BTN_HEIGHT = 56;
export const useScroll = () => {
const { sliceListData } = useTableData();
// 滚动表格到底部
// Scroll table to the bottom
const scrollTableBodyToBottom = () => {
const bodyDom = document.querySelector(
'.table-view-box .semi-table-container>.semi-table-body',

View File

@@ -24,7 +24,7 @@ export const useTableHeight = () => {
const { sliceListData } = useTableData();
const [tableH, setTableHeight] = useState<number | string>(0);
// 更新表格高度
// Update table height
useEffect(() => {
const h = tableViewRef?.current?.getTableHeight();
if (h) {

View File

@@ -35,7 +35,7 @@ export const useAddRow = ({
const { sliceListData } = useTableData();
const { mutateSliceListData } = useTableActions();
const handleAddRow = () => {
/** 先增加容器的高度 */
/** Increase the height of the container first */
increaseTableHeight(ADD_BTN_HEIGHT);
const items = JSON.parse(sliceListData?.list[0]?.content ?? '[]');

View File

@@ -28,12 +28,12 @@ import { useTableData } from '../../context/table-data-context';
import { useTableActions } from '../../context/table-actions-context';
export const useDeleteSliceModal = () => {
// 外部数据
// external data
const dataSetDetail = useKnowledgeStore(state => state.dataSetDetail);
const setDataSetDetail = useKnowledgeStore(state => state.setDataSetDetail);
const documentList = useKnowledgeStore(state => state.documentList);
// 内部数据
// internal data
const { sliceListData, delSliceIds } = useTableData();
const { tableViewRef } = useTableUI();
const { mutateSliceListData } = useTableActions();
@@ -41,7 +41,7 @@ export const useDeleteSliceModal = () => {
const curDoc = documentList?.[0];
const slices = sliceListData?.list;
// 删除切片弹窗
// Delete slice pop-up
const { node: deleteSliceModalNode, delete: openDeleteSliceModal } =
useSliceDeleteModal({
onDel: async () => {

View File

@@ -33,7 +33,7 @@ export const useTableSegmentModal = () => {
const { mutateSliceListData } = useTableActions();
const curDoc = documentList?.[0];
// 表格分段弹窗
// table segmentation pop-up
const {
node: tableSegmentModalNode,
edit: openTableSegmentModal,

View File

@@ -48,11 +48,11 @@ export const useTableSliceOperations = ({
return;
}
/** 新增的行 */
/** new row */
const addIndex = indexs.filter(i => !slices[i].slice_id);
const addIds = addIndex.map(i => slices[i]?.addId);
const oldIndex = indexs.filter(v => !addIndex.includes(v));
// 确保过滤掉undefined
// Make sure to filter out undefined values
const sliceIds = oldIndex
.map(i => slices[i].slice_id)
.filter(Boolean) as string[];
@@ -129,12 +129,12 @@ export const useTableSliceOperations = ({
if (sliceId) {
await updateSlice(sliceId as string, updateContent, updateValue);
} else {
/** 新增分片 */
/** Add sharding */
const createParams = await handleCreateSlice(updateContent);
if (createParams && createSlice && curDoc?.document_id) {
// 调用传入的createSlice方法创建新的分片
// Call the createSlice method passed in to create a new sharding.
try {
// 这里需要使用props中传入的createSlice方法来调用API
// Here you need to use the createSlice method passed in the props to call the API.
await createSlice({
document_id: curDoc.document_id,
raw_text: updateContent,
@@ -145,7 +145,7 @@ export const useTableSliceOperations = ({
}
}
// 改为接口请求成功后才更新
// Change to update after the interface request is successful
if (slices) {
return true;
}
@@ -156,7 +156,7 @@ export const useTableSliceOperations = ({
}
};
/** 弹窗编辑切片 */
/** Pop-up editing slice */
const handleModalEditSlice = (_record: TableViewRecord, index: number) => {
if (!slices || index < 0 || index >= slices.length) {
return;

View File

@@ -16,6 +16,6 @@
import { TableKnowledgeWorkspace } from './components/main';
// 导出组件
// export component
export { TableKnowledgeWorkspace };
export type { TableKnowledgeWorkspaceProps } from './components/main';

View File

@@ -66,7 +66,7 @@ const getTableCacheWidthMap = (tableKey: string) => {
};
/**
* slice 数据转换为 TableView 组件接收的数据类型
* Slice data to the data type received by the TableView component
*/
export const getTableRenderColumnsData = ({
@@ -158,7 +158,7 @@ export const getTableRenderColumnsData = ({
/>
);
}
// 针对违规内容高亮处理
// Highlighting violations
const isAudiFailed = record?.status === SliceStatus.AuditFailed;
const textRender = () => (
<div className={`w-full ${isAudiFailed ? 'text-red-500' : ''}`}>

View File

@@ -75,7 +75,7 @@ export const DocSelector = ({
}
try {
const regx = new RegExp(searchValue);
// 搜索结果不展示「全部内容」选项
// Search results do not show the "All Content" option
return (
(op.value !== 'all' && op.value === value) ||
(op?.text as string)?.match(regx)

View File

@@ -48,7 +48,7 @@ export const LevelContent: React.FC<LevelContentProps> = ({
const canEdit = useKnowledgeStore(state => state.canEdit);
const searchValue = useKnowledgeStore(state => state.searchValue);
// 转换层级分段数据为编辑器可用格式
// Convert hierarchical segmented data into an editor-usable format
const renderLevelSegmentsData = levelSegments.map(item =>
createLevelDocumentChunkByLevelSegment(item),
);

View File

@@ -76,10 +76,10 @@ export const TextKnowledgeWorkspace = ({
const documentList = useKnowledgeStore(state => state.documentList);
const resourceNavigate = useDataNavigate();
// 初始化选择第一个文档
// Initialize to select the first document
useInitSelectFirstDoc();
// 文档管理
// Document Management
const {
handleSelectDocument,
handleRenameDocument,
@@ -89,15 +89,15 @@ export const TextKnowledgeWorkspace = ({
reloadDataset,
});
// 文档基本信息
// Documentation basic information
const { curDoc, curDocId, isProcessing, processFinished, datasetId } =
useDocumentInfo(progressMap);
// 文件预览
// file preview
const { showOriginalFile, handleToggleOriginalFile } =
useFilePreview(curDocId);
// 文档片段数据
// document fragment data
const { loading, renderData, handleContentChange, reload } = useSliceData({
curDocId,
datasetId,
@@ -107,7 +107,7 @@ export const TextKnowledgeWorkspace = ({
rollbackDocumentSelection,
});
// 层级分段数据
// hierarchical segmented data
const {
levelSegments,
selectionIDs,
@@ -119,11 +119,11 @@ export const TextKnowledgeWorkspace = ({
curDoc,
});
// 片段计数器
// fragment counter
const { handleIncreaseSliceCount, handleDecreaseSliceCount } =
useSliceCounter();
// 模态框
// modal box
const {
deleteModalNode,
showDeleteModal,
@@ -153,10 +153,10 @@ export const TextKnowledgeWorkspace = ({
},
});
// 文档选项
// Document Options
const docOptions = getDocumentOptions(documentList, progressMap);
// 处理重新分段
// Handle re-segmentation
const handleResegment = () => {
const isLocalText = Boolean(
curDoc?.source_type === DocumentSource.Document,

View File

@@ -39,7 +39,7 @@ import {
import { DocTag } from './doc-tag';
import { DocSelector } from './doc-selector';
// 文档基本信息
// Documentation basic information
export interface DocumentData {
curDoc?: DocumentInfo;
curDocId: string;
@@ -47,13 +47,13 @@ export interface DocumentData {
docOptions: OptionProps[];
}
// 文件预览相关
// File preview related
export interface FilePreviewData {
showOriginalFile: boolean;
fileUrl?: string;
}
// 文档操作回调
// document action callback
export interface DocumentActions {
onChangeDoc: (docId: string) => void;
onRenameDoc: (docId: string, newName: string) => void;
@@ -64,7 +64,7 @@ export interface DocumentActions {
reloadDataset?: () => void;
}
// 自定义UI元素
// Custom UI elements
export interface CustomUIElements {
linkOriginUrlButton?: ReactNode;
fetchSliceButton?: ReactNode;
@@ -92,7 +92,7 @@ export const TextToolbar: React.FC<TextToolbarProps> = ({
}) => {
const canEdit = useKnowledgeStore(state => state.canEdit);
// 控制按钮显示逻辑
// Control button display logic
const showUpdateFreBtn =
canEdit &&
curDoc &&

View File

@@ -80,7 +80,7 @@ export const DocSelector = ({
const regx = new RegExp(searchValue);
const newOptions = options.filter(
op =>
// 搜索结果不展示「全部内容」选项
// Search results do not show the "All Content" option
(op.value !== 'all' && op.value === value) ||
(op?.text as string)?.match(regx),
);
@@ -107,7 +107,7 @@ export const DocSelector = ({
const handleEditDocName = e => {
e.stopPropagation();
setVisible(true);
// TODO 打开弹框
// TODO opens the box
};
const triggerRender = ({ value: values }) => (
<Popover
@@ -200,7 +200,7 @@ export const DocSelector = ({
</Popover>
);
// TODO: 交互改版,这里做了个假的
// TODO: Interactive revision, made a fake here
return (
<Select
clickToHide={true}

View File

@@ -15,26 +15,26 @@
*/
/**
* 按照功能导出所有 hooks
* Export all hooks by function
*/
// 文档管理
// Document Management
export { useDocumentManagement } from './use-case/use-document-management';
// 文档信息
// Document information
export { useDocumentInfo } from './life-cycle/use-document-info';
// 文档片段数据
// document fragment data
export { useSliceData } from './life-cycle/use-slice-data';
// 层级分段数据
// hierarchical segmented data
export { useLevelSegments } from './use-case/use-level-segments';
// 文档片段计数
// Document fragment count
export { useSliceCounter } from './use-case/use-slice-counter';
// 文件预览
// file preview
export { useFilePreview } from './use-case/use-file-preview';
// 模态框
// modal box
export { useModals } from './use-case/use-modals';

View File

@@ -21,7 +21,7 @@ import { DocumentStatus } from '@coze-arch/bot-api/knowledge';
import { type ProgressMap } from '@/types';
/**
* 处理文档基本信息的 hook
* Hooks that handle basic information about documents
*/
export const useDocumentInfo = (progressMap: ProgressMap) => {
const { documentList, dataSetDetail, curDocId } = useKnowledgeStore(
@@ -32,16 +32,16 @@ export const useDocumentInfo = (progressMap: ProgressMap) => {
})),
);
// 当前文档
// current document
const curDoc = documentList?.find(i => i.document_id === curDocId);
// 处理状态
// processing state
const isProcessing = curDoc?.status === DocumentStatus.Processing;
const processFinished = curDocId
? progressMap[curDocId]?.status === DocumentStatus.Enable
: false;
// 数据集ID
// Dataset ID
const datasetId = dataSetDetail?.dataset_id ?? '';
return {

View File

@@ -40,7 +40,7 @@ interface UseSliceDataParams {
}
/**
* 处理文档片段数据获取的 hook
* Hooks for processing document fragment data acquisition
*/
export const useSliceData = ({
curDocId,
@@ -56,7 +56,7 @@ export const useSliceData = ({
})),
);
// 获取文档内容
// Get document content
const {
loading,
data: sliceData,
@@ -67,12 +67,12 @@ export const useSliceData = ({
params: {
keyword: searchValue,
document_id:
// 如果是层级分段则不请求
// If it is a hierarchical segmentation, it is not requested.
curChunkType !== ChunkType.LevelChunk ? curDocId : '',
},
reloadDeps: [searchValue, curDocId, datasetId, processFinished],
onError: error => {
/** 拉取 slice 失败时,回退 curDocId避免文档标题和内容不一致用户迷惑 */
/** When pulling a slice fails, roll back curDocId to avoid inconsistencies between the document title and content, and user confusion */
dataReporter.errorEvent(DataNamespace.KNOWLEDGE, {
eventName: ReportEventNames.KnowledgeGetSliceList,
error,
@@ -83,7 +83,7 @@ export const useSliceData = ({
},
});
// 使用 useMemo 缓存 chunks 数组,避免因 progressMap 更新导致不必要的重新创建
// Use useMemo to cache the chunks array to avoid unnecessary recreations due to progressMap updates
const renderData = useMemo(
() =>
sliceData?.list.map(item => createBaseDocumentChunkBySliceInfo(item)) ??
@@ -91,7 +91,7 @@ export const useSliceData = ({
[sliceData?.list],
);
// 处理内容变化
// Handling content changes
const handleContentChange = (chunks: DocumentChunk[]) => {
mutate({
...sliceData,

View File

@@ -35,10 +35,10 @@ export const useDocumentManagement = (props?: {
})),
);
// 缓存上一个文档ID用于加载失败后回滚
// Cache the previous document ID for rollback after load failure
const prevDocIdRef = useRef<string | null>(null);
// 更新文档名称
// Update document name
const { run: updateDocument } = useUpdateDocument({
onSuccess: () => {
Toast.success(I18n.t('Update_success'));
@@ -46,13 +46,13 @@ export const useDocumentManagement = (props?: {
},
});
// 选择文档
// Select document
const handleSelectDocument = (docId: string) => {
prevDocIdRef.current = curDocId || null;
setCurDocId(docId);
};
// 重命名文档
// rename document
const handleRenameDocument = (docId: string, newName: string) => {
updateDocument({
document_id: docId,
@@ -60,7 +60,7 @@ export const useDocumentManagement = (props?: {
});
};
// 更新文档频率
// Update document frequency
const handleUpdateDocumentFrequency = (
docId: string,
formData: { updateInterval?: number; updateType?: UpdateType },
@@ -85,7 +85,7 @@ export const useDocumentManagement = (props?: {
return updatedDocList;
};
// 回滚文档选择
// Rollback document selection
const rollbackDocumentSelection = () => {
if (prevDocIdRef.current) {
setCurDocId(prevDocIdRef.current);

View File

@@ -19,7 +19,7 @@ import { useState, useEffect } from 'react';
export const useFilePreview = (curDocId: string) => {
const [showOriginalFile, setShowOriginalFile] = useState(false);
// 切换文档时,重置预览状态
// Reset the preview state when switching documents
useEffect(() => {
if (showOriginalFile) {
setShowOriginalFile(false);

View File

@@ -30,10 +30,10 @@ interface UseLevelSegmentsParams {
}
/**
* 处理层级分段数据的 hook
* Hooks for processing hierarchical segmented data
*/
export const useLevelSegments = ({ curDoc }: UseLevelSegmentsParams) => {
// 用于层级分段选中滚动
// Scroll selected for hierarchical segmentation
const [selectionIDs, setSelectionIDs] = useState<string[]>([]);
const { levelSegments, setLevelSegments } = useKnowledgeStore(
@@ -43,33 +43,33 @@ export const useLevelSegments = ({ curDoc }: UseLevelSegmentsParams) => {
})),
);
// 获取层级分段 slice 列表
// Get a list of hierarchical segments and slices
const { content: treeContent, loading: tosLoading } = useTosContent(
curDoc?.chunk_strategy?.chunk_type === ChunkType.LevelChunk
? curDoc?.doc_tree_tos_url
: undefined,
);
// 使用 useMemo 缓存转换后的层级分段数据
// Use useMemo to cache hierarchical segmented data after conversion
const renderLevelSegmentsData = useMemo(
() =>
levelSegments.map(item => createLevelDocumentChunkByLevelSegment(item)),
[levelSegments],
);
// 处理层级分段变更
// Handling hierarchy segmentation changes
const handleLevelSegmentsChange = (chunks: ILevelSegment[]) => {
setLevelSegments(chunks);
};
// 处理删除层级分段
// Handling deletion of hierarchical segmentation
const handleLevelSegmentDelete = (chunk: ILevelSegment) => {
setLevelSegments(
levelSegments.filter(item => item.slice_id !== chunk.slice_id),
);
};
// 初始化时加载层级分段
// Load hierarchical segmentation during initialization
useEffect(() => {
setLevelSegments(withTitle(treeContent?.chunks ?? [], curDoc?.name ?? ''));
}, [treeContent]);

View File

@@ -51,7 +51,7 @@ export const useModals = (props: UseModalsProps): UseModalsReturn => {
const { docId, documentType, documentSource, onDelete, onUpdateFrequency } =
props;
// 删除模态框
// Delete modal box
const { node: deleteModalNode, delete: showDeleteModal } = useDeleteUnitModal(
{
docId,
@@ -61,7 +61,7 @@ export const useModals = (props: UseModalsProps): UseModalsReturn => {
},
);
// 更新频率模态框
// Update frequency mode box
const { node: updateFrequencyModalNode, edit: showUpdateFrequencyModal } =
useUpdateFrequencyModal({
docId,

View File

@@ -18,7 +18,7 @@ import { useShallow } from 'zustand/react/shallow';
import { useKnowledgeStore } from '@coze-data/knowledge-stores';
/**
* 处理文档片段计数的 hook
* Hooks that handle document fragment counting
*/
export const useSliceCounter = () => {
const { dataSetDetail, setDataSetDetail } = useKnowledgeStore(
@@ -28,7 +28,7 @@ export const useSliceCounter = () => {
})),
);
// 处理添加块时更新计数
// Update count when processing added blocks
const handleIncreaseSliceCount = () => {
if (!dataSetDetail) {
return;
@@ -45,7 +45,7 @@ export const useSliceCounter = () => {
});
};
// 处理删除块时更新计数
// Update count when processing deleted blocks
const handleDecreaseSliceCount = () => {
if (!dataSetDetail) {
return;

View File

@@ -35,7 +35,7 @@ import { type ProgressMap } from '@/types';
const FINISH_PROGRESS = 100;
/**
* 创建基础文档块
* Create base document block
*/
export const createBaseDocumentChunkBySliceInfo = (
props: SliceInfo,
@@ -45,7 +45,7 @@ export const createBaseDocumentChunkBySliceInfo = (
});
/**
* 创建层级文档块
* Create hierarchical document blocks
*/
export const createLevelDocumentChunkByLevelSegment = (
props: ILevelSegment,
@@ -57,7 +57,7 @@ export const createLevelDocumentChunkByLevelSegment = (
});
/**
* 获取文档选项
* Get document options
*/
export const getDocumentOptions = (
documentList: DocumentInfo[],

Some files were not shown because too many files have changed in this diff Show More