feat: manually mirror opencoze's code from bytedance
Change-Id: I09a73aadda978ad9511264a756b2ce51f5761adf
This commit is contained in:
@@ -0,0 +1,243 @@
|
||||
/* stylelint-disable declaration-no-important */
|
||||
.photo-list {
|
||||
overflow: auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
height: calc(100vh - 170px);
|
||||
padding: 0 24px;
|
||||
|
||||
.photo-list-spin {
|
||||
flex: 1
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.footer {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 12px 0;
|
||||
|
||||
.spin {
|
||||
width: 100%;
|
||||
height: 60px;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
.card-group {
|
||||
margin-bottom: 25px;
|
||||
}
|
||||
|
||||
|
||||
// Card 整体
|
||||
.card {
|
||||
cursor: auto;
|
||||
width: 222px;
|
||||
height: 258px;
|
||||
border-radius: 8px;
|
||||
|
||||
&:hover {
|
||||
box-shadow: 0 2px 14px 0 rgba(0, 0, 0, 8%);
|
||||
}
|
||||
|
||||
:global {
|
||||
// 固定高度142,超出高度的图片,截取居中部分展示
|
||||
.semi-card-cover {
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
height: 142px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.card-disabled {
|
||||
:global {
|
||||
.semi-card-cover {
|
||||
background: var(--Light-usage-fill---color-fill-0, rgba(46, 46, 57, 4%));
|
||||
border-radius: var(--default, 8px) var(--default, 8px) 0 0;
|
||||
|
||||
svg {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Card 封面
|
||||
.card-cover {
|
||||
cursor: pointer;
|
||||
border-radius: 8px 8px 0 0;
|
||||
|
||||
// 设置最小高度142,保证填满封面
|
||||
img {
|
||||
min-height: 142px;
|
||||
}
|
||||
}
|
||||
|
||||
.prohibit-cover {
|
||||
overflow: hidden;
|
||||
|
||||
font-size: 12px;
|
||||
line-height: 16px; /* 133.333% */
|
||||
color: var(--Light-usage-text---color-text-3, rgba(29, 28, 36, 35%));
|
||||
text-align: center;
|
||||
text-overflow: ellipsis;
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Card 内容区 (title + description)
|
||||
.card-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
|
||||
.photo-name {
|
||||
font-weight: 600;
|
||||
line-height: 20px;
|
||||
color: rgba(29, 28, 35, 100%);
|
||||
}
|
||||
|
||||
.photo-description {
|
||||
height: 32px;
|
||||
font-size: 12px;
|
||||
line-height: 16px;
|
||||
|
||||
.failed-tag {
|
||||
padding: 0 6px;
|
||||
color: rgba(219, 46, 19, 100%);
|
||||
background-color: rgba(255, 224, 210, 100%);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.processing-tag {
|
||||
padding: 0 6px;
|
||||
color: #304cdb;
|
||||
background-color: #d9e2ff;
|
||||
border-radius: 4px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Card 底部栏(时间 + 操作按钮)
|
||||
.card-footer {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
height: 24px;
|
||||
|
||||
.create-time {
|
||||
font-size: 12px;
|
||||
line-height: 16px;
|
||||
color: rgba(28, 29, 35, 35%)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// UI稿的 confirm modal 和 semi 默认的不一样,需要手动调整样式
|
||||
.confirm-modal {
|
||||
:global {
|
||||
.semi-modal-header {
|
||||
margin-bottom: 16px;
|
||||
|
||||
// icon 和 title 的间距
|
||||
.semi-modal-icon-wrapper {
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
// title 颜色
|
||||
.semi-modal-confirm-title-text {
|
||||
color: rgba(29, 28, 35, 100%);
|
||||
}
|
||||
|
||||
// 关闭 icon 的 hover 颜色
|
||||
.semi-button:hover {
|
||||
background-color: rgba(46, 46, 56, 8%);
|
||||
}
|
||||
}
|
||||
|
||||
.semi-modal-body {
|
||||
margin: 0;
|
||||
padding: 16px 0;
|
||||
|
||||
.semi-modal-confirm-content {
|
||||
color: rgba(29, 28, 35, 100%)
|
||||
}
|
||||
}
|
||||
|
||||
.semi-modal-footer button {
|
||||
min-width: 96px;
|
||||
margin-left: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 编辑 photo 信息的弹窗
|
||||
.modal-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 20px;
|
||||
width: 100%;
|
||||
|
||||
// photo 大图展示
|
||||
// 用 flex 解决宽高和内部 image 不一致的问题
|
||||
.photo-large {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
|
||||
.arrow-button {
|
||||
position: absolute;
|
||||
top: 126px;
|
||||
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
padding: 12px;
|
||||
|
||||
color: #1D1C23;
|
||||
|
||||
background-color: rgba(255, 255, 255, 50%);
|
||||
border: none;
|
||||
border-radius: 26px;
|
||||
box-shadow: 0 0 4px 0 rgba(0, 0, 0, 20%), 0 0 1px 0 rgba(0, 0, 0, 20%);
|
||||
|
||||
transition: all 0.3s;
|
||||
|
||||
&:hover {
|
||||
color: #4D53E8;
|
||||
background-color: rgba(255, 255, 255, 80%);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// photo 描述输入框
|
||||
.photo-caption-textarea {
|
||||
position: relative;
|
||||
|
||||
:global {
|
||||
.semi-input-textarea-counter {
|
||||
height: 40px;
|
||||
}
|
||||
}
|
||||
|
||||
.ai-generate-button {
|
||||
position: absolute;
|
||||
bottom: 8px;
|
||||
left: 12px;
|
||||
}
|
||||
|
||||
// 解决 disabled button 样式错位的问题
|
||||
>span {
|
||||
display: inline !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,386 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/* eslint-disable @coze-arch/max-line-per-function */
|
||||
/* eslint-disable react-hooks/exhaustive-deps */
|
||||
/* eslint-disable max-lines-per-function */
|
||||
import { useSearchParams } from 'react-router-dom';
|
||||
import { useEffect, useState, type FC, useRef } from 'react';
|
||||
|
||||
import dayjs from 'dayjs';
|
||||
import classNames from 'classnames';
|
||||
import { DataNamespace, dataReporter } from '@coze-data/reporter';
|
||||
import {
|
||||
useKnowledgeParams,
|
||||
useKnowledgeStore,
|
||||
} from '@coze-data/knowledge-stores';
|
||||
import { REPORT_EVENTS } from '@coze-arch/report-events';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import {
|
||||
Card,
|
||||
CardGroup,
|
||||
Image,
|
||||
Space,
|
||||
Spin,
|
||||
Tooltip,
|
||||
Typography,
|
||||
UIIconButton,
|
||||
UIModal,
|
||||
UIEmpty,
|
||||
} from '@coze-arch/bot-semi';
|
||||
import {
|
||||
IconCloseKnowledge,
|
||||
IconDeleteOutline,
|
||||
IconEdit,
|
||||
IconWaringRed,
|
||||
IconSegmentEmpty,
|
||||
IconImageFailOutlined,
|
||||
} from '@coze-arch/bot-icons';
|
||||
import { DocumentStatus, type PhotoInfo } from '@coze-arch/bot-api/knowledge';
|
||||
import { KnowledgeApi } from '@coze-arch/bot-api';
|
||||
|
||||
import { type ProgressItem, type ProgressMap } from '@/types';
|
||||
import { usePhotoDetailModal } from '@/components/photo-detail-modal';
|
||||
|
||||
import { usePhotoList } from './use-photo-list';
|
||||
|
||||
import styles from './index.module.less';
|
||||
|
||||
export interface ImageKnowledgeWorkspaceProps {
|
||||
progressMap: ProgressMap;
|
||||
}
|
||||
|
||||
export const ImageKnowledgeWorkspace: FC<
|
||||
ImageKnowledgeWorkspaceProps
|
||||
> = props => {
|
||||
const { progressMap } = props;
|
||||
const [_, setSearchParams] = useSearchParams();
|
||||
const params = useKnowledgeParams();
|
||||
const firstAutoOpenEditDocumentId = params.first_auto_open_edit_document_id;
|
||||
const [currentPhotoId, setCurrentPhotoId] = useState<string>('');
|
||||
const [currentHoverCardId, setCurrentHoverCardId] = useState<string>('');
|
||||
|
||||
const dataSetDetail = useKnowledgeStore(state => state.dataSetDetail);
|
||||
const canEdit = useKnowledgeStore(state => state.canEdit);
|
||||
const searchValue = useKnowledgeStore(state => state.searchValue);
|
||||
const photoFilterValue = useKnowledgeStore(state => state.photoFilterValue);
|
||||
const ref = useRef<HTMLDivElement>(null);
|
||||
|
||||
const { data, loading, loadingMore, reloadAsync, noMore } = usePhotoList(
|
||||
{
|
||||
// @ts-expect-error -- linter-disable-autofix
|
||||
datasetID: dataSetDetail?.dataset_id,
|
||||
filterPhotoType: photoFilterValue,
|
||||
searchValue,
|
||||
},
|
||||
{
|
||||
// @ts-expect-error -- linter-disable-autofix
|
||||
isNoMore: d => d?.list.length >= d?.total,
|
||||
target: ref,
|
||||
},
|
||||
);
|
||||
|
||||
const photoList = data?.list;
|
||||
|
||||
const shouldAutoOpenDetailModal = photoList?.find(
|
||||
i => i.document_id === firstAutoOpenEditDocumentId,
|
||||
);
|
||||
|
||||
const previewPhotoList = photoList?.filter(
|
||||
photo => photo.status !== DocumentStatus.AuditFailed,
|
||||
);
|
||||
const curPhoto = previewPhotoList?.find(
|
||||
i => i.document_id === currentPhotoId,
|
||||
);
|
||||
|
||||
const resetUrlQueryParams = () => {
|
||||
setSearchParams((state: URLSearchParams) => {
|
||||
state.delete('action_type');
|
||||
return state;
|
||||
});
|
||||
};
|
||||
|
||||
const { node, open } = usePhotoDetailModal({
|
||||
photo: curPhoto,
|
||||
progressMap,
|
||||
photoList: previewPhotoList,
|
||||
canEdit: !!canEdit,
|
||||
setCurrentPhotoId,
|
||||
reload: reloadAsync,
|
||||
onCancel: () => {
|
||||
// 重置url参数
|
||||
resetUrlQueryParams();
|
||||
},
|
||||
onSubmit: () => {
|
||||
resetUrlQueryParams();
|
||||
},
|
||||
});
|
||||
|
||||
// 手动控制 data 加载时机
|
||||
useEffect(() => {
|
||||
if (dataSetDetail?.dataset_id) {
|
||||
reloadAsync();
|
||||
|
||||
// 重新加载时,回到最顶部
|
||||
ref.current?.scrollTo?.({
|
||||
top: 0,
|
||||
behavior: 'smooth',
|
||||
});
|
||||
}
|
||||
}, [searchValue, photoFilterValue, dataSetDetail?.dataset_id]);
|
||||
|
||||
// 自动打开编辑弹窗
|
||||
useEffect(() => {
|
||||
if (shouldAutoOpenDetailModal) {
|
||||
if (firstAutoOpenEditDocumentId) {
|
||||
setCurrentPhotoId(firstAutoOpenEditDocumentId);
|
||||
}
|
||||
open();
|
||||
}
|
||||
}, [firstAutoOpenEditDocumentId, shouldAutoOpenDetailModal]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className={styles['photo-list']} ref={ref}>
|
||||
<Spin
|
||||
spinning={loading}
|
||||
wrapperClassName={styles['photo-list-spin']}
|
||||
childStyle={{
|
||||
height: '100%',
|
||||
width: '100%',
|
||||
}}
|
||||
>
|
||||
{/* @ts-expect-error -- linter-disable-autofix */}
|
||||
{photoList?.length <= 0 ? (
|
||||
<UIEmpty
|
||||
empty={{
|
||||
icon: <IconSegmentEmpty />,
|
||||
title: I18n.t('query_data_empty'),
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<CardGroup spacing={12} className={styles['card-group']}>
|
||||
{photoList?.map(item => {
|
||||
const {
|
||||
url,
|
||||
document_id,
|
||||
name,
|
||||
update_time,
|
||||
caption: originCaption,
|
||||
status: originStatus,
|
||||
} = item;
|
||||
// 此处使用 progressMap 可以保持不断刷新直至完成
|
||||
// @ts-expect-error -- linter-disable-autofix
|
||||
const status = progressMap[document_id]?.status || originStatus;
|
||||
// 使用 progressMap 获取最新的caption
|
||||
const caption =
|
||||
// @ts-expect-error -- linter-disable-autofix
|
||||
(progressMap[document_id] as ProgressItem & PhotoInfo)
|
||||
?.caption || originCaption;
|
||||
|
||||
const hasCaption =
|
||||
typeof caption === 'string' && Boolean(caption);
|
||||
|
||||
const handleEdit = () => {
|
||||
// @ts-expect-error -- linter-disable-autofix
|
||||
setCurrentPhotoId(document_id);
|
||||
open();
|
||||
};
|
||||
|
||||
const handleDelete = () => {
|
||||
UIModal.error({
|
||||
// 必填参数,统一 confirm modal 的样式
|
||||
className: styles['confirm-modal'],
|
||||
closeIcon: <IconCloseKnowledge />,
|
||||
|
||||
// 自定义参数
|
||||
title: I18n.t('kl2_007'),
|
||||
content: I18n.t(
|
||||
'dataset_detail_table_deleteModel_description',
|
||||
),
|
||||
icon: <IconWaringRed />,
|
||||
cancelText: I18n.t('Cancel'),
|
||||
okText: I18n.t('Delete'),
|
||||
okButtonProps: {
|
||||
type: 'danger',
|
||||
},
|
||||
onOk: async () => {
|
||||
try {
|
||||
await KnowledgeApi.DeleteDocument({
|
||||
// @ts-expect-error -- linter-disable-autofix
|
||||
document_ids: [document_id],
|
||||
});
|
||||
await reloadAsync();
|
||||
} catch (error) {
|
||||
dataReporter.errorEvent(DataNamespace.KNOWLEDGE, {
|
||||
eventName: REPORT_EVENTS.KnowledgeDeleteDocument,
|
||||
error: error as Error,
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const onMouseEnter = () => {
|
||||
// @ts-expect-error -- linter-disable-autofix
|
||||
setCurrentHoverCardId(document_id);
|
||||
};
|
||||
|
||||
const onMouseLeave = () => {
|
||||
setCurrentHoverCardId('');
|
||||
};
|
||||
|
||||
const isHover = currentHoverCardId === document_id;
|
||||
const isAudiFailed =
|
||||
originStatus === DocumentStatus.AuditFailed;
|
||||
const getCaption = () => {
|
||||
// 违规图片
|
||||
if (isAudiFailed) {
|
||||
return (
|
||||
<span>
|
||||
{I18n.t('knowledge_content_illegal_error_msg')}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
// 处理失败
|
||||
if (status === DocumentStatus.Failed) {
|
||||
return (
|
||||
<span className={styles['failed-tag']}>
|
||||
{I18n.t('dataset_process_fail')}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
// 处理中
|
||||
if (status === DocumentStatus.Processing) {
|
||||
return (
|
||||
<span className={styles['processing-tag']}>
|
||||
{I18n.t('datasets_segment_tag_processing')}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
// 已标注
|
||||
if (hasCaption) {
|
||||
return caption;
|
||||
}
|
||||
|
||||
// 未标注
|
||||
return I18n.t('knowledge_photo_016');
|
||||
};
|
||||
|
||||
return (
|
||||
<Card
|
||||
key={document_id}
|
||||
cover={
|
||||
isAudiFailed ? (
|
||||
<div className={styles['prohibit-cover']}>
|
||||
<IconImageFailOutlined size={'extra-small'} />
|
||||
<p>{I18n.t('knowledge_photo_illegal_error_msg')}</p>
|
||||
</div>
|
||||
) : (
|
||||
<Image
|
||||
src={url}
|
||||
// 仅设置宽度,高度会按图片原比例自动缩放
|
||||
width={222}
|
||||
preview={false}
|
||||
onClick={handleEdit}
|
||||
className={styles['card-cover']}
|
||||
/>
|
||||
)
|
||||
}
|
||||
headerLine={false}
|
||||
bodyStyle={{
|
||||
padding: '12px 16px',
|
||||
}}
|
||||
className={classNames(
|
||||
styles.card,
|
||||
isAudiFailed ? styles['card-disabled'] : '',
|
||||
)}
|
||||
>
|
||||
<div
|
||||
onMouseEnter={onMouseEnter}
|
||||
onMouseLeave={onMouseLeave}
|
||||
className={styles['card-content']}
|
||||
>
|
||||
<Typography.Text
|
||||
className={styles['photo-name']}
|
||||
ellipsis={{
|
||||
showTooltip: true,
|
||||
}}
|
||||
>
|
||||
{name}
|
||||
</Typography.Text>
|
||||
<Typography.Paragraph
|
||||
className={styles['photo-description']}
|
||||
ellipsis={{
|
||||
showTooltip: true,
|
||||
rows: 2,
|
||||
}}
|
||||
style={{
|
||||
color: hasCaption
|
||||
? 'rgba(29, 28, 35, 0.6)'
|
||||
: 'rgba(255, 178, 51, 1)',
|
||||
}}
|
||||
>
|
||||
{getCaption()}
|
||||
</Typography.Paragraph>
|
||||
|
||||
<div className={styles['card-footer']}>
|
||||
<Typography.Text className={styles['create-time']}>
|
||||
{/* @ts-expect-error -- linter-disable-autofix */}
|
||||
{dayjs.unix(update_time).format('YYYY-MM-DD HH:mm')}
|
||||
</Typography.Text>
|
||||
{isHover && canEdit ? (
|
||||
<Space spacing={12}>
|
||||
<Tooltip content={I18n.t('Edit')}>
|
||||
<UIIconButton
|
||||
icon={<IconEdit />}
|
||||
disabled={isAudiFailed}
|
||||
onClick={handleEdit}
|
||||
/>
|
||||
</Tooltip>
|
||||
<Tooltip content={I18n.t('Delete')}>
|
||||
<UIIconButton
|
||||
icon={<IconDeleteOutline />}
|
||||
onClick={handleDelete}
|
||||
/>
|
||||
</Tooltip>
|
||||
</Space>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
);
|
||||
})}
|
||||
</CardGroup>
|
||||
)}
|
||||
</Spin>
|
||||
<div className={styles.footer}>
|
||||
{!noMore && (
|
||||
<Spin
|
||||
spinning={loadingMore}
|
||||
tip={I18n.t('loading')}
|
||||
wrapperClassName={styles.spin}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
{node}
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { type InfiniteScrollOptions } from 'ahooks/lib/useInfiniteScroll/types';
|
||||
import { useInfiniteScroll } from 'ahooks';
|
||||
import { DataNamespace, dataReporter } from '@coze-data/reporter';
|
||||
import { KNOWLEDGE_MAX_DOC_SIZE } from '@coze-data/knowledge-modal-base';
|
||||
import { REPORT_EVENTS } from '@coze-arch/report-events';
|
||||
import { type PhotoInfo } from '@coze-arch/bot-api/knowledge';
|
||||
import { KnowledgeApi } from '@coze-arch/bot-api';
|
||||
|
||||
import { FilterPhotoType } from '@/types';
|
||||
|
||||
export interface UsePhotoListParams {
|
||||
datasetID: string;
|
||||
searchValue?: string;
|
||||
filterPhotoType?: FilterPhotoType;
|
||||
}
|
||||
|
||||
interface Result {
|
||||
list: PhotoInfo[];
|
||||
total: number;
|
||||
}
|
||||
|
||||
const PAGE_SIZE = 20;
|
||||
|
||||
export const usePhotoList = (
|
||||
params: UsePhotoListParams,
|
||||
options: InfiniteScrollOptions<Result>,
|
||||
) => {
|
||||
const { datasetID, searchValue, filterPhotoType } = params;
|
||||
|
||||
const fetchPhotoList = async (
|
||||
page: number,
|
||||
pageSize: number,
|
||||
// @ts-expect-error -- linter-disable-autofix
|
||||
): Promise<Result> => {
|
||||
try {
|
||||
const res = await KnowledgeApi.ListPhoto({
|
||||
page: page ?? 1,
|
||||
size: pageSize ?? KNOWLEDGE_MAX_DOC_SIZE,
|
||||
dataset_id: datasetID,
|
||||
filter: {
|
||||
keyword: searchValue,
|
||||
has_caption:
|
||||
filterPhotoType === FilterPhotoType.HasCaption
|
||||
? true
|
||||
: filterPhotoType === FilterPhotoType.NoCaption
|
||||
? false
|
||||
: // 传 undefined 代表返回全部
|
||||
undefined,
|
||||
},
|
||||
});
|
||||
return {
|
||||
list: res.photo_infos || [],
|
||||
total: res.total || 0,
|
||||
};
|
||||
} catch (error) {
|
||||
dataReporter.errorEvent(DataNamespace.KNOWLEDGE, {
|
||||
eventName: REPORT_EVENTS.KnowledgePhotoList,
|
||||
error: error as Error,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return useInfiniteScroll<Result>(
|
||||
async d => {
|
||||
const p = d ? Math.ceil(d.list.length / PAGE_SIZE) + 1 : 1;
|
||||
return fetchPhotoList(p, PAGE_SIZE);
|
||||
},
|
||||
{
|
||||
manual: true,
|
||||
...options,
|
||||
},
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { useState } from 'react';
|
||||
|
||||
import {
|
||||
useDataNavigate,
|
||||
useKnowledgeStore,
|
||||
} from '@coze-data/knowledge-stores';
|
||||
import { OptType } from '@coze-data/knowledge-resource-processor-core';
|
||||
import { getKnowledgeIDEQuery } from '@coze-data/knowledge-common-services/use-case';
|
||||
import { KnowledgeE2e } from '@coze-data/e2e';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import { IconCozArrowDown } from '@coze-arch/bot-icons';
|
||||
import { FormatType } from '@coze-arch/bot-api/knowledge';
|
||||
import { IconCozArrowUp } from '@coze-arch/coze-design/icons';
|
||||
import { Button, Tooltip } from '@coze-arch/coze-design';
|
||||
|
||||
import { ImportKnowledgeSourceMenu } from '@/features/import-knowledge-source-menu';
|
||||
|
||||
import { type ImportKnowledgeSourceButtonProps } from '../module';
|
||||
import {
|
||||
createBtnDisableToolTip,
|
||||
getTableFormatTooltip,
|
||||
getDefaultFormatTooltip,
|
||||
} from './services/use-case/disabled-tooltip';
|
||||
|
||||
export const ImportKnowledgeSourceButton = ({
|
||||
disabledTooltip: disabledTooltipProp,
|
||||
onSourceChange,
|
||||
}: ImportKnowledgeSourceButtonProps) => {
|
||||
const documentList = useKnowledgeStore(state => state.documentList);
|
||||
const dataSetDetail = useKnowledgeStore(state => state.dataSetDetail);
|
||||
const [visible, setVisible] = useState<boolean>(false);
|
||||
const resourceNavigate = useDataNavigate();
|
||||
const disabledTooltip =
|
||||
disabledTooltipProp ?? createBtnDisableToolTip(dataSetDetail, documentList);
|
||||
const query = getKnowledgeIDEQuery() as Record<string, string>;
|
||||
if (disabledTooltip) {
|
||||
return (
|
||||
<Tooltip
|
||||
content={disabledTooltip}
|
||||
arrowPointAtCenter={false}
|
||||
position="top"
|
||||
>
|
||||
<Button
|
||||
data-testid={KnowledgeE2e.SegmentDetailAddBtn}
|
||||
color="hgltplus"
|
||||
disabled
|
||||
iconPosition="right"
|
||||
icon={<IconCozArrowDown className={'text-[12px]'} />}
|
||||
>
|
||||
{I18n.t('knowledg_unit_add_segments')}
|
||||
</Button>
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<ImportKnowledgeSourceMenu
|
||||
onVisibleChange={dropVisible => {
|
||||
setVisible(dropVisible);
|
||||
}}
|
||||
onChange={unitType => {
|
||||
if (onSourceChange) {
|
||||
onSourceChange(unitType);
|
||||
return;
|
||||
}
|
||||
/** 默认跳转到upload */
|
||||
const formatType = dataSetDetail?.format_type;
|
||||
const docID = documentList?.[0]?.document_id;
|
||||
const params: Record<string, string> = {
|
||||
type: unitType,
|
||||
...query,
|
||||
};
|
||||
if (formatType === FormatType.Table && docID) {
|
||||
params.opt = OptType.INCREMENTAL;
|
||||
params.doc_id = docID;
|
||||
}
|
||||
resourceNavigate.upload?.(params);
|
||||
}}
|
||||
triggerComponent={
|
||||
<Button
|
||||
data-testid={KnowledgeE2e.SegmentDetailAddBtn}
|
||||
iconPosition="right"
|
||||
icon={
|
||||
visible ? (
|
||||
<IconCozArrowUp className={'text-[12px]'} />
|
||||
) : (
|
||||
<IconCozArrowDown className={'text-[12px]'} />
|
||||
)
|
||||
}
|
||||
>
|
||||
{I18n.t('knowledg_unit_add_segments')}
|
||||
</Button>
|
||||
}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export {
|
||||
getTableFormatTooltip,
|
||||
getDefaultFormatTooltip,
|
||||
createBtnDisableToolTip,
|
||||
};
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {
|
||||
KNOWLEDGE_MAX_DOC_SIZE,
|
||||
KNOWLEDGE_MAX_SLICE_COUNT,
|
||||
} from '@coze-data/knowledge-modal-base';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import { type Dataset, type DocumentInfo } from '@coze-arch/bot-api/knowledge';
|
||||
import { DocumentStatus, FormatType } from '@coze-arch/bot-api/knowledge';
|
||||
|
||||
/**
|
||||
* 处理表格类型数据集的禁用提示
|
||||
*/
|
||||
export const getTableFormatTooltip = (documentList: DocumentInfo[]): string => {
|
||||
const docInfo = documentList?.[0];
|
||||
if (!docInfo) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if (docInfo.status === DocumentStatus.Processing) {
|
||||
return I18n.t('knowledge_add_content_processing_tips');
|
||||
}
|
||||
|
||||
// @ts-expect-error -- linter-disable-autofix
|
||||
if (docInfo?.slice_count >= KNOWLEDGE_MAX_SLICE_COUNT) {
|
||||
return I18n.t('kl2_002');
|
||||
}
|
||||
|
||||
return '';
|
||||
};
|
||||
|
||||
/**
|
||||
* 处理默认类型数据集的禁用提示
|
||||
*/
|
||||
export const getDefaultFormatTooltip = (dataSetDetail: Dataset): string => {
|
||||
// @ts-expect-error -- linter-disable-autofix
|
||||
if (dataSetDetail?.doc_count >= KNOWLEDGE_MAX_DOC_SIZE) {
|
||||
return I18n.t('kl2_003');
|
||||
}
|
||||
|
||||
if (dataSetDetail?.processing_file_id_list?.length) {
|
||||
return I18n.t('knowledge_add_content_processing_tips');
|
||||
}
|
||||
|
||||
return '';
|
||||
};
|
||||
|
||||
/**
|
||||
* 创建按钮禁用时的提示文本
|
||||
* @param dataSetDetail - 数据集详情
|
||||
* @param documentList - 文档列表
|
||||
* @returns 提示文本
|
||||
*/
|
||||
export const createBtnDisableToolTip = (
|
||||
dataSetDetail: Dataset,
|
||||
documentList: DocumentInfo[],
|
||||
): string => {
|
||||
const formatType = dataSetDetail?.format_type;
|
||||
|
||||
const tooltipHandlers: Record<string, () => string> = {
|
||||
[FormatType.Table]: () => getTableFormatTooltip(documentList),
|
||||
default: () => getDefaultFormatTooltip(dataSetDetail),
|
||||
};
|
||||
|
||||
if (!formatType) {
|
||||
return tooltipHandlers.default();
|
||||
}
|
||||
|
||||
const handler = tooltipHandlers[formatType] || tooltipHandlers.default;
|
||||
return handler();
|
||||
};
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export {
|
||||
getTableFormatTooltip,
|
||||
getDefaultFormatTooltip,
|
||||
createBtnDisableToolTip,
|
||||
} from './disabled-tooltip';
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { useShallow } from 'zustand/react/shallow';
|
||||
import { useKnowledgeParams, useKnowledgeStore } from '@coze-data/knowledge-stores';
|
||||
import { type UnitType } from '@coze-data/knowledge-resource-processor-core';
|
||||
import { useKnowledgeNavigate } from '@coze-data/knowledge-common-hooks/use-case';
|
||||
import { useSpaceStore } from '@coze-arch/bot-studio-store';
|
||||
import { type FormatType } from '@coze-arch/bot-api/knowledge';
|
||||
|
||||
import { getAddContentUrl } from '@/utils';
|
||||
import { ActionType } from '@/types';
|
||||
|
||||
import { type ImportKnowledgeSourceButtonProps } from '../module';
|
||||
import { ImportKnowledgeSourceButton } from '../base';
|
||||
|
||||
export type BizAgentIdeImportKnowledgeSourceButtonProps =
|
||||
ImportKnowledgeSourceButtonProps;
|
||||
|
||||
export const BizAgentIdeImportKnowledgeSourceButton = ({
|
||||
disabledTooltip,
|
||||
}: BizAgentIdeImportKnowledgeSourceButtonProps) => {
|
||||
const navigate = useKnowledgeNavigate();
|
||||
const { documentList, dataSetDetail } = useKnowledgeStore(
|
||||
useShallow(state => ({
|
||||
documentList: state.documentList,
|
||||
dataSetDetail: state.dataSetDetail,
|
||||
})),
|
||||
);
|
||||
const params = useKnowledgeParams();
|
||||
const spaceId = useSpaceStore(item => item.space.id);
|
||||
return (
|
||||
<ImportKnowledgeSourceButton
|
||||
disabledTooltip={disabledTooltip}
|
||||
onSourceChange={unitType => {
|
||||
navigate(
|
||||
getAddContentUrl({
|
||||
spaceID: spaceId as string,
|
||||
datasetID: dataSetDetail?.dataset_id as string,
|
||||
docID: documentList?.[0]?.document_id,
|
||||
formatType: dataSetDetail?.format_type as FormatType,
|
||||
type: unitType as UnitType,
|
||||
pageMode: 'modal',
|
||||
botId: params.botID,
|
||||
actionType: ActionType.ADD,
|
||||
}),
|
||||
);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export interface ImportKnowledgeSourceButtonProps {
|
||||
disabledTooltip?: string;
|
||||
onSourceChange?: (source: string) => void;
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import type { ReactNode } from 'react';
|
||||
|
||||
import { type UnitType } from '@coze-data/knowledge-resource-processor-core';
|
||||
|
||||
import { useKnowledgeIDERegistry } from '../../context/knowledge-ide-registry-context';
|
||||
import { KnowledgeSourceMenu as KnowledgeSourceMenuComponent } from '../../components/knowledge-source-menu';
|
||||
|
||||
export interface ImportKnowledgeSourceMenuProps {
|
||||
triggerComponent?: ReactNode;
|
||||
onVisibleChange?: (visible: boolean) => void;
|
||||
onChange?: (val: UnitType) => void;
|
||||
}
|
||||
|
||||
export const ImportKnowledgeSourceMenu = (
|
||||
props: ImportKnowledgeSourceMenuProps,
|
||||
) => {
|
||||
const { triggerComponent, onVisibleChange, onChange } = props;
|
||||
const { importKnowledgeMenuSourceFeatureRegistry } =
|
||||
useKnowledgeIDERegistry();
|
||||
|
||||
return (
|
||||
<KnowledgeSourceMenuComponent
|
||||
triggerComponent={triggerComponent}
|
||||
onVisibleChange={onVisibleChange}
|
||||
>
|
||||
{importKnowledgeMenuSourceFeatureRegistry
|
||||
?.entries()
|
||||
.map(([key, { Component }]) => (
|
||||
<Component key={key} onClick={value => onChange?.(value)} />
|
||||
))}
|
||||
</KnowledgeSourceMenuComponent>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { ImageLocalModule } from '@/features/import-knowledge-sources/radio/image-local';
|
||||
import {
|
||||
createImportKnowledgeSourceRadioFeatureRegistry,
|
||||
type ImportKnowledgeRadioSourceFeatureRegistry,
|
||||
} from '@/features/import-knowledge-sources/radio';
|
||||
|
||||
export const importImageKnowledgeSourceRadioGroupContributes: ImportKnowledgeRadioSourceFeatureRegistry =
|
||||
(() => {
|
||||
const importKnowledgeRadioSourceFeatureRegistry =
|
||||
createImportKnowledgeSourceRadioFeatureRegistry(
|
||||
'import-knowledge-source-image-radio-group',
|
||||
);
|
||||
importKnowledgeRadioSourceFeatureRegistry.registerSome([
|
||||
{
|
||||
type: 'image-local',
|
||||
module: ImageLocalModule,
|
||||
},
|
||||
]);
|
||||
return importKnowledgeRadioSourceFeatureRegistry;
|
||||
})();
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { TableLocalModule } from '@coze-data/knowledge-ide-base/features/import-knowledge-sources/radio/table-local';
|
||||
import {
|
||||
createImportKnowledgeSourceRadioFeatureRegistry,
|
||||
type ImportKnowledgeRadioSourceFeatureRegistry,
|
||||
} from '@coze-data/knowledge-ide-base/features/import-knowledge-sources/radio';
|
||||
import { TableCustomModule } from '@coze-data/knowledge-ide-base/features/import-knowledge-sources/radio';
|
||||
|
||||
export const importTableKnowledgeSourceRadioGroupContributes: ImportKnowledgeRadioSourceFeatureRegistry =
|
||||
(() => {
|
||||
const importKnowledgeRadioSourceFeatureRegistry =
|
||||
createImportKnowledgeSourceRadioFeatureRegistry(
|
||||
'import-knowledge-source-table-radio-group',
|
||||
);
|
||||
importKnowledgeRadioSourceFeatureRegistry.registerSome([
|
||||
{
|
||||
type: 'table-local',
|
||||
module: TableLocalModule,
|
||||
},
|
||||
{
|
||||
type: 'table-custom',
|
||||
module: TableCustomModule,
|
||||
},
|
||||
]);
|
||||
return importKnowledgeRadioSourceFeatureRegistry;
|
||||
})();
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {
|
||||
createImportKnowledgeSourceRadioFeatureRegistry,
|
||||
type ImportKnowledgeRadioSourceFeatureRegistry,
|
||||
} from '@coze-data/knowledge-ide-base/features/import-knowledge-sources/radio';
|
||||
import {
|
||||
TextCustomModule,
|
||||
TextLocalModule,
|
||||
} from '@coze-data/knowledge-ide-base/features/import-knowledge-sources/radio';
|
||||
|
||||
export const importTextKnowledgeSourceRadioGroupContributes: ImportKnowledgeRadioSourceFeatureRegistry =
|
||||
(() => {
|
||||
const importKnowledgeRadioSourceFeatureRegistry =
|
||||
createImportKnowledgeSourceRadioFeatureRegistry(
|
||||
'import-knowledge-source-text-radio-group',
|
||||
);
|
||||
importKnowledgeRadioSourceFeatureRegistry.registerSome([
|
||||
{
|
||||
type: 'text-local',
|
||||
module: TextLocalModule,
|
||||
},
|
||||
{
|
||||
type: 'text-custom',
|
||||
module: TextCustomModule,
|
||||
},
|
||||
]);
|
||||
return importKnowledgeRadioSourceFeatureRegistry;
|
||||
})();
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { useMemo } from 'react';
|
||||
|
||||
import { type UnitType } from '@coze-data/knowledge-resource-processor-core';
|
||||
import { FormatType } from '@coze-arch/bot-api/knowledge';
|
||||
|
||||
import { type ImportKnowledgeRadioSourceFeatureRegistry } from '../import-knowledge-sources/radio/registry';
|
||||
import { KnowledgeSourceRadioGroup as KnowledgeSourceRadioGroupComponent } from '../../components/knowledge-source-radio-group';
|
||||
import { importTextKnowledgeSourceRadioGroupContributes } from './import-text-knowledge-source-contributes';
|
||||
import { importTableKnowledgeSourceRadioGroupContributes } from './import-table-knowledge-source-contributes';
|
||||
import { importImageKnowledgeSourceRadioGroupContributes } from './import-image-knowledge-source-contributes';
|
||||
|
||||
export interface ImportKnowledgeSourceRadioGroupProps {
|
||||
formatType: FormatType;
|
||||
value?: UnitType;
|
||||
importKnowledgeSourceRegistry: ImportKnowledgeRadioSourceFeatureRegistry;
|
||||
onChange?: (val: UnitType) => void;
|
||||
}
|
||||
|
||||
export const ImportKnowledgeSourceRadioGroup = (
|
||||
props: ImportKnowledgeSourceRadioGroupProps,
|
||||
) => {
|
||||
const { value, onChange, formatType } = props;
|
||||
const importKnowledgeSourceRegistry = useMemo(() => {
|
||||
if (formatType === FormatType.Text) {
|
||||
return importTextKnowledgeSourceRadioGroupContributes;
|
||||
}
|
||||
if (formatType === FormatType.Table) {
|
||||
return importTableKnowledgeSourceRadioGroupContributes;
|
||||
}
|
||||
if (formatType === FormatType.Image) {
|
||||
return importImageKnowledgeSourceRadioGroupContributes;
|
||||
}
|
||||
}, [formatType]);
|
||||
if (!importKnowledgeSourceRegistry) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<KnowledgeSourceRadioGroupComponent
|
||||
value={value}
|
||||
onChange={e => {
|
||||
onChange?.(e.target.value);
|
||||
}}
|
||||
>
|
||||
{importKnowledgeSourceRegistry.entries().map(([key, { Component }]) => (
|
||||
<Component key={key} />
|
||||
))}
|
||||
</KnowledgeSourceRadioGroupComponent>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { UnitType } from '@coze-data/knowledge-resource-processor-core';
|
||||
import { KnowledgeE2e } from '@coze-data/e2e';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import { IconCozDocument } from '@coze-arch/coze-design/icons';
|
||||
|
||||
import { KnowledgeSourceMenuItem } from '@/components/knowledge-source-menu-item';
|
||||
|
||||
import {
|
||||
type ImportKnowledgeMenuSourceModule,
|
||||
type ImportKnowledgeMenuSourceModuleProps,
|
||||
} from '../module';
|
||||
|
||||
export const ImageLocal = (props: ImportKnowledgeMenuSourceModuleProps) => {
|
||||
const { onClick } = props;
|
||||
return (
|
||||
<KnowledgeSourceMenuItem
|
||||
title={I18n.t('knowledge_photo_002')}
|
||||
icon={<IconCozDocument className="w-4 h-4" />}
|
||||
testId={`${KnowledgeE2e.SegmentDetailDropdownItem}.${UnitType.IMAGE_FILE}`}
|
||||
value={UnitType.IMAGE_FILE}
|
||||
onClick={() => onClick(UnitType.IMAGE_FILE)}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export const ImageLocalModule: ImportKnowledgeMenuSourceModule = {
|
||||
Component: ImageLocal,
|
||||
};
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export { TableCustomModule } from './table-custom';
|
||||
export { TableLocalModule } from './table-local';
|
||||
export { TextCustomModule } from './text-custom';
|
||||
export { TextLocalModule } from './text-local';
|
||||
export { ImageLocalModule } from './image-local';
|
||||
export type {
|
||||
ImportKnowledgeMenuSourceModuleProps,
|
||||
ImportKnowledgeMenuSourceModule,
|
||||
} from './module';
|
||||
export {
|
||||
createImportKnowledgeMenuSourceFeatureRegistry,
|
||||
type ImportKnowledgeMenuSourceFeatureType,
|
||||
type ImportKnowledgeMenuSourceRegistry,
|
||||
} from './registry';
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import type { UnitType } from '@coze-data/knowledge-resource-processor-core';
|
||||
|
||||
export interface ImportKnowledgeMenuSourceModuleProps {
|
||||
onClick: (item: UnitType) => void;
|
||||
}
|
||||
|
||||
export interface ImportKnowledgeMenuSourceModule {
|
||||
Component: React.ComponentType<ImportKnowledgeMenuSourceModuleProps>;
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { FeatureRegistry } from '@coze-data/feature-register';
|
||||
|
||||
import { type ImportKnowledgeMenuSourceModule } from './module';
|
||||
|
||||
export type ImportKnowledgeMenuSourceFeatureType =
|
||||
| 'text-local'
|
||||
| 'text-custom'
|
||||
| 'table-custom'
|
||||
| 'table-local'
|
||||
| 'image-local'
|
||||
| 'image-custom';
|
||||
|
||||
export type ImportKnowledgeMenuSourceRegistry = FeatureRegistry<
|
||||
ImportKnowledgeMenuSourceFeatureType,
|
||||
ImportKnowledgeMenuSourceModule
|
||||
>;
|
||||
|
||||
export const createImportKnowledgeMenuSourceFeatureRegistry = (
|
||||
name: string,
|
||||
): ImportKnowledgeMenuSourceRegistry =>
|
||||
new FeatureRegistry<
|
||||
ImportKnowledgeMenuSourceFeatureType,
|
||||
ImportKnowledgeMenuSourceModule
|
||||
>({
|
||||
name,
|
||||
});
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { UnitType } from '@coze-data/knowledge-resource-processor-core';
|
||||
import { KnowledgeE2e } from '@coze-data/e2e';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import { IconCozPencilPaper } from '@coze-arch/coze-design/icons';
|
||||
|
||||
import { KnowledgeSourceMenuItem } from '@/components/knowledge-source-menu-item';
|
||||
|
||||
import {
|
||||
type ImportKnowledgeMenuSourceModule,
|
||||
type ImportKnowledgeMenuSourceModuleProps,
|
||||
} from '../module';
|
||||
|
||||
export const TableCustom = (props: ImportKnowledgeMenuSourceModuleProps) => {
|
||||
const { onClick } = props;
|
||||
return (
|
||||
<KnowledgeSourceMenuItem
|
||||
title={I18n.t('datasets_createFileModel_step1_TabCustomTitle')}
|
||||
icon={<IconCozPencilPaper className="w-4 h-4" />}
|
||||
testId={`${KnowledgeE2e.SegmentDetailDropdownItem}.${UnitType.TABLE_CUSTOM}`}
|
||||
value={UnitType.TABLE_CUSTOM}
|
||||
onClick={() => onClick(UnitType.TABLE_CUSTOM)}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export const TableCustomModule: ImportKnowledgeMenuSourceModule = {
|
||||
Component: TableCustom,
|
||||
};
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { UnitType } from '@coze-data/knowledge-resource-processor-core';
|
||||
import { KnowledgeE2e } from '@coze-data/e2e';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import { IconCozDocument } from '@coze-arch/coze-design/icons';
|
||||
|
||||
import { KnowledgeSourceMenuItem } from '@/components/knowledge-source-menu-item';
|
||||
|
||||
import {
|
||||
type ImportKnowledgeMenuSourceModule,
|
||||
type ImportKnowledgeMenuSourceModuleProps,
|
||||
} from '../module';
|
||||
|
||||
export const TableLocal = (props: ImportKnowledgeMenuSourceModuleProps) => {
|
||||
const { onClick } = props;
|
||||
return (
|
||||
<KnowledgeSourceMenuItem
|
||||
title={I18n.t('datasets_createFileModel_step1_TabLocalTitle')}
|
||||
icon={<IconCozDocument className="w-4 h-4" />}
|
||||
testId={`${KnowledgeE2e.SegmentDetailDropdownItem}.${UnitType.TABLE_DOC}`}
|
||||
value={UnitType.TABLE_DOC}
|
||||
onClick={() => onClick(UnitType.TABLE_DOC)}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export const TableLocalModule: ImportKnowledgeMenuSourceModule = {
|
||||
Component: TableLocal,
|
||||
};
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { UnitType } from '@coze-data/knowledge-resource-processor-core';
|
||||
import { KnowledgeE2e } from '@coze-data/e2e';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import { IconCozPencilPaper } from '@coze-arch/coze-design/icons';
|
||||
|
||||
import { KnowledgeSourceMenuItem } from '@/components/knowledge-source-menu-item';
|
||||
|
||||
import {
|
||||
type ImportKnowledgeMenuSourceModule,
|
||||
type ImportKnowledgeMenuSourceModuleProps,
|
||||
} from '../module';
|
||||
|
||||
export const TextCustom = (props: ImportKnowledgeMenuSourceModuleProps) => {
|
||||
const { onClick } = props;
|
||||
return (
|
||||
<KnowledgeSourceMenuItem
|
||||
title={I18n.t('datasets_createFileModel_step1_CustomTitle')}
|
||||
icon={<IconCozPencilPaper className="w-4 h-4" />}
|
||||
testId={`${KnowledgeE2e.SegmentDetailDropdownItem}.${UnitType.TEXT_CUSTOM}`}
|
||||
value={UnitType.TEXT_CUSTOM}
|
||||
onClick={() => onClick(UnitType.TEXT_CUSTOM)}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export const TextCustomModule: ImportKnowledgeMenuSourceModule = {
|
||||
Component: TextCustom,
|
||||
};
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { UnitType } from '@coze-data/knowledge-resource-processor-core';
|
||||
import { KnowledgeE2e } from '@coze-data/e2e';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import { IconCozDocument } from '@coze-arch/coze-design/icons';
|
||||
|
||||
import { KnowledgeSourceMenuItem } from '@/components/knowledge-source-menu-item';
|
||||
|
||||
import {
|
||||
type ImportKnowledgeMenuSourceModule,
|
||||
type ImportKnowledgeMenuSourceModuleProps,
|
||||
} from '../module';
|
||||
|
||||
export const TextLocal = (props: ImportKnowledgeMenuSourceModuleProps) => {
|
||||
const { onClick } = props;
|
||||
return (
|
||||
<KnowledgeSourceMenuItem
|
||||
title={I18n.t('datasets_createFileModel_step1_LocalTitle')}
|
||||
icon={<IconCozDocument className="w-4 h-4" />}
|
||||
testId={`${KnowledgeE2e.SegmentDetailDropdownItem}.${UnitType.TEXT_DOC}`}
|
||||
value={UnitType.TEXT_DOC}
|
||||
onClick={() => onClick(UnitType.TEXT_DOC)}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export const TextLocalModule: ImportKnowledgeMenuSourceModule = {
|
||||
Component: TextLocal,
|
||||
};
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { UnitType } from '@coze-data/knowledge-resource-processor-core';
|
||||
import { KnowledgeE2e } from '@coze-data/e2e';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import { IconCozDocument } from '@coze-arch/coze-design/icons';
|
||||
|
||||
import { KnowledgeSourceRadio } from '@/components/knowledge-source-radio';
|
||||
|
||||
import { type ImportKnowledgeRadioSourceModule } from '../module';
|
||||
|
||||
export const ImageLocal: ImportKnowledgeRadioSourceModule['Component'] = () => (
|
||||
<KnowledgeSourceRadio
|
||||
title={I18n.t('knowledge_photo_002')}
|
||||
description={I18n.t('knowledge_photo_003')}
|
||||
icon={<IconCozDocument className="w-4 h-4" />}
|
||||
e2e={KnowledgeE2e.CreateKnowledgeModalPhotoImgRadio}
|
||||
key={UnitType.IMAGE_FILE}
|
||||
value={UnitType.IMAGE_FILE}
|
||||
/>
|
||||
);
|
||||
|
||||
export const ImageLocalModule: ImportKnowledgeRadioSourceModule = {
|
||||
Component: ImageLocal,
|
||||
};
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export { TableCustomModule } from './table-custom';
|
||||
export { TableLocalModule } from './table-local';
|
||||
export { TextCustomModule } from './text-custom';
|
||||
export { TextLocalModule } from './text-local';
|
||||
export { ImageLocalModule } from './image-local';
|
||||
export type { ImportKnowledgeRadioSourceModule } from './module';
|
||||
export {
|
||||
createImportKnowledgeSourceRadioFeatureRegistry,
|
||||
type ImportKnowledgeRadioSourceFeatureType,
|
||||
ImportKnowledgeRadioSourceFeatureRegistry,
|
||||
} from './registry';
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import type { ComponentProps, ReactElement } from 'react';
|
||||
|
||||
import type { KnowledgeSourceRadio } from '@/components/knowledge-source-radio';
|
||||
|
||||
export interface ImportKnowledgeRadioSourceModule {
|
||||
Component: () => ReactElement<
|
||||
ComponentProps<typeof KnowledgeSourceRadio>
|
||||
> | null;
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { FeatureRegistry } from '@coze-data/feature-register';
|
||||
|
||||
import { TextLocalModule } from './text-local';
|
||||
import { type ImportKnowledgeRadioSourceModule } from './module';
|
||||
|
||||
export type ImportKnowledgeRadioSourceFeatureType =
|
||||
| 'text-local'
|
||||
| 'text-custom'
|
||||
| 'table-custom'
|
||||
| 'table-local'
|
||||
| 'image-local'
|
||||
| 'image-custom';
|
||||
|
||||
export type ImportKnowledgeRadioSourceFeatureRegistry = FeatureRegistry<
|
||||
ImportKnowledgeRadioSourceFeatureType,
|
||||
ImportKnowledgeRadioSourceModule
|
||||
>;
|
||||
|
||||
export const createImportKnowledgeSourceRadioFeatureRegistry = (
|
||||
name: string,
|
||||
): ImportKnowledgeRadioSourceFeatureRegistry =>
|
||||
new FeatureRegistry<
|
||||
ImportKnowledgeRadioSourceFeatureType,
|
||||
ImportKnowledgeRadioSourceModule
|
||||
>({
|
||||
name,
|
||||
defaultFeature: {
|
||||
type: 'text-local',
|
||||
module: TextLocalModule,
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { UnitType } from '@coze-data/knowledge-resource-processor-core';
|
||||
import { KnowledgeE2e } from '@coze-data/e2e';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import { IconCozPencilPaper } from '@coze-arch/coze-design/icons';
|
||||
|
||||
import { KnowledgeSourceRadio } from '@/components/knowledge-source-radio';
|
||||
|
||||
import { type ImportKnowledgeRadioSourceModule } from '../module';
|
||||
|
||||
export const TableCustom: ImportKnowledgeRadioSourceModule['Component'] =
|
||||
() => (
|
||||
<KnowledgeSourceRadio
|
||||
title={I18n.t('datasets_createFileModel_step1_TabCustomTitle')}
|
||||
description={I18n.t(
|
||||
'datasets_createFileModel_step1_TabCustomDescription',
|
||||
)}
|
||||
icon={<IconCozPencilPaper className="w-4 h-4" />}
|
||||
e2e={KnowledgeE2e.CreateKnowledgeModalTableCustomRadio}
|
||||
key={UnitType.TABLE_CUSTOM}
|
||||
value={UnitType.TABLE_CUSTOM}
|
||||
/>
|
||||
);
|
||||
|
||||
export const TableCustomModule: ImportKnowledgeRadioSourceModule = {
|
||||
Component: TableCustom,
|
||||
};
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import { IconCozDocument } from '@coze-arch/coze-design/icons';
|
||||
import { UnitType } from '@coze-data/knowledge-resource-processor-core';
|
||||
import { KnowledgeE2e } from '@coze-data/e2e';
|
||||
|
||||
import { KnowledgeSourceRadio } from '@/components/knowledge-source-radio';
|
||||
import { type ImportKnowledgeRadioSourceModule } from '../module';
|
||||
|
||||
export const TableLocal: ImportKnowledgeRadioSourceModule['Component'] = () => (
|
||||
<KnowledgeSourceRadio
|
||||
title={I18n.t('datasets_createFileModel_step1_TabLocalTitle')}
|
||||
description={I18n.t('datasets_createFileModel_step1_TabLocalDescription')}
|
||||
icon={<IconCozDocument className="w-4 h-4" />}
|
||||
e2e={KnowledgeE2e.CreateKnowledgeModalTableLocalRadio}
|
||||
key={UnitType.TABLE_DOC}
|
||||
value={UnitType.TABLE_DOC}
|
||||
/>
|
||||
);
|
||||
|
||||
export const TableLocalModule: ImportKnowledgeRadioSourceModule = {
|
||||
Component: TableLocal,
|
||||
};
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import { IconCozPencilPaper } from '@coze-arch/coze-design/icons';
|
||||
import { UnitType } from '@coze-data/knowledge-resource-processor-core';
|
||||
import { KnowledgeE2e } from '@coze-data/e2e';
|
||||
|
||||
import { type ImportKnowledgeRadioSourceModule } from '../module';
|
||||
import { KnowledgeSourceRadio } from '@/components/knowledge-source-radio';
|
||||
|
||||
export const TextCustom: ImportKnowledgeRadioSourceModule['Component'] = () => (
|
||||
<KnowledgeSourceRadio
|
||||
title={I18n.t('datasets_createFileModel_step1_CustomTitle')}
|
||||
description={I18n.t('datasets_createFileModel_step1_CustomDescription')}
|
||||
icon={<IconCozPencilPaper className="w-4 h-4" />}
|
||||
e2e={KnowledgeE2e.CreateKnowledgeModalTextCustomRadio}
|
||||
key={UnitType.TEXT_CUSTOM}
|
||||
value={UnitType.TEXT_CUSTOM}
|
||||
/>
|
||||
);
|
||||
|
||||
export const TextCustomModule: ImportKnowledgeRadioSourceModule = {
|
||||
Component: TextCustom,
|
||||
};
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { UnitType } from '@coze-data/knowledge-resource-processor-core';
|
||||
import { KnowledgeE2e } from '@coze-data/e2e';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import { IconCozDocument } from '@coze-arch/coze-design/icons';
|
||||
|
||||
import { KnowledgeSourceRadio } from '@/components/knowledge-source-radio';
|
||||
import { type ImportKnowledgeRadioSourceModule } from '../module';
|
||||
|
||||
export const TextLocal: ImportKnowledgeRadioSourceModule['Component'] = () => (
|
||||
<KnowledgeSourceRadio
|
||||
title={I18n.t('datasets_createFileModel_step1_LocalTitle')}
|
||||
description={I18n.t('datasets_createFileModel_step1_LocalDescription')}
|
||||
icon={<IconCozDocument className="w-4 h-4" />}
|
||||
e2e={KnowledgeE2e.CreateKnowledgeModalTextLocalRadio}
|
||||
key={UnitType.TEXT_DOC}
|
||||
value={UnitType.TEXT_DOC}
|
||||
/>
|
||||
);
|
||||
|
||||
export const TextLocalModule: ImportKnowledgeRadioSourceModule = {
|
||||
Component: TextLocal,
|
||||
};
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { useDataNavigate } from '@coze-data/knowledge-stores';
|
||||
import { OptType } from '@coze-data/knowledge-resource-processor-core';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import { UpdateType } from '@coze-arch/bot-api/knowledge';
|
||||
import { Menu } from '@coze-arch/coze-design';
|
||||
|
||||
import {
|
||||
type TableConfigMenuModule,
|
||||
type TableConfigMenuModuleProps,
|
||||
} from '../module';
|
||||
|
||||
export const ConfigurationTableStructure = (
|
||||
props: TableConfigMenuModuleProps,
|
||||
) => {
|
||||
const { documentInfo } = props;
|
||||
const resourceNavigate = useDataNavigate();
|
||||
|
||||
if (
|
||||
documentInfo.update_type !== undefined &&
|
||||
documentInfo.update_type !== UpdateType.NoUpdate
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const handleClick = () => {
|
||||
resourceNavigate.upload?.({
|
||||
type: 'table',
|
||||
opt: OptType.RESEGMENT,
|
||||
doc_id: documentInfo?.document_id ?? '',
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<Menu.Item onClick={handleClick}>
|
||||
{I18n.t('knowledge_segment_config_table')}
|
||||
</Menu.Item>
|
||||
);
|
||||
};
|
||||
export const ConfigurationTableStructureModule: TableConfigMenuModule = {
|
||||
Component: ConfigurationTableStructure,
|
||||
};
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export {
|
||||
createTableConfigMenuRegistry,
|
||||
type TableConfigMenuRegistry,
|
||||
type TableConfigMenuFeatureType,
|
||||
} from './registry';
|
||||
export {
|
||||
type TableConfigMenuModule,
|
||||
type TableConfigMenuModuleProps,
|
||||
} from './module';
|
||||
export { ConfigurationTableStructureModule } from './configuration-table-structure';
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import type { DocumentInfo } from '@coze-arch/bot-api/knowledge';
|
||||
export interface TableConfigMenuModuleProps {
|
||||
documentInfo: DocumentInfo;
|
||||
reload?: () => void;
|
||||
onChangeDocList?: (docList: DocumentInfo[]) => void;
|
||||
}
|
||||
|
||||
export interface TableConfigMenuModule {
|
||||
Component: React.ComponentType<TableConfigMenuModuleProps>;
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { FeatureRegistry } from '@coze-data/feature-register';
|
||||
|
||||
import { type TableConfigMenuModule } from './module';
|
||||
|
||||
export type TableConfigMenuFeatureType =
|
||||
| 'configuration-table-structure'
|
||||
| 'update-frequency'
|
||||
| 'fetch-slice'
|
||||
| 'view-source';
|
||||
|
||||
export type TableConfigMenuRegistry = FeatureRegistry<
|
||||
TableConfigMenuFeatureType,
|
||||
TableConfigMenuModule
|
||||
>;
|
||||
|
||||
export const createTableConfigMenuRegistry = (
|
||||
name: string,
|
||||
): TableConfigMenuRegistry =>
|
||||
new FeatureRegistry<TableConfigMenuFeatureType, TableConfigMenuModule>({
|
||||
name,
|
||||
});
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { useKnowledgeStore } from '@coze-data/knowledge-stores';
|
||||
import { type DocumentInfo } from '@coze-arch/bot-api/knowledge';
|
||||
|
||||
import { useReloadKnowledgeIDE } from '@/hooks/use-case/use-reload-knowledge-ide';
|
||||
|
||||
import { type TableConfigMenuRegistry } from '../../knowledge-ide-table-config-menus';
|
||||
import { KnowledgeConfigMenu as KnowledgeConfigMenuComponent } from '../../../components/knowledge-config-menu';
|
||||
|
||||
export interface TableConfigButtonProps {
|
||||
knowledgeTableConfigMenuContributes?: TableConfigMenuRegistry;
|
||||
onChangeDocList?: (docList: DocumentInfo[]) => void;
|
||||
}
|
||||
|
||||
export const TableConfigButton = (props: TableConfigButtonProps) => {
|
||||
const { knowledgeTableConfigMenuContributes, onChangeDocList } = props;
|
||||
const documentList = useKnowledgeStore(state => state.documentList);
|
||||
const documentInfo = documentList?.[0];
|
||||
const canEdit = useKnowledgeStore(state => state.canEdit);
|
||||
const { reload } = useReloadKnowledgeIDE();
|
||||
|
||||
if (!knowledgeTableConfigMenuContributes) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<KnowledgeConfigMenuComponent>
|
||||
{canEdit
|
||||
? knowledgeTableConfigMenuContributes
|
||||
?.entries()
|
||||
.map(([key, { Component }]) => (
|
||||
<Component
|
||||
key={key}
|
||||
documentInfo={documentInfo}
|
||||
onChangeDocList={onChangeDocList}
|
||||
reload={reload}
|
||||
/>
|
||||
))
|
||||
: null}
|
||||
</KnowledgeConfigMenuComponent>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { useMemo } from 'react';
|
||||
|
||||
import { useKnowledgeStore } from '@coze-data/knowledge-stores';
|
||||
import { UnitType } from '@coze-data/knowledge-resource-processor-core';
|
||||
import { FormatType } from '@coze-arch/bot-api/knowledge';
|
||||
|
||||
import { getUnitType } from '@/utils';
|
||||
|
||||
import { TableLocalTableConfigButton } from './table-local';
|
||||
import { TableCustomTableConfigButton } from './table-custom';
|
||||
import { type TableConfigButtonProps } from './base';
|
||||
export const KnowledgeIDETableConfig = (props: TableConfigButtonProps) => {
|
||||
const documentInfo = useKnowledgeStore(state => state.documentList?.[0]);
|
||||
const unitType = useMemo(() => {
|
||||
if (documentInfo) {
|
||||
return getUnitType({
|
||||
format_type: FormatType.Table,
|
||||
source_type: documentInfo?.source_type,
|
||||
});
|
||||
}
|
||||
return UnitType.TABLE_API;
|
||||
}, [documentInfo]);
|
||||
if (unitType === UnitType.TABLE_CUSTOM) {
|
||||
return <TableCustomTableConfigButton {...props} />;
|
||||
}
|
||||
if (unitType === UnitType.TABLE_DOC) {
|
||||
return <TableLocalTableConfigButton {...props} />;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { TableConfigButton, type TableConfigButtonProps } from '../base';
|
||||
import { knowledgeTableConfigMenuContributes } from './knowledge-ide-table-config-menu-contributes';
|
||||
export const TableCustomTableConfigButton = (props: TableConfigButtonProps) => (
|
||||
<TableConfigButton
|
||||
{...props}
|
||||
knowledgeTableConfigMenuContributes={knowledgeTableConfigMenuContributes}
|
||||
/>
|
||||
);
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {
|
||||
ConfigurationTableStructureModule,
|
||||
createTableConfigMenuRegistry,
|
||||
type TableConfigMenuRegistry,
|
||||
} from '@/features/knowledge-ide-table-config-menus';
|
||||
|
||||
export const knowledgeTableConfigMenuContributes: TableConfigMenuRegistry =
|
||||
(() => {
|
||||
const knowledgeTableConfigMenuRegistry = createTableConfigMenuRegistry(
|
||||
'knowledge-ide-table-custom-config-menu',
|
||||
);
|
||||
knowledgeTableConfigMenuRegistry.registerSome([
|
||||
{
|
||||
type: 'configuration-table-structure',
|
||||
module: ConfigurationTableStructureModule,
|
||||
},
|
||||
]);
|
||||
return knowledgeTableConfigMenuRegistry;
|
||||
})();
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { TableConfigButton, type TableConfigButtonProps } from '../base';
|
||||
import { knowledgeTableLocalConfigMenuContributes } from './knowledge-ide-table-config-menu-contributes';
|
||||
export const TableLocalTableConfigButton = (props: TableConfigButtonProps) => (
|
||||
<TableConfigButton
|
||||
{...props}
|
||||
knowledgeTableConfigMenuContributes={
|
||||
knowledgeTableLocalConfigMenuContributes
|
||||
}
|
||||
/>
|
||||
);
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {
|
||||
ConfigurationTableStructureModule,
|
||||
createTableConfigMenuRegistry,
|
||||
type TableConfigMenuRegistry,
|
||||
} from '@/features/knowledge-ide-table-config-menus';
|
||||
|
||||
export const knowledgeTableLocalConfigMenuContributes: TableConfigMenuRegistry =
|
||||
(() => {
|
||||
const knowledgeTableConfigMenuRegistry = createTableConfigMenuRegistry(
|
||||
'knowledge-ide-table-local-config-menu',
|
||||
);
|
||||
knowledgeTableConfigMenuRegistry.registerSome([
|
||||
{
|
||||
type: 'configuration-table-structure',
|
||||
module: ConfigurationTableStructureModule,
|
||||
},
|
||||
]);
|
||||
return knowledgeTableConfigMenuRegistry;
|
||||
})();
|
||||
@@ -0,0 +1,275 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
import { useKnowledgeParams } from '@coze-data/knowledge-stores';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import { SceneType, usePageJumpService } from '@coze-arch/bot-hooks';
|
||||
import {
|
||||
type Knowledge,
|
||||
type GetDraftBotInfoAgwData,
|
||||
type KnowledgeInfo,
|
||||
ReferenceUpdateType,
|
||||
BotMode,
|
||||
} from '@coze-arch/bot-api/playground_api';
|
||||
import {
|
||||
type Dataset,
|
||||
DatasetStatus,
|
||||
StorageLocation,
|
||||
} from '@coze-arch/bot-api/knowledge';
|
||||
import { PlaygroundApi } from '@coze-arch/bot-api';
|
||||
import { Toast, Button } from '@coze-arch/coze-design';
|
||||
|
||||
import { ActionType } from '@/types';
|
||||
|
||||
type BotDataset =
|
||||
| Knowledge
|
||||
| {
|
||||
dataset: KnowledgeInfo[];
|
||||
};
|
||||
|
||||
interface UpdateDatasetForBot {
|
||||
botId: string;
|
||||
agentId: string;
|
||||
dataset: BotDataset;
|
||||
updatedDatasetList?: KnowledgeInfo[];
|
||||
spaceId: string;
|
||||
|
||||
dataSetDetail?: Dataset;
|
||||
}
|
||||
export const useFetchBotInfo = (spaceId, botId) => {
|
||||
const [botInfo, setBotInfo] = useState<GetDraftBotInfoAgwData>();
|
||||
const fetchBotInfo = async () => {
|
||||
try {
|
||||
const { data } = await PlaygroundApi.GetDraftBotInfoAgw({
|
||||
bot_id: botId,
|
||||
});
|
||||
setBotInfo(data ?? {});
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (spaceId && botId) {
|
||||
fetchBotInfo();
|
||||
}
|
||||
}, [spaceId, botId]);
|
||||
|
||||
return botInfo;
|
||||
};
|
||||
|
||||
const updateDatasetForBot = async ({
|
||||
botId,
|
||||
agentId,
|
||||
dataset,
|
||||
botInfo,
|
||||
updatedDatasetList,
|
||||
spaceId,
|
||||
}: UpdateDatasetForBot & {
|
||||
botInfo?: GetDraftBotInfoAgwData;
|
||||
}) => {
|
||||
if (botInfo?.bot_info.bot_mode === BotMode.SingleMode) {
|
||||
await PlaygroundApi.UpdateDraftBotInfoAgw({
|
||||
bot_info: {
|
||||
bot_id: botId,
|
||||
knowledge: {
|
||||
...dataset,
|
||||
knowledge_info: updatedDatasetList,
|
||||
},
|
||||
},
|
||||
});
|
||||
} else {
|
||||
const currentAgent = botInfo?.bot_info?.agents?.find(
|
||||
agent => agent.agent_id === agentId,
|
||||
);
|
||||
if (currentAgent?.agent_id) {
|
||||
await PlaygroundApi.UpdateAgentV2({
|
||||
...currentAgent,
|
||||
current_version:
|
||||
currentAgent.update_type === ReferenceUpdateType.AutoUpdate
|
||||
? '0'
|
||||
: currentAgent.current_version,
|
||||
id: currentAgent?.agent_id,
|
||||
space_id: spaceId,
|
||||
bot_id: botId,
|
||||
knowledge: {
|
||||
...dataset,
|
||||
knowledge_info: updatedDatasetList,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const getUpdatedDataset = (
|
||||
dataset: BotDataset,
|
||||
actionType: ActionType,
|
||||
dataSetDetail: Dataset,
|
||||
): KnowledgeInfo[] => {
|
||||
// 更新后的bot知识库
|
||||
let updatedDatasetList: KnowledgeInfo[] = [];
|
||||
// 原本的bot知识库内容
|
||||
let originDataset: KnowledgeInfo[] = [];
|
||||
|
||||
// 兼容json版本的dataset,FG全量后删除
|
||||
if ('dataset' in dataset) {
|
||||
originDataset = dataset?.dataset ?? [];
|
||||
} else {
|
||||
originDataset = dataset?.knowledge_info ?? [];
|
||||
}
|
||||
|
||||
if (actionType === ActionType.REMOVE) {
|
||||
updatedDatasetList = originDataset?.filter(
|
||||
item => item.id !== dataSetDetail.dataset_id,
|
||||
);
|
||||
} else {
|
||||
updatedDatasetList = [
|
||||
...originDataset,
|
||||
{ name: dataSetDetail.name, id: dataSetDetail.dataset_id },
|
||||
];
|
||||
}
|
||||
|
||||
return updatedDatasetList;
|
||||
};
|
||||
|
||||
// 更新bot知识库逻辑
|
||||
export const handleDatasetUpdate = async ({
|
||||
botInfo,
|
||||
botId,
|
||||
agentId,
|
||||
dataSetDetail = {},
|
||||
dataset,
|
||||
actionType,
|
||||
spaceId,
|
||||
updateSuccess,
|
||||
}: UpdateDatasetForBot & {
|
||||
botInfo?: GetDraftBotInfoAgwData;
|
||||
updateSuccess: () => void;
|
||||
actionType: ActionType;
|
||||
}) => {
|
||||
const updatedDatasetList = getUpdatedDataset(
|
||||
dataset,
|
||||
actionType,
|
||||
dataSetDetail,
|
||||
);
|
||||
|
||||
const updateBotParams = {
|
||||
spaceId,
|
||||
botId,
|
||||
agentId,
|
||||
updatedDatasetList,
|
||||
dataset,
|
||||
};
|
||||
|
||||
await updateDatasetForBot({ ...updateBotParams, botInfo });
|
||||
|
||||
updateSuccess();
|
||||
};
|
||||
|
||||
// 根据不同botInfo信息 获取不同的bot原有的dataset
|
||||
export const getDatasetInfo = (
|
||||
botInfo: GetDraftBotInfoAgwData | undefined,
|
||||
agentId: string,
|
||||
): BotDataset => {
|
||||
if (agentId) {
|
||||
return (
|
||||
botInfo?.bot_info?.agents?.find(item => item.agent_id === agentId)
|
||||
?.knowledge ?? {}
|
||||
);
|
||||
}
|
||||
|
||||
return botInfo?.bot_info?.knowledge ?? {};
|
||||
};
|
||||
|
||||
export const NavBarActionButton = ({
|
||||
dataSetDetail,
|
||||
}: {
|
||||
dataSetDetail: Dataset;
|
||||
}) => {
|
||||
const [loading, setLoading] = useState(false);
|
||||
const { jump } = usePageJumpService();
|
||||
const params = useKnowledgeParams();
|
||||
const { spaceID, botID, agentID, actionType } = params;
|
||||
|
||||
const botInfo = useFetchBotInfo(spaceID, botID);
|
||||
|
||||
const dataset = getDatasetInfo(botInfo, agentID ?? '');
|
||||
|
||||
const updateSuccess = () => {
|
||||
Toast.success(
|
||||
I18n.t(
|
||||
actionType === ActionType.REMOVE
|
||||
? 'bot_edit_dataset_removed_toast'
|
||||
: 'bot_edit_dataset_added_toast',
|
||||
{ dataset_name: dataSetDetail.name },
|
||||
),
|
||||
);
|
||||
jump(SceneType.KNOWLEDGE__BACK__BOT, {
|
||||
spaceID,
|
||||
botID,
|
||||
mode:
|
||||
dataSetDetail.storage_location === StorageLocation.Douyin
|
||||
? 'douyin'
|
||||
: 'bot',
|
||||
});
|
||||
};
|
||||
const handleActionClick = async () => {
|
||||
setLoading(true);
|
||||
try {
|
||||
await handleDatasetUpdate({
|
||||
botInfo,
|
||||
botId: botID ?? '',
|
||||
agentId: agentID ?? '',
|
||||
dataSetDetail,
|
||||
dataset,
|
||||
actionType: actionType ?? ActionType.ADD,
|
||||
spaceId: spaceID ?? '',
|
||||
updateSuccess,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Button
|
||||
loading={loading}
|
||||
disabled={dataSetDetail?.status === DatasetStatus.DatasetForbid}
|
||||
onClick={handleActionClick}
|
||||
>
|
||||
{actionType === ActionType.REMOVE &&
|
||||
dataSetDetail?.storage_location === StorageLocation.Douyin
|
||||
? I18n.t('dy_avatar_resource_delete')
|
||||
: null}
|
||||
{actionType === ActionType.REMOVE &&
|
||||
dataSetDetail?.storage_location !== StorageLocation.Douyin
|
||||
? I18n.t('kl2_014')
|
||||
: null}
|
||||
{actionType !== ActionType.REMOVE &&
|
||||
dataSetDetail?.storage_location === StorageLocation.Douyin
|
||||
? I18n.t('dy_avatar_resource_add')
|
||||
: null}
|
||||
{actionType !== ActionType.REMOVE &&
|
||||
dataSetDetail?.storage_location !== StorageLocation.Douyin
|
||||
? I18n.t('kl2_013')
|
||||
: null}
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { useShallow } from 'zustand/react/shallow';
|
||||
import { useKnowledgeStore } from '@coze-data/knowledge-stores';
|
||||
|
||||
import { ImportKnowledgeSourceButton } from '@/features/import-knowledge-source-button/base';
|
||||
import { KnowledgeIDENavBar as KnowledgeIDENavBarComponent } from '@/components/knowledge-nav-bar';
|
||||
|
||||
import { type KnowledgeIDENavBarProps } from '../module';
|
||||
|
||||
export const BaseKnowledgeIDENavBar = (props: KnowledgeIDENavBarProps) => {
|
||||
const { progressMap, hideBackButton, importKnowledgeSourceButton } = props;
|
||||
const { setDataSetDetail } = useKnowledgeStore(
|
||||
useShallow(state => ({
|
||||
setDataSetDetail: state.setDataSetDetail,
|
||||
})),
|
||||
);
|
||||
return (
|
||||
<KnowledgeIDENavBarComponent
|
||||
{...props}
|
||||
importKnowledgeSourceButton={
|
||||
importKnowledgeSourceButton ?? <ImportKnowledgeSourceButton />
|
||||
}
|
||||
onChangeDataset={setDataSetDetail}
|
||||
progressMap={progressMap}
|
||||
hideBackButton={hideBackButton}
|
||||
/>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { useMemo, useState } from 'react';
|
||||
|
||||
import { useShallow } from 'zustand/react/shallow';
|
||||
import { useKnowledgeParams, useKnowledgeStore } from '@coze-data/knowledge-stores';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import { SceneType, usePageJumpService } from '@coze-arch/bot-hooks';
|
||||
import { StorageLocation } from '@coze-arch/bot-api/knowledge';
|
||||
import { Modal, Toast } from '@coze-arch/coze-design';
|
||||
|
||||
import { ActionType } from '@/types';
|
||||
import {
|
||||
useFetchBotInfo,
|
||||
getDatasetInfo,
|
||||
handleDatasetUpdate,
|
||||
} from '@/features/nav-bar-action-button';
|
||||
|
||||
export const useBeforeKnowledgeIDEClose = ({
|
||||
onBack,
|
||||
}: {
|
||||
onBack?: () => void;
|
||||
}) => {
|
||||
const [loading, setLoading] = useState(false);
|
||||
const {
|
||||
spaceID: spaceId,
|
||||
agentID: agentId,
|
||||
botID: botId,
|
||||
actionType,
|
||||
} = useKnowledgeParams();
|
||||
const { dataSetDetail } = useKnowledgeStore(
|
||||
useShallow(state => ({
|
||||
dataSetDetail: state.dataSetDetail,
|
||||
})),
|
||||
);
|
||||
|
||||
const { jump } = usePageJumpService();
|
||||
|
||||
const botInfo = useFetchBotInfo(spaceId, botId);
|
||||
|
||||
const dataset = getDatasetInfo(botInfo, agentId ?? '');
|
||||
|
||||
const hasAddDataset = useMemo(() => {
|
||||
let datasetIds: string[] = [];
|
||||
if ('dataset' in dataset) {
|
||||
datasetIds = (dataset?.dataset || []).map(item => item.id ?? '');
|
||||
}
|
||||
if ('knowledge_info' in dataset) {
|
||||
datasetIds = (dataset?.knowledge_info || []).map(item => item.id ?? '');
|
||||
}
|
||||
return !datasetIds.includes(dataSetDetail?.dataset_id || '');
|
||||
}, [dataset, dataSetDetail?.dataset_id]);
|
||||
|
||||
const updateSuccessJump = () => {
|
||||
jump(SceneType.KNOWLEDGE__BACK__BOT, {
|
||||
spaceID: spaceId,
|
||||
botID: botId,
|
||||
mode:
|
||||
dataSetDetail?.storage_location === StorageLocation.Douyin
|
||||
? 'douyin'
|
||||
: 'bot',
|
||||
});
|
||||
};
|
||||
const handleFullModalBack = () => {
|
||||
if (onBack) {
|
||||
onBack?.();
|
||||
} else {
|
||||
updateSuccessJump();
|
||||
}
|
||||
};
|
||||
|
||||
const updateSuccess = () => {
|
||||
Toast.success(
|
||||
I18n.t(
|
||||
actionType === ActionType.REMOVE
|
||||
? 'bot_edit_dataset_removed_toast'
|
||||
: 'bot_edit_dataset_added_toast',
|
||||
{ dataset_name: dataSetDetail?.name },
|
||||
),
|
||||
);
|
||||
updateSuccessJump();
|
||||
};
|
||||
|
||||
const handleBotIdeBack = () => {
|
||||
// Bot IDE检查是否有绑定knowledge,如果有绑定知识库正常关闭,没有绑定确认提示处理
|
||||
if (hasAddDataset) {
|
||||
Modal.confirm({
|
||||
title: I18n.t('bot_ide_knowledge_confirm_title'),
|
||||
content:
|
||||
dataSetDetail?.storage_location === StorageLocation.Douyin
|
||||
? I18n.t('dy_avatar_resource_add_tip')
|
||||
: I18n.t('bot_ide_knowledge_confirm_content'),
|
||||
okText: I18n.t('bot_ide_knowledge_confirm_ok'),
|
||||
cancelText: I18n.t('bot_ide_knowledge_confirm_cancel'),
|
||||
confirmLoading: loading,
|
||||
onOk: async () => {
|
||||
setLoading(true);
|
||||
try {
|
||||
await handleDatasetUpdate({
|
||||
botInfo,
|
||||
botId: botId ?? '',
|
||||
agentId: agentId ?? '',
|
||||
dataSetDetail,
|
||||
dataset,
|
||||
actionType: actionType ?? ActionType.ADD,
|
||||
spaceId: spaceId ?? '',
|
||||
updateSuccess,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
// 无论成功无论都跳转一次
|
||||
handleFullModalBack();
|
||||
}
|
||||
},
|
||||
onCancel: () => {
|
||||
// 取消,正常跳转
|
||||
handleFullModalBack();
|
||||
},
|
||||
});
|
||||
} else {
|
||||
// 正常绑定不做弹窗拦截
|
||||
handleFullModalBack();
|
||||
}
|
||||
};
|
||||
|
||||
return handleBotIdeBack;
|
||||
};
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { useShallow } from 'zustand/react/shallow';
|
||||
import { useKnowledgeStore } from '@coze-data/knowledge-stores';
|
||||
|
||||
import { NavBarActionButton } from '@/features/nav-bar-action-button';
|
||||
import { BizAgentIdeImportKnowledgeSourceButton } from '@/features/import-knowledge-source-button/biz-agent-ide';
|
||||
import { KnowledgeModalNavBar as KnowledgeModalNavBarComponent } from '@/components/knowledge-modal-nav-bar';
|
||||
|
||||
import { type KnowledgeIDENavBarProps } from '../module';
|
||||
import { useBeforeKnowledgeIDEClose } from './hooks/use-case/use-before-knowledgeide-close';
|
||||
|
||||
export type BizAgentIdeKnowledgeIDENavBarProps = KnowledgeIDENavBarProps;
|
||||
|
||||
export const BizAgentIdeKnowledgeIDENavBar = (
|
||||
props: BizAgentIdeKnowledgeIDENavBarProps,
|
||||
) => {
|
||||
const { onBack, importKnowledgeSourceButton } = props;
|
||||
const { dataSetDetail, documentList } = useKnowledgeStore(
|
||||
useShallow(state => ({
|
||||
dataSetDetail: state.dataSetDetail,
|
||||
documentList: state.documentList,
|
||||
})),
|
||||
);
|
||||
const handleBotIdeBack = useBeforeKnowledgeIDEClose({
|
||||
onBack,
|
||||
});
|
||||
return (
|
||||
<KnowledgeModalNavBarComponent
|
||||
title={dataSetDetail?.name as string}
|
||||
onBack={onBack}
|
||||
datasetDetail={dataSetDetail}
|
||||
docInfo={documentList?.[0]}
|
||||
actionButtons={
|
||||
<NavBarActionButton
|
||||
key={dataSetDetail?.dataset_id}
|
||||
dataSetDetail={dataSetDetail}
|
||||
/>
|
||||
}
|
||||
importKnowledgeSourceButton={
|
||||
importKnowledgeSourceButton ?? (
|
||||
<BizAgentIdeImportKnowledgeSourceButton />
|
||||
)
|
||||
}
|
||||
beforeBack={handleBotIdeBack}
|
||||
/>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { type KnowledgeIDENavBarProps } from '../module';
|
||||
import { BaseKnowledgeIDENavBar } from '../base';
|
||||
|
||||
export type BizLibraryKnowledgeIDENavBarProps = KnowledgeIDENavBarProps;
|
||||
|
||||
export const BizLibraryKnowledgeIDENavBar = (
|
||||
props: BizLibraryKnowledgeIDENavBarProps,
|
||||
) => <BaseKnowledgeIDENavBar {...props} />;
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { type KnowledgeIDENavBarProps } from '../module';
|
||||
import { BaseKnowledgeIDENavBar } from '../base';
|
||||
|
||||
export type BizProjectKnowledgeIDENavBarProps = KnowledgeIDENavBarProps;
|
||||
|
||||
export const BizProjectKnowledgeIDENavBar = (
|
||||
props: BizProjectKnowledgeIDENavBarProps,
|
||||
) => <BaseKnowledgeIDENavBar {...props} hideBackButton />;
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { useShallow } from 'zustand/react/shallow';
|
||||
import { useKnowledgeStore } from '@coze-data/knowledge-stores';
|
||||
|
||||
import { KnowledgeModalNavBar as KnowledgeModalNavBarComponent } from '@/components/knowledge-modal-nav-bar';
|
||||
|
||||
import { type KnowledgeIDENavBarProps } from '../module';
|
||||
|
||||
export type BizWorkflowKnowledgeIDENavBarProps = KnowledgeIDENavBarProps;
|
||||
|
||||
export const BizWorkflowKnowledgeIDENavBar = (
|
||||
props: BizWorkflowKnowledgeIDENavBarProps,
|
||||
) => {
|
||||
const { onBack, actionButtons } = props;
|
||||
const { dataSetDetail, documentList } = useKnowledgeStore(
|
||||
useShallow(state => ({
|
||||
dataSetDetail: state.dataSetDetail,
|
||||
documentList: state.documentList,
|
||||
})),
|
||||
);
|
||||
return (
|
||||
<KnowledgeModalNavBarComponent
|
||||
title={dataSetDetail?.name as string}
|
||||
onBack={onBack}
|
||||
datasetDetail={dataSetDetail}
|
||||
docInfo={documentList?.[0]}
|
||||
actionButtons={actionButtons}
|
||||
/>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { type ProgressMap } from '@/types';
|
||||
|
||||
export interface KnowledgeIDENavBarProps {
|
||||
progressMap: ProgressMap;
|
||||
hideBackButton?: boolean;
|
||||
textConfigButton?: React.ReactNode;
|
||||
tableConfigButton?: React.ReactNode;
|
||||
importKnowledgeSourceButton?: React.ReactNode;
|
||||
actionButtons?: React.ReactNode;
|
||||
onBack?: () => void;
|
||||
}
|
||||
@@ -0,0 +1,164 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { useMemo, useRef, useState } from 'react';
|
||||
|
||||
import classnames from 'classnames';
|
||||
import { useKnowledgeStore } from '@coze-data/knowledge-stores';
|
||||
import { type TableViewMethods } from '@coze-common/table-view';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import { EmptyState, Spin, Layout } from '@coze-arch/coze-design';
|
||||
import { IconSegmentEmpty } from '@coze-arch/bot-icons';
|
||||
import { type DocumentInfo } from '@coze-arch/bot-api/knowledge';
|
||||
|
||||
import styles from '../styles/index.module.less';
|
||||
import { useGetSliceListData } from '../hooks/inner/use-get-slice-list-data';
|
||||
import { TableUIContext } from '../context/table-ui-context';
|
||||
import { TableDataContext } from '../context/table-data-context';
|
||||
import { TableActionsContext } from '../context/table-actions-context';
|
||||
import { TableDataView } from './table-data-view';
|
||||
|
||||
const MAX_TOTAL = 1000;
|
||||
|
||||
export interface TableKnowledgeWorkspaceProps {
|
||||
onChangeDocList?: (docList: DocumentInfo[]) => void;
|
||||
reload?: () => void;
|
||||
isReloading: boolean;
|
||||
}
|
||||
|
||||
export const TableKnowledgeWorkspace = ({
|
||||
isReloading,
|
||||
}: TableKnowledgeWorkspaceProps) => {
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
const contentWrapperRef = useRef<HTMLDivElement>(null);
|
||||
const tableViewRef = useRef<TableViewMethods>(null);
|
||||
const canEdit = useKnowledgeStore(state => state.canEdit);
|
||||
const documentList = useKnowledgeStore(state => state.documentList)?.filter(
|
||||
doc => doc.document_id,
|
||||
) as { document_id: string }[];
|
||||
const [curIndex, setCurIndex] = useState(0);
|
||||
const [curSliceId, setCurSliceId] = useState('');
|
||||
const [delSliceIds, setDelSliceIds] = useState<string[]>([]);
|
||||
|
||||
const {
|
||||
sliceListData,
|
||||
mutateSliceListData,
|
||||
loadMoreSliceList,
|
||||
isLoadingSliceList,
|
||||
isLoadingMoreSliceList,
|
||||
} = useGetSliceListData();
|
||||
|
||||
const slices = sliceListData?.list;
|
||||
|
||||
const isShowAddBtn = useMemo(
|
||||
() =>
|
||||
Boolean(
|
||||
canEdit &&
|
||||
!sliceListData?.hasMore &&
|
||||
sliceListData?.total &&
|
||||
sliceListData?.total < MAX_TOTAL,
|
||||
),
|
||||
[canEdit, sliceListData],
|
||||
);
|
||||
|
||||
const hasShowEmptyContent = useMemo(() => {
|
||||
if (!documentList?.length && !isReloading) {
|
||||
return true;
|
||||
}
|
||||
return (
|
||||
sliceListData?.ready &&
|
||||
!slices?.length &&
|
||||
!(isLoadingMoreSliceList || isLoadingSliceList)
|
||||
);
|
||||
}, [
|
||||
sliceListData,
|
||||
documentList,
|
||||
isReloading,
|
||||
isLoadingMoreSliceList,
|
||||
isLoadingSliceList,
|
||||
slices,
|
||||
]);
|
||||
|
||||
// 创建 UI Context 值
|
||||
const uiContextValue = {
|
||||
tableViewRef,
|
||||
isLoadingMoreSliceList,
|
||||
isLoadingSliceList,
|
||||
isShowAddBtn,
|
||||
};
|
||||
|
||||
// 创建数据 Context 值
|
||||
const dataContextValue = {
|
||||
sliceListData: sliceListData || { list: [], total: 0 },
|
||||
curIndex,
|
||||
curSliceId,
|
||||
delSliceIds,
|
||||
};
|
||||
|
||||
// 创建操作 Context 值
|
||||
const actionsContextValue = {
|
||||
setCurIndex,
|
||||
setCurSliceId,
|
||||
setDelSliceIds,
|
||||
loadMoreSliceList,
|
||||
mutateSliceListData,
|
||||
};
|
||||
|
||||
return (
|
||||
<TableUIContext.Provider value={uiContextValue}>
|
||||
<TableDataContext.Provider value={dataContextValue}>
|
||||
<TableActionsContext.Provider value={actionsContextValue}>
|
||||
<Layout.Content
|
||||
ref={containerRef}
|
||||
className={classnames(
|
||||
styles['slice-list-ui-content'],
|
||||
'knowledge-ide-base-slice-list-ui-content',
|
||||
)}
|
||||
>
|
||||
<Spin
|
||||
spinning={isLoadingSliceList}
|
||||
wrapperClassName={styles.spin}
|
||||
size="large"
|
||||
style={{ width: '100%', height: '100%' }}
|
||||
>
|
||||
{slices?.length ? (
|
||||
<div
|
||||
ref={contentWrapperRef}
|
||||
className={styles['slice-list-table']}
|
||||
>
|
||||
<TableDataView />
|
||||
</div>
|
||||
) : null}
|
||||
{hasShowEmptyContent && !isLoadingSliceList ? (
|
||||
<div className={styles['empty-content']}>
|
||||
<EmptyState
|
||||
size="large"
|
||||
icon={
|
||||
<IconSegmentEmpty
|
||||
style={{ width: 150, height: '100%' }}
|
||||
/>
|
||||
}
|
||||
title={I18n.t('dataset_segment_empty_desc')}
|
||||
/>
|
||||
</div>
|
||||
) : null}
|
||||
</Spin>
|
||||
</Layout.Content>
|
||||
</TableActionsContext.Provider>
|
||||
</TableDataContext.Provider>
|
||||
</TableUIContext.Provider>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,183 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import classnames from 'classnames';
|
||||
import {
|
||||
useKnowledgeParamsStore,
|
||||
useKnowledgeStore,
|
||||
} from '@coze-data/knowledge-stores';
|
||||
import { KnowledgeE2e } from '@coze-data/e2e';
|
||||
import { TableView } from '@coze-common/table-view';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import { IconCozPlus } from '@coze-arch/coze-design/icons';
|
||||
import { Button } from '@coze-arch/coze-design';
|
||||
import { DocumentStatus } from '@coze-arch/bot-api/knowledge';
|
||||
|
||||
import styles from '../styles/index.module.less';
|
||||
import { getTableRenderColumnsData } from '../service/use-case/get-table-render-columns-data';
|
||||
import { useTableSliceOperations } from '../hooks/use-case/use-table-slice-operations';
|
||||
import { useTableSegmentModal } from '../hooks/use-case/use-table-segment-modal';
|
||||
import { useDeleteSliceModal } from '../hooks/use-case/use-delete-slice-modal';
|
||||
import { useAddRow } from '../hooks/use-case/use-add-row';
|
||||
import { useTableHeight } from '../hooks/inner/use-table-height';
|
||||
import { useScroll } from '../hooks/inner/use-scroll';
|
||||
import { useTableUI } from '../context/table-ui-context';
|
||||
import { useTableData } from '../context/table-data-context';
|
||||
import { useTableActions } from '../context/table-actions-context';
|
||||
|
||||
// 表格内容组件
|
||||
const TableContent = () => {
|
||||
const knowledgeIDEBiz = useKnowledgeParamsStore(state => state.params.biz);
|
||||
const documentList = useKnowledgeStore(state => state.documentList);
|
||||
const curDoc = documentList?.[0];
|
||||
|
||||
const { tableViewRef, isLoadingMoreSliceList, isLoadingSliceList } =
|
||||
useTableUI();
|
||||
|
||||
const { sliceListData } = useTableData();
|
||||
|
||||
const slices = sliceListData?.list;
|
||||
|
||||
const { loadMoreSliceList } = useTableActions();
|
||||
|
||||
const canEdit = Boolean(useKnowledgeStore(state => state.canEdit));
|
||||
|
||||
// 删除切片弹窗
|
||||
const { deleteSliceModalNode, openDeleteSliceModal } = useDeleteSliceModal();
|
||||
|
||||
// 编辑slice弹窗
|
||||
const { tableSegmentModalNode, openTableSegmentModal } =
|
||||
useTableSegmentModal();
|
||||
|
||||
// 获取表格操作方法
|
||||
const { deleteSlice, rowUpdateSliceData, modalEditSlice } =
|
||||
useTableSliceOperations({
|
||||
openDeleteSliceModal,
|
||||
openTableSegmentModal,
|
||||
});
|
||||
|
||||
const { tableH } = useTableHeight();
|
||||
|
||||
// 如果没有数据,直接返回空
|
||||
if (!slices?.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const tableKey = curDoc?.document_id;
|
||||
|
||||
const { data: dataSource, columns } = getTableRenderColumnsData({
|
||||
sliceList: slices,
|
||||
metaData: curDoc?.table_meta,
|
||||
onEdit: modalEditSlice,
|
||||
onDelete: deleteSlice,
|
||||
onUpdate: rowUpdateSliceData,
|
||||
canEdit,
|
||||
tableKey: tableKey || '',
|
||||
});
|
||||
|
||||
return (
|
||||
<div
|
||||
className={classnames(
|
||||
styles['table-view-container-box'],
|
||||
'table-view-box',
|
||||
)}
|
||||
style={{ height: tableH }}
|
||||
>
|
||||
<TableView
|
||||
tableKey={tableKey}
|
||||
ref={tableViewRef}
|
||||
className={classnames(
|
||||
`${styles['unit-table-view']} ${
|
||||
isLoadingMoreSliceList ? styles['table-view-loading'] : ''
|
||||
}`,
|
||||
knowledgeIDEBiz === 'project'
|
||||
? styles['table-preview-max']
|
||||
: styles['table-preview-secondary'],
|
||||
)}
|
||||
resizable
|
||||
dataSource={dataSource}
|
||||
loading={isLoadingSliceList}
|
||||
columns={columns}
|
||||
rowSelect={canEdit}
|
||||
isVirtualized
|
||||
rowOperation={canEdit}
|
||||
scrollToBottom={() => {
|
||||
if (!isLoadingSliceList && !isLoadingMoreSliceList) {
|
||||
loadMoreSliceList();
|
||||
}
|
||||
}}
|
||||
editProps={{
|
||||
onDelete: indexs => deleteSlice(indexs as number[]),
|
||||
onEdit: (record, index) => {
|
||||
modalEditSlice(record, index as number);
|
||||
},
|
||||
}}
|
||||
/>
|
||||
{deleteSliceModalNode}
|
||||
{tableSegmentModalNode}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
// 添加行按钮组件
|
||||
const AddRowButton = () => {
|
||||
const { isShowAddBtn } = useTableUI();
|
||||
const documentList = useKnowledgeStore(state => state.documentList);
|
||||
const curDoc = documentList?.[0];
|
||||
const { increaseTableHeight } = useTableHeight();
|
||||
const { scrollTableBodyToBottom } = useScroll();
|
||||
const { handleAddRow } = useAddRow({
|
||||
increaseTableHeight,
|
||||
scrollTableBodyToBottom,
|
||||
});
|
||||
|
||||
if (!isShowAddBtn) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={styles['add-row-btn']}>
|
||||
<Button
|
||||
disabled={curDoc?.status === DocumentStatus.Processing}
|
||||
data-testid={KnowledgeE2e.SegmentDetailContentAddRowBtn}
|
||||
color="primary"
|
||||
size="default"
|
||||
icon={<IconCozPlus />}
|
||||
onClick={handleAddRow}
|
||||
>
|
||||
{I18n.t('knowledge_optimize_0010')}
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
// 主组件
|
||||
export const TableDataView = () => {
|
||||
const { sliceListData } = useTableData();
|
||||
const slices = sliceListData?.list;
|
||||
|
||||
// 如果没有数据,只显示添加按钮
|
||||
if (!slices?.length) {
|
||||
return <AddRowButton />;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<TableContent />
|
||||
<AddRowButton />
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { createContext, useContext } from 'react';
|
||||
|
||||
import { type DatasetDataScrollList } from '@/service';
|
||||
|
||||
// 表格操作相关的 Context
|
||||
interface TableActionsContextType {
|
||||
setCurIndex: (index: number | ((prev: number) => number)) => void;
|
||||
setCurSliceId: (id: string | ((prev: string) => string)) => void;
|
||||
setDelSliceIds: (ids: string[] | ((prev: string[]) => string[])) => void;
|
||||
loadMoreSliceList: () => void;
|
||||
mutateSliceListData: (data: DatasetDataScrollList) => void;
|
||||
}
|
||||
|
||||
export const TableActionsContext =
|
||||
createContext<TableActionsContextType | null>(null);
|
||||
|
||||
export const useTableActions = () => {
|
||||
const context = useContext(TableActionsContext);
|
||||
if (!context) {
|
||||
throw new Error(
|
||||
'useTableActions must be used within a TableActionsProvider',
|
||||
);
|
||||
}
|
||||
return context;
|
||||
};
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { createContext, useContext } from 'react';
|
||||
|
||||
import { type DatasetDataScrollList } from '@/service';
|
||||
|
||||
// 表格数据相关的 Context
|
||||
interface TableDataContextType {
|
||||
sliceListData: DatasetDataScrollList;
|
||||
curIndex: number;
|
||||
curSliceId: string;
|
||||
delSliceIds: string[];
|
||||
}
|
||||
|
||||
export const TableDataContext = createContext<TableDataContextType | null>(
|
||||
null,
|
||||
);
|
||||
|
||||
export const useTableData = () => {
|
||||
const context = useContext(TableDataContext);
|
||||
if (!context) {
|
||||
throw new Error('useTableData must be used within a TableDataProvider');
|
||||
}
|
||||
return context;
|
||||
};
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { createContext, useContext } from 'react';
|
||||
import { type MutableRefObject } from 'react';
|
||||
|
||||
import { type TableViewMethods } from '@coze-common/table-view';
|
||||
|
||||
// 表格 UI 相关的 Context
|
||||
interface TableUIContextType {
|
||||
tableViewRef: MutableRefObject<TableViewMethods | null>;
|
||||
isLoadingMoreSliceList: boolean;
|
||||
isLoadingSliceList: boolean;
|
||||
isShowAddBtn: boolean;
|
||||
}
|
||||
|
||||
export const TableUIContext = createContext<TableUIContextType | null>(null);
|
||||
|
||||
export const useTableUI = () => {
|
||||
const context = useContext(TableUIContext);
|
||||
if (!context) {
|
||||
throw new Error('useTableUI must be used within a TableUIProvider');
|
||||
}
|
||||
return context;
|
||||
};
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { useKnowledgeStore } from '@coze-data/knowledge-stores';
|
||||
|
||||
import { type ISliceInfo } from '@/types/slice';
|
||||
import { useCreateSlice as useCreateSliceService } from '@/service/slice';
|
||||
|
||||
import { useTableData } from '../../context/table-data-context';
|
||||
import { useTableActions } from '../../context/table-actions-context';
|
||||
|
||||
export const useCreateSlice = () => {
|
||||
const dataSetDetail = useKnowledgeStore(state => state.dataSetDetail);
|
||||
const setDataSetDetail = useKnowledgeStore(state => state.setDataSetDetail);
|
||||
const { sliceListData } = useTableData();
|
||||
const { mutateSliceListData } = useTableActions();
|
||||
const documentList = useKnowledgeStore(state => state.documentList);
|
||||
const curDoc = documentList?.[0];
|
||||
|
||||
// 创建切片
|
||||
const { createSlice } = useCreateSliceService({
|
||||
onReload: (createItem: ISliceInfo) => {
|
||||
const list =
|
||||
(sliceListData?.list ?? []).filter(item => !item.addId) ?? [];
|
||||
const createSliceContent = JSON.parse(createItem.content ?? '{}');
|
||||
const itemContent = (curDoc?.table_meta ?? []).reduce(
|
||||
(
|
||||
prev: { column_name: string; column_id: string; value: string }[],
|
||||
cur,
|
||||
) => {
|
||||
prev.push({
|
||||
column_name: cur?.column_name ?? '',
|
||||
column_id: cur?.id ?? '',
|
||||
value: cur.id ? createSliceContent[cur.id] : '',
|
||||
});
|
||||
return prev;
|
||||
},
|
||||
[],
|
||||
);
|
||||
list.push({
|
||||
...createItem,
|
||||
content: JSON.stringify(itemContent),
|
||||
});
|
||||
|
||||
mutateSliceListData({
|
||||
...sliceListData,
|
||||
total: Number(sliceListData?.total ?? '0'),
|
||||
list,
|
||||
});
|
||||
|
||||
if (dataSetDetail) {
|
||||
setDataSetDetail({
|
||||
...dataSetDetail,
|
||||
slice_count: list?.length ?? 0,
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
return {
|
||||
createSlice,
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { DataNamespace, dataReporter } from '@coze-data/reporter';
|
||||
import { useKnowledgeStore } from '@coze-data/knowledge-stores';
|
||||
import { REPORT_EVENTS as ReportEventNames } from '@coze-arch/report-events';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import { Toast } from '@coze-arch/coze-design';
|
||||
|
||||
import { useScrollListSliceReq } from '@/service';
|
||||
|
||||
export const useGetSliceListData = () => {
|
||||
const documentList = useKnowledgeStore(state => state.documentList);
|
||||
const curDocId = documentList?.[0]?.document_id;
|
||||
// 加载数据
|
||||
const {
|
||||
data: sliceListData,
|
||||
mutate: mutateSliceListData,
|
||||
reload: reloadSliceList,
|
||||
loadMore: loadMoreSliceList,
|
||||
loading: isLoadingSliceList,
|
||||
loadingMore: isLoadingMoreSliceList,
|
||||
} = useScrollListSliceReq({
|
||||
params: {
|
||||
document_id: curDocId,
|
||||
},
|
||||
reloadDeps: [curDocId],
|
||||
target: null,
|
||||
onError: error => {
|
||||
dataReporter.errorEvent(DataNamespace.KNOWLEDGE, {
|
||||
eventName: ReportEventNames.KnowledgeGetSliceList,
|
||||
error,
|
||||
});
|
||||
|
||||
Toast.error(I18n.t('knowledge_document_view'));
|
||||
},
|
||||
});
|
||||
|
||||
return {
|
||||
sliceListData,
|
||||
mutateSliceListData,
|
||||
reloadSliceList,
|
||||
loadMoreSliceList,
|
||||
isLoadingMoreSliceList,
|
||||
isLoadingSliceList,
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { useTableData } from '../../context/table-data-context';
|
||||
|
||||
const ADD_BTN_HEIGHT = 56;
|
||||
|
||||
export const useScroll = () => {
|
||||
const { sliceListData } = useTableData();
|
||||
// 滚动表格到底部
|
||||
const scrollTableBodyToBottom = () => {
|
||||
const bodyDom = document.querySelector(
|
||||
'.table-view-box .semi-table-container>.semi-table-body',
|
||||
);
|
||||
if (bodyDom && sliceListData?.list.length) {
|
||||
bodyDom.scrollTop = sliceListData?.list.length * ADD_BTN_HEIGHT;
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
scrollTableBodyToBottom,
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
import { useTableUI } from '../../context/table-ui-context';
|
||||
import { useTableData } from '../../context/table-data-context';
|
||||
|
||||
export const useTableHeight = () => {
|
||||
const { tableViewRef, isShowAddBtn } = useTableUI();
|
||||
const { sliceListData } = useTableData();
|
||||
const [tableH, setTableHeight] = useState<number | string>(0);
|
||||
|
||||
// 更新表格高度
|
||||
useEffect(() => {
|
||||
const h = tableViewRef?.current?.getTableHeight();
|
||||
if (h) {
|
||||
setTableHeight(isShowAddBtn ? h : '100%');
|
||||
}
|
||||
}, [sliceListData, isShowAddBtn, tableViewRef]);
|
||||
|
||||
const increaseTableHeight = (addBtnHeight: number) => {
|
||||
setTableHeight(Number(tableH ?? '0') + addBtnHeight);
|
||||
};
|
||||
|
||||
return {
|
||||
tableH,
|
||||
increaseTableHeight,
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { nanoid } from 'nanoid';
|
||||
|
||||
import { type ISliceInfo } from '@/types/slice';
|
||||
|
||||
import { useTableData } from '../../context/table-data-context';
|
||||
import { useTableActions } from '../../context/table-actions-context';
|
||||
|
||||
const ADD_BTN_HEIGHT = 56;
|
||||
|
||||
interface UseAddRowProps {
|
||||
increaseTableHeight: (height: number) => void;
|
||||
scrollTableBodyToBottom: () => void;
|
||||
}
|
||||
|
||||
export const useAddRow = ({
|
||||
increaseTableHeight,
|
||||
scrollTableBodyToBottom,
|
||||
}: UseAddRowProps) => {
|
||||
const { sliceListData } = useTableData();
|
||||
const { mutateSliceListData } = useTableActions();
|
||||
const handleAddRow = () => {
|
||||
/** 先增加容器的高度 */
|
||||
increaseTableHeight(ADD_BTN_HEIGHT);
|
||||
const items = JSON.parse(sliceListData?.list[0]?.content ?? '[]');
|
||||
|
||||
const addItemContent = items?.map(v => ({
|
||||
...v,
|
||||
value: '',
|
||||
char_count: 0,
|
||||
hit_count: 0,
|
||||
}));
|
||||
|
||||
mutateSliceListData({
|
||||
...sliceListData,
|
||||
total: Number(sliceListData?.total ?? '0'),
|
||||
list: sliceListData?.list.concat([
|
||||
{ content: JSON.stringify(addItemContent), addId: nanoid() },
|
||||
]) as ISliceInfo[],
|
||||
});
|
||||
|
||||
scrollTableBodyToBottom();
|
||||
};
|
||||
|
||||
return {
|
||||
handleAddRow,
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { DataNamespace, dataReporter } from '@coze-data/reporter';
|
||||
import { useKnowledgeStore } from '@coze-data/knowledge-stores';
|
||||
import { useSliceDeleteModal } from '@coze-data/knowledge-modal-base';
|
||||
import { REPORT_EVENTS as ReportEventNames } from '@coze-arch/report-events';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import { Toast } from '@coze-arch/coze-design';
|
||||
|
||||
import { delSlice } from '@/service';
|
||||
|
||||
import { useTableUI } from '../../context/table-ui-context';
|
||||
import { useTableData } from '../../context/table-data-context';
|
||||
import { useTableActions } from '../../context/table-actions-context';
|
||||
|
||||
export const useDeleteSliceModal = () => {
|
||||
// 外部数据
|
||||
const dataSetDetail = useKnowledgeStore(state => state.dataSetDetail);
|
||||
const setDataSetDetail = useKnowledgeStore(state => state.setDataSetDetail);
|
||||
const documentList = useKnowledgeStore(state => state.documentList);
|
||||
|
||||
// 内部数据
|
||||
const { sliceListData, delSliceIds } = useTableData();
|
||||
const { tableViewRef } = useTableUI();
|
||||
const { mutateSliceListData } = useTableActions();
|
||||
|
||||
const curDoc = documentList?.[0];
|
||||
const slices = sliceListData?.list;
|
||||
|
||||
// 删除切片弹窗
|
||||
const { node: deleteSliceModalNode, delete: openDeleteSliceModal } =
|
||||
useSliceDeleteModal({
|
||||
onDel: async () => {
|
||||
try {
|
||||
await delSlice(delSliceIds);
|
||||
if (!curDoc) {
|
||||
return;
|
||||
}
|
||||
Toast.success({
|
||||
content: I18n.t('Delete_success'),
|
||||
showClose: false,
|
||||
});
|
||||
console.log('oldList', slices);
|
||||
const newList = (slices || []).filter(
|
||||
lItem =>
|
||||
!delSliceIds.includes(lItem.slice_id ?? '') &&
|
||||
!delSliceIds.includes(lItem.addId ?? ''),
|
||||
);
|
||||
mutateSliceListData({
|
||||
...sliceListData,
|
||||
list: newList,
|
||||
});
|
||||
console.log('newList', newList);
|
||||
tableViewRef?.current?.resetSelected();
|
||||
if (dataSetDetail && typeof dataSetDetail.slice_count === 'number') {
|
||||
setDataSetDetail({
|
||||
...dataSetDetail,
|
||||
slice_count:
|
||||
dataSetDetail.slice_count > -1
|
||||
? Math.max(
|
||||
0,
|
||||
dataSetDetail.slice_count - (delSliceIds?.length || 0),
|
||||
)
|
||||
: 0,
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
dataReporter.errorEvent(DataNamespace.KNOWLEDGE, {
|
||||
eventName: ReportEventNames.KnowledgeDeleteSlice,
|
||||
error: error as Error,
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
return {
|
||||
deleteSliceModalNode,
|
||||
openDeleteSliceModal,
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { useKnowledgeStore } from '@coze-data/knowledge-stores';
|
||||
import {
|
||||
ModalActionType,
|
||||
useTableSegmentModal as useBaseTableSegmentModal,
|
||||
} from '@coze-data/knowledge-modal-base';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import { Toast } from '@coze-arch/coze-design';
|
||||
import { SliceStatus } from '@coze-arch/bot-api/knowledge';
|
||||
|
||||
import { useTableData } from '../../context/table-data-context';
|
||||
import { useTableActions } from '../../context/table-actions-context';
|
||||
|
||||
export const useTableSegmentModal = () => {
|
||||
const documentList = useKnowledgeStore(state => state.documentList);
|
||||
|
||||
const { sliceListData, curIndex, curSliceId } = useTableData();
|
||||
const { mutateSliceListData } = useTableActions();
|
||||
const curDoc = documentList?.[0];
|
||||
|
||||
// 表格分段弹窗
|
||||
const {
|
||||
node: tableSegmentModalNode,
|
||||
edit: openTableSegmentModal,
|
||||
fetchCreateTableSegment,
|
||||
fetchUpdateTableSegment,
|
||||
} = useBaseTableSegmentModal({
|
||||
title:
|
||||
curIndex > -1 ? (
|
||||
<div className="slice-modal-title">
|
||||
{I18n.t('datasets_segment_detailModel_title', { num: curIndex + 1 })}
|
||||
</div>
|
||||
) : (
|
||||
I18n.t('dataset_segment_content')
|
||||
),
|
||||
meta: curDoc?.table_meta || [],
|
||||
canEdit: true,
|
||||
onSubmit: async (actionType, tData) => {
|
||||
if (actionType === ModalActionType.Create && curDoc?.document_id) {
|
||||
await fetchCreateTableSegment(curDoc?.document_id, tData);
|
||||
} else if (actionType === ModalActionType.Edit && curSliceId) {
|
||||
await fetchUpdateTableSegment(curSliceId, tData);
|
||||
}
|
||||
},
|
||||
onFinish: (actionType, tData) => {
|
||||
if (actionType === ModalActionType.Create) {
|
||||
Toast.success({
|
||||
content: I18n.t('knowledge_tableview_03'),
|
||||
showClose: false,
|
||||
});
|
||||
} else if (actionType === ModalActionType.Edit) {
|
||||
if (sliceListData) {
|
||||
const updateContent = JSON.stringify(tData);
|
||||
const newList = sliceListData.list;
|
||||
newList[curIndex].content = updateContent;
|
||||
newList[curIndex].status = SliceStatus.FinishVectoring;
|
||||
mutateSliceListData({
|
||||
...sliceListData,
|
||||
list: newList,
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
return {
|
||||
tableSegmentModalNode,
|
||||
openTableSegmentModal,
|
||||
fetchCreateTableSegment,
|
||||
fetchUpdateTableSegment,
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,176 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { cloneDeep } from 'lodash-es';
|
||||
import { useKnowledgeStore } from '@coze-data/knowledge-stores';
|
||||
import { transSliceContentOutput } from '@coze-data/knowledge-modal-base';
|
||||
import { type TableViewRecord } from '@coze-common/table-view';
|
||||
import { ColumnType } from '@coze-arch/bot-api/knowledge';
|
||||
|
||||
import { type DatasetDataScrollList, updateSlice } from '@/service';
|
||||
|
||||
import { useCreateSlice } from '../inner/use-create-slice';
|
||||
import { useTableUI } from '../../context/table-ui-context';
|
||||
import { useTableData } from '../../context/table-data-context';
|
||||
import { useTableActions } from '../../context/table-actions-context';
|
||||
|
||||
export const useTableSliceOperations = ({
|
||||
openDeleteSliceModal,
|
||||
openTableSegmentModal,
|
||||
}: {
|
||||
openDeleteSliceModal: () => void;
|
||||
openTableSegmentModal: (content: string) => void;
|
||||
}) => {
|
||||
const documentList = useKnowledgeStore(state => state.documentList);
|
||||
const { mutateSliceListData, setDelSliceIds, setCurIndex, setCurSliceId } =
|
||||
useTableActions();
|
||||
const { createSlice } = useCreateSlice();
|
||||
const { sliceListData } = useTableData();
|
||||
const { tableViewRef } = useTableUI();
|
||||
const curDoc = documentList?.[0];
|
||||
const slices = sliceListData?.list;
|
||||
|
||||
const handleDeleteSlice = (indexs: number[]) => {
|
||||
if (!slices) {
|
||||
return;
|
||||
}
|
||||
|
||||
/** 新增的行 */
|
||||
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值
|
||||
const sliceIds = oldIndex
|
||||
.map(i => slices[i].slice_id)
|
||||
.filter(Boolean) as string[];
|
||||
|
||||
if (addIds.length && sliceIds.length <= 0) {
|
||||
mutateSliceListData({
|
||||
...sliceListData,
|
||||
total: Number(sliceListData?.total ?? '0'),
|
||||
list: slices.filter(item => !addIds.includes(item?.addId)),
|
||||
} satisfies DatasetDataScrollList);
|
||||
tableViewRef?.current?.resetSelected();
|
||||
}
|
||||
|
||||
if (sliceIds.length) {
|
||||
setDelSliceIds(sliceIds);
|
||||
openDeleteSliceModal();
|
||||
}
|
||||
};
|
||||
|
||||
const handleCreateSlice = (createParams: string) => {
|
||||
if (!curDoc?.document_id) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
return {
|
||||
document_id: curDoc.document_id,
|
||||
raw_text: createParams,
|
||||
};
|
||||
} catch (error) {
|
||||
console.log('error', error);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
const handleUpdateSliceData = async (
|
||||
record: TableViewRecord,
|
||||
index: number,
|
||||
updateValue?: string,
|
||||
) => {
|
||||
if (!slices) {
|
||||
return;
|
||||
}
|
||||
|
||||
const oldData = cloneDeep(sliceListData);
|
||||
try {
|
||||
const sliceId = slices[index].slice_id;
|
||||
const filterRecord = Object.fromEntries(
|
||||
Object.entries(record).filter(
|
||||
([key]) => !['tableViewKey', 'char_count', 'hit_count'].includes(key),
|
||||
),
|
||||
);
|
||||
|
||||
const ImageIds: string[] = [];
|
||||
curDoc?.table_meta?.forEach(meta => {
|
||||
if (meta.column_type === ColumnType.Image) {
|
||||
ImageIds.push(meta.id as string);
|
||||
}
|
||||
});
|
||||
|
||||
const formatRecord = Object.fromEntries(
|
||||
Object.entries(filterRecord).map(([key, value]) => {
|
||||
if (ImageIds.includes(key)) {
|
||||
return [key, transSliceContentOutput(value as string)];
|
||||
}
|
||||
return [key, value];
|
||||
}),
|
||||
);
|
||||
|
||||
const updateParams = { ...formatRecord };
|
||||
delete updateParams.status;
|
||||
const updateContent = JSON.stringify(updateParams);
|
||||
|
||||
if (sliceId) {
|
||||
await updateSlice(sliceId as string, updateContent, updateValue);
|
||||
} else {
|
||||
/** 新增分片 */
|
||||
const createParams = await handleCreateSlice(updateContent);
|
||||
if (createParams && createSlice && curDoc?.document_id) {
|
||||
// 调用传入的createSlice方法创建新的分片
|
||||
try {
|
||||
// 这里需要使用props中传入的createSlice方法来调用API
|
||||
await createSlice({
|
||||
document_id: curDoc.document_id,
|
||||
raw_text: updateContent,
|
||||
});
|
||||
} catch (error) {
|
||||
console.log('createSlice error:', error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 改为接口请求成功后才更新
|
||||
if (slices) {
|
||||
return true;
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
mutateSliceListData(oldData);
|
||||
throw Error(error as string);
|
||||
}
|
||||
};
|
||||
|
||||
/** 弹窗编辑切片 */
|
||||
const handleModalEditSlice = (_record: TableViewRecord, index: number) => {
|
||||
if (!slices || index < 0 || index >= slices.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
setCurIndex(index);
|
||||
setCurSliceId(slices[index]?.slice_id || '');
|
||||
openTableSegmentModal(slices[index]?.content || '');
|
||||
};
|
||||
|
||||
return {
|
||||
deleteSlice: handleDeleteSlice,
|
||||
createSlice: handleCreateSlice,
|
||||
modalEditSlice: handleModalEditSlice,
|
||||
rowUpdateSliceData: handleUpdateSliceData,
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,398 @@
|
||||
/* stylelint-disable declaration-no-important */
|
||||
/* stylelint-disable no-descending-specificity */
|
||||
|
||||
@import '../../assets/common.less';
|
||||
|
||||
.slice-list-ui-content {
|
||||
overflow: auto;
|
||||
flex: 1;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.empty-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding-bottom: 5%;
|
||||
}
|
||||
|
||||
.slice-modal-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.tag {
|
||||
margin-left: 6px;
|
||||
}
|
||||
}
|
||||
|
||||
.serial-number-text {
|
||||
font-size: 12px;
|
||||
color: var(--coz-fg-secondary);
|
||||
|
||||
}
|
||||
|
||||
.unit-table-view {
|
||||
.serial-number {
|
||||
padding-left: 0 !important;
|
||||
font-size: 14px !important;
|
||||
color: var(--coz-fg-secondary);
|
||||
}
|
||||
|
||||
|
||||
:global {
|
||||
.coz-tag {
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.data-tags {
|
||||
min-width: 173px;
|
||||
}
|
||||
|
||||
.semi-table-wrapper {
|
||||
margin-top: 0 !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.slice-article {
|
||||
position: relative;
|
||||
|
||||
overflow-y: auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
height: calc(100% - 24px);
|
||||
padding: 0 16px;
|
||||
|
||||
background-color: var(--coz-bg-plus);
|
||||
border: 1px solid var(--coz-stroke-primary);
|
||||
border-radius: 8px;
|
||||
|
||||
.slice-article-content {
|
||||
padding: 12px 2px;
|
||||
}
|
||||
}
|
||||
|
||||
.text-slice-toolbar {
|
||||
position: sticky;
|
||||
z-index: 10;
|
||||
top: 0;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
padding: 12px 0;
|
||||
|
||||
background-color: var(--coz-bg-plus);
|
||||
border-bottom: 1px solid var(--coz-stroke-primary);
|
||||
|
||||
.content-left-slot {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
|
||||
.doc-tag-wrapper {
|
||||
margin-left: 12px;
|
||||
}
|
||||
|
||||
.menu_wrapper {
|
||||
border-radius: 8px !important;
|
||||
}
|
||||
|
||||
.menu {
|
||||
width: 160px;
|
||||
padding: 4px;
|
||||
|
||||
:global {
|
||||
.semi-dropdown-item {
|
||||
height: 32px;
|
||||
padding: 8px;
|
||||
font-size: 12px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.semi-icon>svg {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
}
|
||||
|
||||
.semi-dropdown-item-disabled>.semi-dropdown-item-icon {
|
||||
opacity: 0.3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.slice-list-table {
|
||||
overflow-y: hidden;
|
||||
grid-auto-rows: min-content;
|
||||
grid-gap: 16px;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.table-view-container-box {
|
||||
max-height: calc(100% - 51px);
|
||||
// overflow-y: scroll;
|
||||
}
|
||||
|
||||
.add-row-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 48px;
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.spin {
|
||||
:global {
|
||||
.semi-spin-wrapper {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.semi-tabs-content {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.semi-spin-children {
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.doc-selector-dropdown {
|
||||
:global {
|
||||
.option-prefix-icon {
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.semi-select-option {
|
||||
cursor: pointer;
|
||||
|
||||
position: relative;
|
||||
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
align-items: center;
|
||||
|
||||
box-sizing: border-box;
|
||||
padding: 8px 16px;
|
||||
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
line-height: 16px;
|
||||
word-break: break-word;
|
||||
|
||||
border-radius: 4px;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.doc-selector-dropdown,
|
||||
.doc-selector {
|
||||
overflow: hidden;
|
||||
max-width: 723px;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
|
||||
:global {
|
||||
.semi-input-wrapper {
|
||||
width: 100% !important;
|
||||
min-width: 256px;
|
||||
}
|
||||
|
||||
.coz-select-option-item.selected {
|
||||
.doc-name-item {
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.doc-option {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
max-width: 603px;
|
||||
|
||||
color: var(--coz-fg-primary);
|
||||
}
|
||||
|
||||
.doc-name {
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex: 1;
|
||||
|
||||
margin: 0 8px;
|
||||
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
line-height: 20px;
|
||||
color: var(--coz-fg-primary);
|
||||
|
||||
&-selected {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
&-prev {
|
||||
overflow: hidden;
|
||||
display: inline-block;
|
||||
flex: 1;
|
||||
|
||||
text-overflow: ellipsis;
|
||||
white-space:nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.borderless-filter-render {
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.borderless-filter-text {
|
||||
font-weight: 600;
|
||||
color: #1c1f23;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
.filter-icon {
|
||||
margin-bottom: -2px;
|
||||
margin-left: 2px;
|
||||
}
|
||||
|
||||
.doc-selector-trigger {
|
||||
cursor: pointer;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
height: 32px;
|
||||
padding: 0 12px;
|
||||
|
||||
font-size: 14px;
|
||||
color: var(--coz-fg-primary);
|
||||
|
||||
border-radius: 8px;
|
||||
|
||||
&:hover {
|
||||
background-color: var(--coz-mg-secondary-pressed, rgba(6, 7, 9, 14%));
|
||||
}
|
||||
|
||||
&-label {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
&-icon {
|
||||
cursor: pointer;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
|
||||
border-radius: 6px;
|
||||
|
||||
&:hover {
|
||||
background-color: var(--coz-mg-secondary-pressed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.edit-doc-name-container {
|
||||
&-title {
|
||||
margin-bottom: 12px;
|
||||
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
line-height: 20px;
|
||||
color: var(--coz-fg-plus);
|
||||
}
|
||||
|
||||
&-input {
|
||||
padding-bottom: 12px;
|
||||
|
||||
&-error {
|
||||
padding: 2px 8px 0;
|
||||
font-size: 12px;
|
||||
line-height: 16px;
|
||||
color: var(--coz-fg-hglt-red);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.table-preview-max {
|
||||
:global(.table-wrapper) {
|
||||
:global {
|
||||
// 为什么这么写 请看 packages/components/table-view/src/components/table-view/index.module.less(15-21)
|
||||
.semi-table-tbody>.semi-table-row,
|
||||
.semi-table-thead>.semi-table-row>.semi-table-row-head,
|
||||
.semi-table-tbody>.semi-table-row>.semi-table-cell-fixed-left,
|
||||
.semi-table-thead>.semi-table-row>.semi-table-row-head.semi-table-cell-fixed-left::before,
|
||||
.semi-table-tbody>.semi-table-row>.semi-table-cell-fixed-right,
|
||||
.semi-table-thead>.semi-table-row>.semi-table-row-head.semi-table-cell-fixed-right::before {
|
||||
background-color: #FFF !important;
|
||||
}
|
||||
|
||||
.semi-table-tbody {
|
||||
.semi-table-row {
|
||||
&:hover {
|
||||
>.semi-table-row-cell {
|
||||
background-color: #F2F3F7 !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.semi-table-row-selected {
|
||||
.semi-table-row-cell,
|
||||
.semi-table-column-selection {
|
||||
background: #D8DBFB !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.table-preview-secondary {
|
||||
:global(.table-wrapper) {
|
||||
:global {
|
||||
// 为什么这么写 请看 packages/components/table-view/src/components/table-view/index.module.less(15-21)
|
||||
.semi-table-tbody>.semi-table-row,
|
||||
.semi-table-thead>.semi-table-row>.semi-table-row-head,
|
||||
.semi-table-tbody>.semi-table-row>.semi-table-cell-fixed-left,
|
||||
.semi-table-thead>.semi-table-row>.semi-table-row-head.semi-table-cell-fixed-left::before,
|
||||
.semi-table-tbody>.semi-table-row>.semi-table-cell-fixed-right,
|
||||
.semi-table-thead>.semi-table-row>.semi-table-row-head.semi-table-cell-fixed-right::before {
|
||||
background-color: #FCFCFF !important;
|
||||
}
|
||||
|
||||
.semi-table-tbody {
|
||||
.semi-table-row {
|
||||
&:hover {
|
||||
>.semi-table-row-cell {
|
||||
background-color: #EFF0F7 !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.semi-table-row-selected {
|
||||
.semi-table-row-cell,
|
||||
.semi-table-column-selection {
|
||||
background: #D9DDFF !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { TableKnowledgeWorkspace } from './components/main';
|
||||
|
||||
// 导出组件
|
||||
export { TableKnowledgeWorkspace };
|
||||
export type { TableKnowledgeWorkspaceProps } from './components/main';
|
||||
@@ -0,0 +1,271 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/* eslint-disable @coze-arch/max-line-per-function */
|
||||
import { get } from 'lodash-es';
|
||||
import { getDataTypeText } from '@coze-data/utils';
|
||||
import { getSrcFromImg } from '@coze-data/knowledge-modal-base';
|
||||
import { KnowledgeE2e } from '@coze-data/e2e';
|
||||
import {
|
||||
TextRender,
|
||||
ActionsRender,
|
||||
TagRender,
|
||||
ImageRender,
|
||||
type TableViewRecord,
|
||||
type TableViewColumns,
|
||||
colWidthCacheService,
|
||||
} from '@coze-common/table-view';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import { Tag, Tooltip, Typography } from '@coze-arch/coze-design';
|
||||
import { safeJSONParse } from '@coze-arch/bot-utils';
|
||||
import { ColumnType, SliceStatus } from '@coze-arch/bot-api/knowledge';
|
||||
|
||||
import { type TranSliceListParams } from '@/types/slice';
|
||||
|
||||
const MAX_WIDTH = 1400;
|
||||
const MIN_WIDTH = 200;
|
||||
const DIFF_WIDTH = 397;
|
||||
const READONLY_DIFF_WIDTH = 259;
|
||||
|
||||
export function isNoMore(data, pageSize) {
|
||||
return Boolean(
|
||||
!data?.total || (data.nextPageIndex - 1) * pageSize >= data.total,
|
||||
);
|
||||
}
|
||||
|
||||
export function isStop(res) {
|
||||
return res?.list?.length || res?.total;
|
||||
}
|
||||
|
||||
const ColumnTypeComp = (props: { columnType: ColumnType }) => (
|
||||
<Tag color="primary" className="ml-[6px] text-xs" size="mini">
|
||||
{getDataTypeText(props.columnType)}
|
||||
</Tag>
|
||||
);
|
||||
|
||||
const getTableCacheWidthMap = (tableKey: string) => {
|
||||
try {
|
||||
return colWidthCacheService.getTableWidthMap(tableKey) ?? {};
|
||||
} catch (e) {
|
||||
console.log('getTableCacheWidthMap error', e);
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* slice 数据转换为 TableView 组件接收的数据类型
|
||||
*/
|
||||
|
||||
export const getTableRenderColumnsData = ({
|
||||
sliceList,
|
||||
metaData = [],
|
||||
onEdit,
|
||||
onUpdate,
|
||||
onDelete,
|
||||
canEdit,
|
||||
tableKey,
|
||||
}: TranSliceListParams): {
|
||||
data: TableViewRecord[];
|
||||
columns: TableViewColumns[];
|
||||
} => {
|
||||
try {
|
||||
const dom = document.getElementsByClassName(
|
||||
'knowledge-ide-base-slice-list-ui-content',
|
||||
)[0];
|
||||
const cacheWidthMap = getTableCacheWidthMap(tableKey);
|
||||
const maxWidth = dom
|
||||
? (dom as HTMLElement).offsetWidth -
|
||||
(canEdit ? DIFF_WIDTH : READONLY_DIFF_WIDTH)
|
||||
: MAX_WIDTH;
|
||||
const res: TableViewRecord[] = sliceList.map(slice => {
|
||||
const { char_count, hit_count, status } = slice;
|
||||
const record = { char_count, hit_count, status };
|
||||
const sliceArr = safeJSONParse(slice.content);
|
||||
if (Array.isArray(sliceArr)) {
|
||||
sliceArr.forEach(sliceData => {
|
||||
record[sliceData.column_id] = sliceData.value;
|
||||
});
|
||||
}
|
||||
return record;
|
||||
});
|
||||
const dataWidth =
|
||||
maxWidth / metaData.length > MIN_WIDTH
|
||||
? maxWidth / metaData.length
|
||||
: MIN_WIDTH;
|
||||
const columns: TableViewColumns[] = metaData.map((meta, columnIndex) => ({
|
||||
dataIndex: meta.id,
|
||||
title: (
|
||||
<div className="flex flex-row items-center">
|
||||
<Typography.Text
|
||||
className="cursor-pointer"
|
||||
ellipsis={{
|
||||
showTooltip: {
|
||||
opts: { content: meta.column_name },
|
||||
},
|
||||
}}
|
||||
>
|
||||
{meta.column_name}
|
||||
</Typography.Text>
|
||||
{meta.is_semantic ? (
|
||||
<Tag
|
||||
size="mini"
|
||||
color="green"
|
||||
className="ml-2"
|
||||
data-testid={KnowledgeE2e.TableLocalPreviewSemantic}
|
||||
>
|
||||
{I18n.t('knowledge_1226_001')}
|
||||
</Tag>
|
||||
) : null}
|
||||
{meta.column_type ? (
|
||||
<ColumnTypeComp columnType={meta.column_type} />
|
||||
) : null}
|
||||
</div>
|
||||
),
|
||||
width: get(cacheWidthMap, meta.id || '') ?? dataWidth,
|
||||
render: (text, record, index) => {
|
||||
const isEditing =
|
||||
columnIndex === 0 &&
|
||||
index === sliceList.length - 1 &&
|
||||
!!sliceList[index].addId;
|
||||
if (meta.column_type === ColumnType.Image) {
|
||||
const srcList = getSrcFromImg(text);
|
||||
return (
|
||||
<ImageRender
|
||||
srcList={srcList}
|
||||
onChange={(src, tosKey) => {
|
||||
let val = '';
|
||||
if (src || tosKey) {
|
||||
val = `<img src="${src ?? ''}" ${
|
||||
tosKey ? `data-tos-key="${tosKey}"` : ''
|
||||
}>`;
|
||||
}
|
||||
const newRecord = { ...record, [meta?.id as string]: val };
|
||||
onUpdate?.(newRecord, index);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
// 针对违规内容高亮处理
|
||||
const isAudiFailed = record?.status === SliceStatus.AuditFailed;
|
||||
const textRender = () => (
|
||||
<div className={`w-full ${isAudiFailed ? 'text-red-500' : ''}`}>
|
||||
<TextRender
|
||||
dataIndex={meta.id}
|
||||
value={text}
|
||||
record={record}
|
||||
index={index}
|
||||
isEditing={isEditing}
|
||||
editable={canEdit}
|
||||
validator={{
|
||||
validate: value => {
|
||||
if (meta.is_semantic) {
|
||||
return !value || value === '';
|
||||
}
|
||||
return false;
|
||||
},
|
||||
errorMsg: I18n.t('datasets_url_empty'),
|
||||
}}
|
||||
onBlur={async (_text, updateRecord) =>
|
||||
await onUpdate?.(updateRecord, index, _text as string)
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
if (isAudiFailed) {
|
||||
return (
|
||||
<Tooltip
|
||||
content={I18n.t('knowledge_content_illegal_error_msg')}
|
||||
trigger="hover"
|
||||
position="top"
|
||||
getPopupContainer={() => document.body}
|
||||
>
|
||||
{textRender()}
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
return textRender();
|
||||
},
|
||||
}));
|
||||
columns.push({
|
||||
title: '',
|
||||
className: 'not-resize-handle data-tags',
|
||||
resize: false,
|
||||
render: (_text, record, _index) => {
|
||||
const { char_count, hit_count } = record;
|
||||
return (
|
||||
<div className="flex gap-3">
|
||||
<TagRender
|
||||
value={`${char_count ?? 0} ${I18n.t('datasets_segment_card_bit', {
|
||||
num: char_count ?? 0,
|
||||
})}`}
|
||||
/>
|
||||
<TagRender
|
||||
value={I18n.t('datasets_segment_card_hit', {
|
||||
num: hit_count ?? 0,
|
||||
})}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
});
|
||||
if (canEdit) {
|
||||
columns.push({
|
||||
title: '',
|
||||
width: 100,
|
||||
className: 'not-resize-handle',
|
||||
resize: false,
|
||||
render: (_text, record, index) => (
|
||||
<ActionsRender
|
||||
record={record}
|
||||
index={index}
|
||||
editProps={{
|
||||
disabled: false,
|
||||
onEdit: () => {
|
||||
onEdit?.(record, index);
|
||||
},
|
||||
}}
|
||||
deleteProps={{
|
||||
disabled: false,
|
||||
onDelete: () => {
|
||||
onDelete?.([index]);
|
||||
},
|
||||
}}
|
||||
/>
|
||||
),
|
||||
});
|
||||
}
|
||||
columns.unshift({
|
||||
title: '',
|
||||
width: 68,
|
||||
fixed: true,
|
||||
resize: false,
|
||||
className: 'pl-0 text-sm not-resize-handle',
|
||||
render: (_text, _record, index) => (
|
||||
<div className="text-xs coz-fg-secondary">{index + 1}</div>
|
||||
),
|
||||
});
|
||||
return {
|
||||
data: res,
|
||||
columns,
|
||||
};
|
||||
} catch (error) {
|
||||
console.log('transSliceList handler error', error);
|
||||
return {
|
||||
data: [],
|
||||
columns: [],
|
||||
};
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,398 @@
|
||||
/* stylelint-disable declaration-no-important */
|
||||
/* stylelint-disable no-descending-specificity */
|
||||
|
||||
@import '../../../assets/common.less';
|
||||
|
||||
.slice-list-ui-content {
|
||||
overflow: auto;
|
||||
flex: 1;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.empty-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding-bottom: 5%;
|
||||
}
|
||||
|
||||
.slice-modal-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.tag {
|
||||
margin-left: 6px;
|
||||
}
|
||||
}
|
||||
|
||||
.serial-number-text {
|
||||
font-size: 12px;
|
||||
color: var(--coz-fg-secondary);
|
||||
|
||||
}
|
||||
|
||||
.unit-table-view {
|
||||
.serial-number {
|
||||
padding-left: 0 !important;
|
||||
font-size: 14px !important;
|
||||
color: var(--coz-fg-secondary);
|
||||
}
|
||||
|
||||
|
||||
:global {
|
||||
.coz-tag {
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.data-tags {
|
||||
min-width: 173px;
|
||||
}
|
||||
|
||||
.semi-table-wrapper {
|
||||
margin-top: 0 !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.slice-article {
|
||||
position: relative;
|
||||
|
||||
overflow-y: auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
height: calc(100% - 24px);
|
||||
padding: 0 16px;
|
||||
|
||||
background-color: var(--coz-bg-plus);
|
||||
border: 1px solid var(--coz-stroke-primary);
|
||||
border-radius: 8px;
|
||||
|
||||
.slice-article-content {
|
||||
padding: 12px 2px;
|
||||
}
|
||||
}
|
||||
|
||||
.text-slice-toolbar {
|
||||
position: sticky;
|
||||
z-index: 10;
|
||||
top: 0;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
padding: 12px 0;
|
||||
|
||||
background-color: var(--coz-bg-plus);
|
||||
border-bottom: 1px solid var(--coz-stroke-primary);
|
||||
|
||||
.content-left-slot {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
|
||||
.doc-tag-wrapper {
|
||||
margin-left: 12px;
|
||||
}
|
||||
|
||||
.menu_wrapper {
|
||||
border-radius: 8px !important;
|
||||
}
|
||||
|
||||
.menu {
|
||||
width: 160px;
|
||||
padding: 4px;
|
||||
|
||||
:global {
|
||||
.semi-dropdown-item {
|
||||
height: 32px;
|
||||
padding: 8px;
|
||||
font-size: 12px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.semi-icon>svg {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
}
|
||||
|
||||
.semi-dropdown-item-disabled>.semi-dropdown-item-icon {
|
||||
opacity: 0.3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.slice-list-table {
|
||||
overflow-y: hidden;
|
||||
grid-auto-rows: min-content;
|
||||
grid-gap: 16px;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.table-view-container-box {
|
||||
max-height: calc(100% - 51px);
|
||||
// overflow-y: scroll;
|
||||
}
|
||||
|
||||
.add-row-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 48px;
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.spin {
|
||||
:global {
|
||||
.semi-spin-wrapper {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.semi-tabs-content {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.semi-spin-children {
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.doc-selector-dropdown {
|
||||
:global {
|
||||
.option-prefix-icon {
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.semi-select-option {
|
||||
cursor: pointer;
|
||||
|
||||
position: relative;
|
||||
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
align-items: center;
|
||||
|
||||
box-sizing: border-box;
|
||||
padding: 8px 16px;
|
||||
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
line-height: 16px;
|
||||
word-break: break-word;
|
||||
|
||||
border-radius: 4px;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.doc-selector-dropdown,
|
||||
.doc-selector {
|
||||
overflow: hidden;
|
||||
max-width: 723px;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
|
||||
:global {
|
||||
.semi-input-wrapper {
|
||||
width: 100% !important;
|
||||
min-width: 256px;
|
||||
}
|
||||
|
||||
.coz-select-option-item.selected {
|
||||
.doc-name-item {
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.doc-option {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
max-width: 603px;
|
||||
|
||||
color: var(--coz-fg-primary);
|
||||
}
|
||||
|
||||
.doc-name {
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex: 1;
|
||||
|
||||
margin: 0 8px;
|
||||
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
line-height: 20px;
|
||||
color: var(--coz-fg-primary);
|
||||
|
||||
&-selected {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
&-prev {
|
||||
overflow: hidden;
|
||||
display: inline-block;
|
||||
flex: 1;
|
||||
|
||||
text-overflow: ellipsis;
|
||||
white-space:nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.borderless-filter-render {
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.borderless-filter-text {
|
||||
font-weight: 600;
|
||||
color: #1c1f23;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
.filter-icon {
|
||||
margin-bottom: -2px;
|
||||
margin-left: 2px;
|
||||
}
|
||||
|
||||
.doc-selector-trigger {
|
||||
cursor: pointer;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
height: 32px;
|
||||
padding: 0 12px;
|
||||
|
||||
font-size: 14px;
|
||||
color: var(--coz-fg-primary);
|
||||
|
||||
border-radius: 8px;
|
||||
|
||||
&:hover {
|
||||
background-color: var(--coz-mg-secondary-pressed, rgba(6, 7, 9, 14%));
|
||||
}
|
||||
|
||||
&-label {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
&-icon {
|
||||
cursor: pointer;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
|
||||
border-radius: 6px;
|
||||
|
||||
&:hover {
|
||||
background-color: var(--coz-mg-secondary-pressed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.edit-doc-name-container {
|
||||
&-title {
|
||||
margin-bottom: 12px;
|
||||
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
line-height: 20px;
|
||||
color: var(--coz-fg-plus);
|
||||
}
|
||||
|
||||
&-input {
|
||||
padding-bottom: 12px;
|
||||
|
||||
&-error {
|
||||
padding: 2px 8px 0;
|
||||
font-size: 12px;
|
||||
line-height: 16px;
|
||||
color: var(--coz-fg-hglt-red);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.table-preview-max {
|
||||
:global(.table-wrapper) {
|
||||
:global {
|
||||
// 为什么这么写 请看 packages/components/table-view/src/components/table-view/index.module.less(15-21)
|
||||
.semi-table-tbody>.semi-table-row,
|
||||
.semi-table-thead>.semi-table-row>.semi-table-row-head,
|
||||
.semi-table-tbody>.semi-table-row>.semi-table-cell-fixed-left,
|
||||
.semi-table-thead>.semi-table-row>.semi-table-row-head.semi-table-cell-fixed-left::before,
|
||||
.semi-table-tbody>.semi-table-row>.semi-table-cell-fixed-right,
|
||||
.semi-table-thead>.semi-table-row>.semi-table-row-head.semi-table-cell-fixed-right::before {
|
||||
background-color: #FFF !important;
|
||||
}
|
||||
|
||||
.semi-table-tbody {
|
||||
.semi-table-row {
|
||||
&:hover {
|
||||
>.semi-table-row-cell {
|
||||
background-color: #F2F3F7 !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.semi-table-row-selected {
|
||||
.semi-table-row-cell,
|
||||
.semi-table-column-selection {
|
||||
background: #D8DBFB !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.table-preview-secondary {
|
||||
:global(.table-wrapper) {
|
||||
:global {
|
||||
// 为什么这么写 请看 packages/components/table-view/src/components/table-view/index.module.less(15-21)
|
||||
.semi-table-tbody>.semi-table-row,
|
||||
.semi-table-thead>.semi-table-row>.semi-table-row-head,
|
||||
.semi-table-tbody>.semi-table-row>.semi-table-cell-fixed-left,
|
||||
.semi-table-thead>.semi-table-row>.semi-table-row-head.semi-table-cell-fixed-left::before,
|
||||
.semi-table-tbody>.semi-table-row>.semi-table-cell-fixed-right,
|
||||
.semi-table-thead>.semi-table-row>.semi-table-row-head.semi-table-cell-fixed-right::before {
|
||||
background-color: #FCFCFF !important;
|
||||
}
|
||||
|
||||
.semi-table-tbody {
|
||||
.semi-table-row {
|
||||
&:hover {
|
||||
>.semi-table-row-cell {
|
||||
background-color: #EFF0F7 !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.semi-table-row-selected {
|
||||
.semi-table-row-cell,
|
||||
.semi-table-column-selection {
|
||||
background: #D9DDFF !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import classnames from 'classnames';
|
||||
import { IllustrationNoResult } from '@douyinfe/semi-illustrations';
|
||||
import { useKnowledgeStore } from '@coze-data/knowledge-stores';
|
||||
import { type DocumentChunk } from '@coze-data/knowledge-common-components/text-knowledge-editor/scenes/base';
|
||||
import { BaseTextKnowledgeEditor } from '@coze-data/knowledge-common-components/text-knowledge-editor';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import { EmptyState } from '@coze-arch/coze-design';
|
||||
import { IconSegmentEmpty } from '@coze-arch/bot-icons';
|
||||
|
||||
import styles from '../styles/index.module.less';
|
||||
|
||||
export interface BaseContentProps {
|
||||
loading: boolean;
|
||||
isProcessing: boolean;
|
||||
documentId: string;
|
||||
renderData: DocumentChunk[];
|
||||
onContentChange: (chunks: DocumentChunk[]) => void;
|
||||
onAddChunk: () => void;
|
||||
onDeleteChunk: (chunk: DocumentChunk) => void;
|
||||
}
|
||||
|
||||
export const BaseContent: React.FC<BaseContentProps> = ({
|
||||
loading,
|
||||
isProcessing,
|
||||
documentId,
|
||||
renderData,
|
||||
onContentChange,
|
||||
onAddChunk,
|
||||
onDeleteChunk,
|
||||
}) => {
|
||||
const canEdit = useKnowledgeStore(state => state.canEdit);
|
||||
const searchValue = useKnowledgeStore(state => state.searchValue);
|
||||
|
||||
if (renderData?.length === 0 && !loading) {
|
||||
return (
|
||||
<div className={classnames(styles['empty-content'])}>
|
||||
<EmptyState
|
||||
size="large"
|
||||
icon={
|
||||
searchValue ? (
|
||||
<IllustrationNoResult style={{ width: 150, height: '100%' }} />
|
||||
) : (
|
||||
<IconSegmentEmpty style={{ width: 150, height: '100%' }} />
|
||||
)
|
||||
}
|
||||
title={
|
||||
isProcessing
|
||||
? I18n.t('content_view_003')
|
||||
: searchValue
|
||||
? I18n.t('knowledge_no_result')
|
||||
: I18n.t('dataset_segment_empty_desc')
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={styles['slice-article-content']}>
|
||||
<BaseTextKnowledgeEditor
|
||||
chunks={renderData}
|
||||
documentId={documentId}
|
||||
readonly={!canEdit}
|
||||
onChange={onContentChange}
|
||||
onAddChunk={onAddChunk}
|
||||
onDeleteChunk={onDeleteChunk}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,228 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/* eslint-disable @coze-arch/max-line-per-function */
|
||||
import { useState } from 'react';
|
||||
|
||||
import classNames from 'classnames';
|
||||
import { useDebounceFn } from 'ahooks';
|
||||
import { KnowledgeE2e } from '@coze-data/e2e';
|
||||
import { logger } from '@coze-arch/logger';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import { IconCozEdit } from '@coze-arch/coze-design/icons';
|
||||
import {
|
||||
Popover,
|
||||
Select,
|
||||
Tooltip,
|
||||
Button,
|
||||
TextArea,
|
||||
Search,
|
||||
} from '@coze-arch/coze-design';
|
||||
import { type OptionProps } from '@coze-arch/bot-semi/Select';
|
||||
import { type FormatType } from '@coze-arch/bot-api/knowledge';
|
||||
|
||||
import styles from '../styles/index.module.less';
|
||||
|
||||
export interface DocSelectorProps<T> {
|
||||
type: FormatType;
|
||||
options: OptionProps[];
|
||||
value: T;
|
||||
canEdit?: boolean;
|
||||
onChange: (v: T) => void;
|
||||
onRename: (docId: string, newName: string) => void;
|
||||
}
|
||||
|
||||
const DOC_NAME_MAX_LEN = 100;
|
||||
export const DocSelector = ({
|
||||
type,
|
||||
options,
|
||||
value,
|
||||
onChange,
|
||||
canEdit,
|
||||
onRename,
|
||||
}: DocSelectorProps<typeof value>) => {
|
||||
const [search, setSearch] = useState('');
|
||||
const [searchValue, setSearchValue] = useState('');
|
||||
const [docName, setDocName] = useState('');
|
||||
const [visible, setVisible] = useState(false);
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
const debounceSetSearch = useDebounceFn(
|
||||
(v?: string) => {
|
||||
setSearchValue(v || '');
|
||||
},
|
||||
{
|
||||
wait: 300,
|
||||
},
|
||||
);
|
||||
|
||||
const handledOptions = options.filter(op => {
|
||||
if (!searchValue) {
|
||||
return true;
|
||||
}
|
||||
try {
|
||||
const regx = new RegExp(searchValue);
|
||||
// 搜索结果不展示「全部内容」选项
|
||||
return (
|
||||
(op.value !== 'all' && op.value === value) ||
|
||||
(op?.text as string)?.match(regx)
|
||||
);
|
||||
} catch (e) {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
const setDocNameFn = () => {
|
||||
const name = options.find(op => op.value === value)?.text;
|
||||
if (name) {
|
||||
setDocName(name as string);
|
||||
}
|
||||
};
|
||||
|
||||
const handleEditDocName = e => {
|
||||
e.stopPropagation();
|
||||
setVisible(true);
|
||||
};
|
||||
|
||||
const handleSaveDocName = () => {
|
||||
if (!docName) {
|
||||
return;
|
||||
}
|
||||
setLoading(true);
|
||||
|
||||
try {
|
||||
onRename(value as string, docName);
|
||||
setVisible(false);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const triggerRender = ({ value: values }) => (
|
||||
<Popover
|
||||
clickToHide={true}
|
||||
visible={visible}
|
||||
onClickOutSide={() => setVisible(false)}
|
||||
trigger="custom"
|
||||
style={{ padding: 16, width: 320 }}
|
||||
onVisibleChange={v => {
|
||||
if (v) {
|
||||
setDocNameFn();
|
||||
}
|
||||
}}
|
||||
content={
|
||||
<div
|
||||
className={styles['edit-doc-name-container']}
|
||||
onClick={e => e.stopPropagation()}
|
||||
>
|
||||
<div className={styles['edit-doc-name-container-title']}>
|
||||
{I18n.t('knowledge_detail_doc_rename')}
|
||||
</div>
|
||||
<div className={styles['edit-doc-name-container-input']}>
|
||||
<TextArea
|
||||
value={docName}
|
||||
maxLength={DOC_NAME_MAX_LEN}
|
||||
maxCount={DOC_NAME_MAX_LEN}
|
||||
validateStatus={!docName ? 'error' : 'default'}
|
||||
placeholder={I18n.t('knowledge_upload_text_custom_doc_name_tips')}
|
||||
onChange={v => setDocName(v)}
|
||||
/>
|
||||
{!docName && (
|
||||
<div className={styles['edit-doc-name-container-input-error']}>
|
||||
{I18n.t('knowledge_upload_text_custom_doc_name_tips')}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="text-right">
|
||||
<Button
|
||||
disabled={!docName}
|
||||
onClick={handleSaveDocName}
|
||||
size="small"
|
||||
loading={loading}
|
||||
>
|
||||
{I18n.t('Save')}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
position="bottomLeft"
|
||||
>
|
||||
<div
|
||||
onClick={() => {
|
||||
setVisible(false);
|
||||
}}
|
||||
className={styles['doc-selector-trigger']}
|
||||
data-testid={KnowledgeE2e.SegmentDetailContentSelectTrigger}
|
||||
>
|
||||
<div className={styles['doc-selector-trigger-label']}>
|
||||
{values.map(item => (
|
||||
<div key={item.value}>{item.label}</div>
|
||||
))}
|
||||
</div>
|
||||
{!canEdit || !value ? null : (
|
||||
<div>
|
||||
<Tooltip
|
||||
clickToHide
|
||||
theme="dark"
|
||||
content={I18n.t('knowledge_detail_doc_rename')}
|
||||
>
|
||||
<div
|
||||
className={styles['doc-selector-trigger-icon']}
|
||||
onClick={handleEditDocName}
|
||||
data-testid={
|
||||
KnowledgeE2e.SegmentDetailContentSelectTriggerEditIcon
|
||||
}
|
||||
>
|
||||
<IconCozEdit className={'text-[14px]'} />
|
||||
</div>
|
||||
</Tooltip>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</Popover>
|
||||
);
|
||||
|
||||
return (
|
||||
<Select
|
||||
clickToHide={true}
|
||||
maxHeight={670}
|
||||
disabled
|
||||
className={classNames(styles['doc-selector'])}
|
||||
dropdownClassName={styles['doc-selector-dropdown']}
|
||||
optionList={handledOptions}
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
getPopupContainer={() => document.body}
|
||||
triggerRender={triggerRender}
|
||||
innerTopSlot={
|
||||
<Search
|
||||
value={search}
|
||||
placeholder={I18n.t('datasets_placeholder_search')}
|
||||
onChange={v => {
|
||||
setSearch(v);
|
||||
}}
|
||||
onSearch={v => {
|
||||
logger.info({
|
||||
message: 'onSearch',
|
||||
meta: { v },
|
||||
});
|
||||
debounceSetSearch.run(v);
|
||||
}}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { useMemo } from 'react';
|
||||
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import { Space, Tag } from '@coze-arch/coze-design';
|
||||
import {
|
||||
ChunkType,
|
||||
DocumentSource,
|
||||
FormatType,
|
||||
type DocumentInfo,
|
||||
} from '@coze-arch/bot-api/knowledge';
|
||||
|
||||
import { getSourceName } from '@/utils';
|
||||
import { DOCUMENT_UPDATE_TYPE_MAP } from '@/constant';
|
||||
|
||||
import styles from '../styles/index.module.less';
|
||||
|
||||
export interface DocTagProps {
|
||||
documentInfo?: DocumentInfo;
|
||||
}
|
||||
|
||||
export const DocTag: React.FC<DocTagProps> = ({ documentInfo }) => {
|
||||
const updateFrequencyStr = useMemo(() => {
|
||||
let str: string = DOCUMENT_UPDATE_TYPE_MAP[documentInfo?.update_type ?? ''];
|
||||
if (documentInfo?.update_interval) {
|
||||
str = `${I18n.t('datasets_segment_tag_updateFrequency', {
|
||||
num: documentInfo.update_interval,
|
||||
})}`;
|
||||
}
|
||||
return str;
|
||||
}, [documentInfo]);
|
||||
|
||||
if (!documentInfo) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const renderSegmentTag = () => {
|
||||
const { format_type, chunk_strategy } = documentInfo;
|
||||
if (format_type !== FormatType.Text || !chunk_strategy) {
|
||||
return null;
|
||||
}
|
||||
if (chunk_strategy.chunk_type === ChunkType.CustomChunk) {
|
||||
return (
|
||||
<Tag color="primary" size="mini">
|
||||
{I18n.t('datasets_segment_tag_custom')}
|
||||
</Tag>
|
||||
);
|
||||
}
|
||||
if (chunk_strategy.chunk_type === ChunkType.LevelChunk) {
|
||||
return (
|
||||
<Tag color="primary" size="mini">
|
||||
{I18n.t('knowledge_level_016')}
|
||||
</Tag>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<Tag color="primary" size="mini">
|
||||
{I18n.t('datasets_segment_tag_auto')}
|
||||
</Tag>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<Space className={styles['doc-tag-wrapper']} spacing={4}>
|
||||
<Tag color="primary" size="mini">
|
||||
{getSourceName(documentInfo)}
|
||||
</Tag>
|
||||
{documentInfo.source_type === DocumentSource.Web && (
|
||||
<Tag color="primary" size="mini">
|
||||
{updateFrequencyStr}
|
||||
</Tag>
|
||||
)}
|
||||
{renderSegmentTag()}
|
||||
</Space>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import classnames from 'classnames';
|
||||
import {
|
||||
usePreviewPdf,
|
||||
PreviewMd,
|
||||
PreviewTxt,
|
||||
} from '@coze-data/knowledge-common-components';
|
||||
import {
|
||||
IconCozArrowLeft,
|
||||
IconCozArrowRight,
|
||||
IconCozMinus,
|
||||
IconCozPlus,
|
||||
} from '@coze-arch/coze-design/icons';
|
||||
import { IconButton } from '@coze-arch/coze-design';
|
||||
|
||||
export interface FilePreviewProps {
|
||||
fileType?: string;
|
||||
fileUrl: string;
|
||||
visible: boolean;
|
||||
}
|
||||
|
||||
export const FilePreview: React.FC<FilePreviewProps> = ({
|
||||
fileType,
|
||||
fileUrl,
|
||||
visible,
|
||||
}) => {
|
||||
const {
|
||||
pdfNode,
|
||||
numPages,
|
||||
currentPage,
|
||||
onNext,
|
||||
onBack,
|
||||
scale,
|
||||
increaseScale,
|
||||
decreaseScale,
|
||||
} = usePreviewPdf({
|
||||
fileUrl,
|
||||
});
|
||||
|
||||
return (
|
||||
<div
|
||||
className={classnames(
|
||||
'w-full h-full',
|
||||
'border border-solid coz-stroke-primary border-t-0 border-b-0 border-l-0',
|
||||
'flex flex-col items-center overflow-auto',
|
||||
!visible && 'hidden',
|
||||
)}
|
||||
>
|
||||
{(() => {
|
||||
if (fileType === 'md') {
|
||||
return <PreviewMd fileUrl={fileUrl} />;
|
||||
}
|
||||
|
||||
if (fileType === 'txt') {
|
||||
return <PreviewTxt fileUrl={fileUrl} />;
|
||||
}
|
||||
|
||||
if (['docx', 'pdf', 'doc'].includes(fileType ?? '')) {
|
||||
return (
|
||||
<div className="grow w-full relative">
|
||||
{numPages >= 1 ? (
|
||||
<div
|
||||
className={classnames(
|
||||
'flex w-fit h-[32px] items-center justify-center gap-[3px] absolute top-[8px] right-[8px]',
|
||||
'coz-bg-max rounded-[8px] coz-shadow-default',
|
||||
'z-10',
|
||||
'px-[8px]',
|
||||
)}
|
||||
>
|
||||
<IconButton
|
||||
icon={<IconCozArrowLeft />}
|
||||
size="small"
|
||||
color="secondary"
|
||||
onClick={onBack}
|
||||
></IconButton>
|
||||
<div className="coz-fg-secondary text-[12px] font-[400] leading-[24px]">
|
||||
{currentPage} / {numPages}
|
||||
</div>
|
||||
<IconButton
|
||||
icon={<IconCozArrowRight />}
|
||||
size="small"
|
||||
color="secondary"
|
||||
onClick={onNext}
|
||||
/>
|
||||
<div className="w-[1px] h-[12px] coz-mg-primary"></div>
|
||||
<IconButton
|
||||
icon={<IconCozMinus />}
|
||||
size="small"
|
||||
color="secondary"
|
||||
onClick={decreaseScale}
|
||||
/>
|
||||
<div className="coz-fg-secondary text-[12px] font-[400] leading-[16px]">
|
||||
{Math.round(scale * 100)}%
|
||||
</div>
|
||||
<IconButton
|
||||
icon={<IconCozPlus />}
|
||||
size="small"
|
||||
color="secondary"
|
||||
onClick={increaseScale}
|
||||
/>
|
||||
</div>
|
||||
) : null}
|
||||
{pdfNode}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
})()}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import classnames from 'classnames';
|
||||
import { IllustrationNoResult } from '@douyinfe/semi-illustrations';
|
||||
import {
|
||||
useKnowledgeStore,
|
||||
type ILevelSegment,
|
||||
} from '@coze-data/knowledge-stores';
|
||||
import { LevelTextKnowledgeEditor } from '@coze-data/knowledge-common-components/text-knowledge-editor';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import { EmptyState } from '@coze-arch/coze-design';
|
||||
import { IconSegmentEmpty } from '@coze-arch/bot-icons';
|
||||
|
||||
import { createLevelDocumentChunkByLevelSegment } from '../utils/document-utils';
|
||||
import styles from '../styles/index.module.less';
|
||||
|
||||
export interface LevelContentProps {
|
||||
isProcessing: boolean;
|
||||
documentId: string;
|
||||
levelSegments: ILevelSegment[];
|
||||
selectionIDs: string[];
|
||||
onLevelSegmentsChange: (chunks: ILevelSegment[]) => void;
|
||||
onLevelSegmentDelete: (chunk: ILevelSegment) => void;
|
||||
}
|
||||
|
||||
export const LevelContent: React.FC<LevelContentProps> = ({
|
||||
isProcessing,
|
||||
documentId,
|
||||
levelSegments,
|
||||
selectionIDs,
|
||||
onLevelSegmentsChange,
|
||||
onLevelSegmentDelete,
|
||||
}) => {
|
||||
const canEdit = useKnowledgeStore(state => state.canEdit);
|
||||
const searchValue = useKnowledgeStore(state => state.searchValue);
|
||||
|
||||
// 转换层级分段数据为编辑器可用格式
|
||||
const renderLevelSegmentsData = levelSegments.map(item =>
|
||||
createLevelDocumentChunkByLevelSegment(item),
|
||||
);
|
||||
|
||||
if (levelSegments.length === 0) {
|
||||
return (
|
||||
<div className={classnames(styles['empty-content'])}>
|
||||
<EmptyState
|
||||
size="large"
|
||||
icon={
|
||||
searchValue ? (
|
||||
<IllustrationNoResult style={{ width: 150, height: '100%' }} />
|
||||
) : (
|
||||
<IconSegmentEmpty style={{ width: 150, height: '100%' }} />
|
||||
)
|
||||
}
|
||||
title={
|
||||
isProcessing
|
||||
? I18n.t('content_view_003')
|
||||
: searchValue
|
||||
? I18n.t('knowledge_no_result')
|
||||
: I18n.t('dataset_segment_empty_desc')
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<LevelTextKnowledgeEditor
|
||||
chunks={renderLevelSegmentsData}
|
||||
selectionIDs={selectionIDs}
|
||||
documentId={documentId}
|
||||
readonly={!canEdit}
|
||||
onChange={onLevelSegmentsChange}
|
||||
onDeleteChunk={onLevelSegmentDelete}
|
||||
/>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,298 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/* eslint-disable @coze-arch/max-line-per-function */
|
||||
|
||||
/* eslint-disable complexity */
|
||||
import { type ReactNode, useRef } from 'react';
|
||||
|
||||
import classnames from 'classnames';
|
||||
import {
|
||||
useDataNavigate,
|
||||
useKnowledgeParams,
|
||||
useKnowledgeStore,
|
||||
} from '@coze-data/knowledge-stores';
|
||||
import {
|
||||
OptType,
|
||||
UnitType,
|
||||
} from '@coze-data/knowledge-resource-processor-core';
|
||||
import { SegmentMenu } from '@coze-data/knowledge-common-components';
|
||||
import { Spin } from '@coze-arch/coze-design';
|
||||
import {
|
||||
ChunkType,
|
||||
DocumentSource,
|
||||
type DocumentInfo,
|
||||
} from '@coze-arch/bot-api/knowledge';
|
||||
|
||||
import { type ProgressMap } from '@/types';
|
||||
|
||||
import { getDocumentOptions } from '../utils/document-utils';
|
||||
import { useModals } from '../hooks/use-case/use-modals';
|
||||
import { useInitSelectFirstDoc } from '../hooks/use-case/use-init-select-first-doc';
|
||||
import { useFilePreview } from '../hooks/use-case/use-file-preview';
|
||||
import { useDocumentManagement } from '../hooks/use-case/use-document-management';
|
||||
import {
|
||||
useDocumentInfo,
|
||||
useSliceData,
|
||||
useLevelSegments,
|
||||
useSliceCounter,
|
||||
} from '../hooks';
|
||||
import { TextToolbar } from './text-toolbar';
|
||||
import { LevelContent } from './level-content';
|
||||
import { FilePreview } from './file-preview';
|
||||
import { BaseContent } from './base-content';
|
||||
|
||||
export interface TextKnowledgeWorkspaceProps {
|
||||
onChangeDocList?: (docList: DocumentInfo[]) => void;
|
||||
reload?: () => void;
|
||||
progressMap: ProgressMap;
|
||||
linkOriginUrlButton?: ReactNode;
|
||||
fetchSliceButton?: ReactNode;
|
||||
}
|
||||
|
||||
export const TextKnowledgeWorkspace = ({
|
||||
onChangeDocList,
|
||||
reload: reloadDataset,
|
||||
progressMap,
|
||||
linkOriginUrlButton,
|
||||
fetchSliceButton,
|
||||
}: TextKnowledgeWorkspaceProps) => {
|
||||
const contentWrapperRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const knowledgeParams = useKnowledgeParams();
|
||||
const documentList = useKnowledgeStore(state => state.documentList);
|
||||
const resourceNavigate = useDataNavigate();
|
||||
|
||||
// 初始化选择第一个文档
|
||||
useInitSelectFirstDoc();
|
||||
|
||||
// 文档管理
|
||||
const {
|
||||
handleSelectDocument,
|
||||
handleRenameDocument,
|
||||
handleUpdateDocumentFrequency,
|
||||
rollbackDocumentSelection,
|
||||
} = useDocumentManagement({
|
||||
reloadDataset,
|
||||
});
|
||||
|
||||
// 文档基本信息
|
||||
const { curDoc, curDocId, isProcessing, processFinished, datasetId } =
|
||||
useDocumentInfo(progressMap);
|
||||
|
||||
// 文件预览
|
||||
const { showOriginalFile, handleToggleOriginalFile } =
|
||||
useFilePreview(curDocId);
|
||||
|
||||
// 文档片段数据
|
||||
const { loading, renderData, handleContentChange, reload } = useSliceData({
|
||||
curDocId,
|
||||
datasetId,
|
||||
curChunkType: curDoc?.chunk_strategy?.chunk_type,
|
||||
processFinished,
|
||||
target: contentWrapperRef,
|
||||
rollbackDocumentSelection,
|
||||
});
|
||||
|
||||
// 层级分段数据
|
||||
const {
|
||||
levelSegments,
|
||||
selectionIDs,
|
||||
setSelectionIDs,
|
||||
tosLoading,
|
||||
handleLevelSegmentsChange,
|
||||
handleLevelSegmentDelete,
|
||||
} = useLevelSegments({
|
||||
curDoc,
|
||||
});
|
||||
|
||||
// 片段计数器
|
||||
const { handleIncreaseSliceCount, handleDecreaseSliceCount } =
|
||||
useSliceCounter();
|
||||
|
||||
// 模态框
|
||||
const {
|
||||
deleteModalNode,
|
||||
showDeleteModal,
|
||||
updateFrequencyModalNode,
|
||||
showUpdateFrequencyModal,
|
||||
} = useModals({
|
||||
docId: curDoc?.document_id,
|
||||
documentType: curDoc?.format_type,
|
||||
documentSource: curDoc?.source_type,
|
||||
onDelete: () => {
|
||||
reloadDataset?.();
|
||||
handleSelectDocument('');
|
||||
},
|
||||
onUpdateFrequency: formData => {
|
||||
if (!onChangeDocList || !curDoc) {
|
||||
return;
|
||||
}
|
||||
|
||||
const updatedDocList = handleUpdateDocumentFrequency(
|
||||
curDoc.document_id ?? '',
|
||||
formData,
|
||||
);
|
||||
|
||||
if (updatedDocList) {
|
||||
onChangeDocList(updatedDocList);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
// 文档选项
|
||||
const docOptions = getDocumentOptions(documentList, progressMap);
|
||||
|
||||
// 处理重新分段
|
||||
const handleResegment = () => {
|
||||
const isLocalText = Boolean(
|
||||
curDoc?.source_type === DocumentSource.Document,
|
||||
);
|
||||
resourceNavigate.upload?.({
|
||||
type: isLocalText ? UnitType.TEXT_DOC : UnitType.TEXT,
|
||||
opt: OptType.RESEGMENT,
|
||||
doc_id: curDocId ?? '',
|
||||
page_mode: knowledgeParams.pageMode ?? '',
|
||||
bot_id: knowledgeParams.botID ?? '',
|
||||
});
|
||||
};
|
||||
|
||||
const fromProject = knowledgeParams.biz === 'project';
|
||||
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
className={classnames(
|
||||
'flex grow border-solid coz-stroke-primary coz-bg-max',
|
||||
fromProject
|
||||
? 'h-[calc(100%-64px)] border-0 border-t'
|
||||
: 'h-[calc(100%-112px)] border rounded-[8px]',
|
||||
)}
|
||||
>
|
||||
<div
|
||||
className={classnames(
|
||||
'w-[300px] h-full shrink-0 overflow-auto p-[12px]',
|
||||
'border-0 border-r border-solid coz-stroke-primary',
|
||||
)}
|
||||
>
|
||||
<SegmentMenu
|
||||
isSearchable
|
||||
list={(documentList ?? []).map(item => ({
|
||||
id: item.document_id ?? '',
|
||||
title: item.name ?? '',
|
||||
label: docOptions.find(opt => opt.value === item.document_id)
|
||||
?.label,
|
||||
}))}
|
||||
selectedID={curDocId}
|
||||
onClick={id => {
|
||||
if (id !== curDocId) {
|
||||
handleSelectDocument(id);
|
||||
}
|
||||
}}
|
||||
levelSegments={levelSegments}
|
||||
setSelectionIDs={setSelectionIDs}
|
||||
treeDisabled
|
||||
treeVisible={
|
||||
curDoc?.chunk_strategy?.chunk_type === ChunkType.LevelChunk
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Spin
|
||||
spinning={loading || tosLoading}
|
||||
size="large"
|
||||
wrapperClassName="h-full !w-full grow rounded-r-[8px] overflow-hidden"
|
||||
childStyle={{ height: '100%', flexGrow: 1, width: '100%' }}
|
||||
>
|
||||
<TextToolbar
|
||||
documentData={{
|
||||
curDoc,
|
||||
curDocId,
|
||||
curFormatType: curDoc?.format_type,
|
||||
docOptions,
|
||||
}}
|
||||
filePreviewData={{
|
||||
showOriginalFile,
|
||||
fileUrl: curDoc?.preview_tos_url,
|
||||
}}
|
||||
documentActions={{
|
||||
onChangeDoc: handleSelectDocument,
|
||||
onRenameDoc: handleRenameDocument,
|
||||
onToggleOriginalFile: handleToggleOriginalFile,
|
||||
onResegment: handleResegment,
|
||||
onUpdateFrequency: () =>
|
||||
showUpdateFrequencyModal({
|
||||
updateInterval: curDoc?.update_interval,
|
||||
updateType: curDoc?.update_type,
|
||||
}),
|
||||
onDelete: showDeleteModal,
|
||||
reloadDataset,
|
||||
}}
|
||||
customUIElements={{
|
||||
linkOriginUrlButton,
|
||||
fetchSliceButton,
|
||||
}}
|
||||
/>
|
||||
|
||||
<div className="flex h-[calc(100%-56px)] grow w-full">
|
||||
<FilePreview
|
||||
fileType={curDoc?.type}
|
||||
fileUrl={curDoc?.preview_tos_url || ''}
|
||||
visible={showOriginalFile}
|
||||
/>
|
||||
|
||||
<div
|
||||
ref={contentWrapperRef}
|
||||
className={classnames(
|
||||
'w-full grow h-full overflow-auto',
|
||||
'px-[16px] pt-[16px]',
|
||||
)}
|
||||
>
|
||||
{curDoc?.chunk_strategy?.chunk_type === ChunkType.LevelChunk ? (
|
||||
<LevelContent
|
||||
isProcessing={isProcessing}
|
||||
documentId={curDocId}
|
||||
levelSegments={levelSegments}
|
||||
selectionIDs={selectionIDs}
|
||||
onLevelSegmentsChange={handleLevelSegmentsChange}
|
||||
onLevelSegmentDelete={handleLevelSegmentDelete}
|
||||
/>
|
||||
) : (
|
||||
<BaseContent
|
||||
loading={loading}
|
||||
isProcessing={isProcessing}
|
||||
documentId={curDocId}
|
||||
renderData={renderData}
|
||||
onContentChange={handleContentChange}
|
||||
onAddChunk={() => {
|
||||
reload();
|
||||
handleIncreaseSliceCount();
|
||||
}}
|
||||
onDeleteChunk={() => {
|
||||
handleDecreaseSliceCount();
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</Spin>
|
||||
</div>
|
||||
|
||||
{deleteModalNode}
|
||||
{updateFrequencyModalNode}
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,191 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/* eslint-disable complexity */
|
||||
|
||||
import { type ReactNode } from 'react';
|
||||
|
||||
import classnames from 'classnames';
|
||||
import { isFeishuOrLarkDocumentSource } from '@coze-data/utils';
|
||||
import { useKnowledgeStore } from '@coze-data/knowledge-stores';
|
||||
import { KnowledgeE2e } from '@coze-data/e2e';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import {
|
||||
IconCozAdjust,
|
||||
IconCozHistory,
|
||||
IconCozTrashCan,
|
||||
} from '@coze-arch/coze-design/icons';
|
||||
import { Space, Tooltip, IconButton, Switch } from '@coze-arch/coze-design';
|
||||
import { type OptionProps } from '@coze-arch/bot-semi/Select';
|
||||
import {
|
||||
DocumentSource,
|
||||
FormatType,
|
||||
type DocumentInfo,
|
||||
} from '@coze-arch/bot-api/knowledge';
|
||||
|
||||
import { DocTag } from './doc-tag';
|
||||
import { DocSelector } from './doc-selector';
|
||||
|
||||
// 文档基本信息
|
||||
export interface DocumentData {
|
||||
curDoc?: DocumentInfo;
|
||||
curDocId: string;
|
||||
curFormatType?: FormatType;
|
||||
docOptions: OptionProps[];
|
||||
}
|
||||
|
||||
// 文件预览相关
|
||||
export interface FilePreviewData {
|
||||
showOriginalFile: boolean;
|
||||
fileUrl?: string;
|
||||
}
|
||||
|
||||
// 文档操作回调
|
||||
export interface DocumentActions {
|
||||
onChangeDoc: (docId: string) => void;
|
||||
onRenameDoc: (docId: string, newName: string) => void;
|
||||
onToggleOriginalFile: (checked: boolean) => void;
|
||||
onResegment: () => void;
|
||||
onUpdateFrequency: () => void;
|
||||
onDelete: () => void;
|
||||
reloadDataset?: () => void;
|
||||
}
|
||||
|
||||
// 自定义UI元素
|
||||
export interface CustomUIElements {
|
||||
linkOriginUrlButton?: ReactNode;
|
||||
fetchSliceButton?: ReactNode;
|
||||
}
|
||||
|
||||
export interface TextToolbarProps {
|
||||
documentData: DocumentData;
|
||||
filePreviewData: FilePreviewData;
|
||||
documentActions: DocumentActions;
|
||||
customUIElements: CustomUIElements;
|
||||
}
|
||||
|
||||
export const TextToolbar: React.FC<TextToolbarProps> = ({
|
||||
documentData: { curDoc, curDocId, curFormatType, docOptions },
|
||||
filePreviewData: { showOriginalFile, fileUrl },
|
||||
documentActions: {
|
||||
onChangeDoc,
|
||||
onRenameDoc,
|
||||
onToggleOriginalFile,
|
||||
onResegment,
|
||||
onUpdateFrequency,
|
||||
onDelete,
|
||||
},
|
||||
customUIElements: { linkOriginUrlButton, fetchSliceButton },
|
||||
}) => {
|
||||
const canEdit = useKnowledgeStore(state => state.canEdit);
|
||||
|
||||
// 控制按钮显示逻辑
|
||||
const showUpdateFreBtn =
|
||||
canEdit &&
|
||||
curDoc &&
|
||||
(curDoc.source_type === DocumentSource.Web ||
|
||||
isFeishuOrLarkDocumentSource(curDoc?.source_type));
|
||||
|
||||
const showDeleteDocBtn = curDoc && canEdit;
|
||||
const showResegmentButton = curDoc?.format_type === FormatType.Text;
|
||||
const showFetchSliceBtn =
|
||||
canEdit &&
|
||||
curDoc &&
|
||||
![DocumentSource.Custom, DocumentSource.Document].includes(
|
||||
curDoc.source_type as DocumentSource,
|
||||
);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={classnames(
|
||||
'w-full flex items-center justify-between py-[12px] px-[16px]',
|
||||
'border border-solid coz-stroke-primary border-l-0 border-t-0 border-r-0',
|
||||
)}
|
||||
>
|
||||
<div className={classnames('flex items-center')}>
|
||||
<DocSelector
|
||||
type={curFormatType as FormatType}
|
||||
options={docOptions}
|
||||
canEdit={canEdit}
|
||||
value={curDocId}
|
||||
onChange={onChangeDoc}
|
||||
onRename={onRenameDoc}
|
||||
/>
|
||||
<DocTag documentInfo={curDoc} />
|
||||
</div>
|
||||
|
||||
<Space spacing={8}>
|
||||
{fileUrl ? (
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="coz-fg-secondary text-[12px] leading-[16px]">
|
||||
{I18n.t('knowledge_level_030')}
|
||||
</span>
|
||||
<Switch
|
||||
size="mini"
|
||||
checked={showOriginalFile}
|
||||
onChange={onToggleOriginalFile}
|
||||
></Switch>
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
{showResegmentButton && canEdit ? (
|
||||
<Tooltip theme="dark" content={I18n.t('knowledge_new_001')}>
|
||||
<IconButton
|
||||
data-testid={KnowledgeE2e.SegmentDetailUpdateBtn}
|
||||
iconPosition="left"
|
||||
color="secondary"
|
||||
size="small"
|
||||
icon={<IconCozAdjust />}
|
||||
onClick={onResegment}
|
||||
/>
|
||||
</Tooltip>
|
||||
) : null}
|
||||
|
||||
{showUpdateFreBtn ? (
|
||||
<Tooltip
|
||||
theme="dark"
|
||||
content={I18n.t('datasets_unit_upload_field_update_frequency')}
|
||||
>
|
||||
<IconButton
|
||||
data-dtestid={`${KnowledgeE2e.SegmentDetailContentItemFrequencyIcon}.${curDoc?.document_id}`}
|
||||
icon={<IconCozHistory className="text-[14px]" />}
|
||||
iconPosition="left"
|
||||
color="secondary"
|
||||
size="small"
|
||||
onClick={onUpdateFrequency}
|
||||
></IconButton>
|
||||
</Tooltip>
|
||||
) : null}
|
||||
|
||||
{showFetchSliceBtn ? fetchSliceButton : null}
|
||||
{linkOriginUrlButton}
|
||||
|
||||
{showDeleteDocBtn ? (
|
||||
<Tooltip theme="dark" content={I18n.t('kl2_006')}>
|
||||
<IconButton
|
||||
data-testid={KnowledgeE2e.SegmentDetailContentDeleteIcon}
|
||||
icon={<IconCozTrashCan className="text-[14px]" />}
|
||||
color="secondary"
|
||||
iconPosition="left"
|
||||
size="small"
|
||||
onClick={onDelete}
|
||||
></IconButton>
|
||||
</Tooltip>
|
||||
) : null}
|
||||
</Space>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,234 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/* eslint-disable @coze-arch/max-line-per-function */
|
||||
import { useMemo, useState } from 'react';
|
||||
|
||||
import classNames from 'classnames';
|
||||
import { useDebounceFn } from 'ahooks';
|
||||
import { KnowledgeE2e } from '@coze-data/e2e';
|
||||
import { logger } from '@coze-arch/logger';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import { type OptionProps } from '@coze-arch/bot-semi/Select';
|
||||
import { type FormatType } from '@coze-arch/bot-api/knowledge';
|
||||
import {
|
||||
// IconCozArrowDownFill,
|
||||
IconCozEdit,
|
||||
} from '@coze-arch/coze-design/icons';
|
||||
import {
|
||||
Popover,
|
||||
Select,
|
||||
Toast,
|
||||
Tooltip,
|
||||
Button,
|
||||
TextArea,
|
||||
Search,
|
||||
} from '@coze-arch/coze-design';
|
||||
|
||||
import { useUpdateDocument } from '@/service/document';
|
||||
|
||||
import styles from './index.module.less';
|
||||
|
||||
export interface DocSelectorProps<T> {
|
||||
type: FormatType;
|
||||
options: OptionProps[];
|
||||
value: T;
|
||||
canEdit?: boolean;
|
||||
onChange: (v: T) => void;
|
||||
reload: () => void;
|
||||
}
|
||||
|
||||
const DOC_NAME_MAX_LEN = 100;
|
||||
export const DocSelector = ({
|
||||
type,
|
||||
options,
|
||||
value,
|
||||
onChange,
|
||||
reload,
|
||||
canEdit,
|
||||
}: DocSelectorProps<typeof value>) => {
|
||||
const [search, setSearch] = useState('');
|
||||
const [searchValue, setSearchValue] = useState('');
|
||||
const [docName, setDocName] = useState('');
|
||||
const [visible, setVisible] = useState(false);
|
||||
const debounceSetSearch = useDebounceFn(
|
||||
(v?: string) => {
|
||||
setSearchValue(v || '');
|
||||
},
|
||||
{
|
||||
wait: 300,
|
||||
},
|
||||
);
|
||||
const handledOptions = useMemo(() => {
|
||||
if (!searchValue) {
|
||||
return options;
|
||||
}
|
||||
try {
|
||||
const regx = new RegExp(searchValue);
|
||||
const newOptions = options.filter(
|
||||
op =>
|
||||
// 搜索结果不展示「全部内容」选项
|
||||
(op.value !== 'all' && op.value === value) ||
|
||||
(op?.text as string)?.match(regx),
|
||||
);
|
||||
return newOptions;
|
||||
// eslint-disable-next-line @coze-arch/use-error-in-catch
|
||||
} catch (e) {
|
||||
return options;
|
||||
}
|
||||
}, [searchValue, options]);
|
||||
|
||||
const setDocNameFn = () => {
|
||||
const name = options.find(op => op.value === value)?.text;
|
||||
if (name) {
|
||||
setDocName(name as string);
|
||||
}
|
||||
};
|
||||
const { run, loading } = useUpdateDocument({
|
||||
onSuccess: () => {
|
||||
Toast.success(I18n.t('Update_success'));
|
||||
setVisible(false);
|
||||
reload();
|
||||
},
|
||||
});
|
||||
const handleEditDocName = e => {
|
||||
e.stopPropagation();
|
||||
setVisible(true);
|
||||
// TODO 打开弹框
|
||||
};
|
||||
const triggerRender = ({ value: values }) => (
|
||||
<Popover
|
||||
// showArrow
|
||||
clickToHide={true}
|
||||
visible={visible}
|
||||
onClickOutSide={() => setVisible(false)}
|
||||
trigger="custom"
|
||||
style={{ padding: 16, width: 320 }}
|
||||
onVisibleChange={v => {
|
||||
if (v) {
|
||||
setDocNameFn();
|
||||
}
|
||||
}}
|
||||
content={
|
||||
<div
|
||||
className={styles['edit-doc-name-container']}
|
||||
onClick={e => e.stopPropagation()}
|
||||
>
|
||||
<div className={styles['edit-doc-name-container-title']}>
|
||||
{I18n.t('knowledge_detail_doc_rename')}
|
||||
</div>
|
||||
<div className={styles['edit-doc-name-container-input']}>
|
||||
<TextArea
|
||||
value={docName}
|
||||
maxLength={DOC_NAME_MAX_LEN}
|
||||
maxCount={DOC_NAME_MAX_LEN}
|
||||
validateStatus={!docName ? 'error' : 'default'}
|
||||
placeholder={I18n.t('knowledge_upload_text_custom_doc_name_tips')}
|
||||
onChange={v => setDocName(v)}
|
||||
/>
|
||||
{!docName && (
|
||||
<div className={styles['edit-doc-name-container-input-error']}>
|
||||
{I18n.t('knowledge_upload_text_custom_doc_name_tips')}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="text-right">
|
||||
<Button
|
||||
disabled={!docName}
|
||||
onClick={() => {
|
||||
run({
|
||||
document_id: value,
|
||||
document_name: docName,
|
||||
});
|
||||
}}
|
||||
size="small"
|
||||
loading={loading}
|
||||
>
|
||||
{I18n.t('Save')}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
position="bottomLeft"
|
||||
>
|
||||
<div
|
||||
onClick={() => {
|
||||
setVisible(false);
|
||||
}}
|
||||
className={styles['doc-selector-trigger']}
|
||||
data-testid={KnowledgeE2e.SegmentDetailContentSelectTrigger}
|
||||
>
|
||||
<div className={styles['doc-selector-trigger-label']}>
|
||||
{values.map(item => (
|
||||
<div>{item.label}</div>
|
||||
))}
|
||||
</div>
|
||||
{!canEdit || !value ? null : (
|
||||
<div>
|
||||
<Tooltip
|
||||
clickToHide
|
||||
theme="dark"
|
||||
content={I18n.t('knowledge_detail_doc_rename')}
|
||||
>
|
||||
<div
|
||||
className={styles['doc-selector-trigger-icon']}
|
||||
onClick={handleEditDocName}
|
||||
data-testid={
|
||||
KnowledgeE2e.SegmentDetailContentSelectTriggerEditIcon
|
||||
}
|
||||
>
|
||||
<IconCozEdit className={'text-[14px]'} />
|
||||
</div>
|
||||
</Tooltip>
|
||||
</div>
|
||||
)}
|
||||
{/* <IconCozArrowDownFill className={'text-[16px] ml-[8px] p-[2px]'} /> */}
|
||||
</div>
|
||||
</Popover>
|
||||
);
|
||||
|
||||
// TODO: 交互改版,这里做了个假的
|
||||
return (
|
||||
<Select
|
||||
clickToHide={true}
|
||||
maxHeight={670}
|
||||
disabled
|
||||
className={classNames(styles['doc-selector'])}
|
||||
dropdownClassName={styles['doc-selector-dropdown']}
|
||||
optionList={handledOptions}
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
getPopupContainer={() => document.body}
|
||||
triggerRender={triggerRender}
|
||||
innerTopSlot={
|
||||
<Search
|
||||
value={search}
|
||||
placeholder={I18n.t('datasets_placeholder_search')}
|
||||
onChange={v => {
|
||||
setSearch(v);
|
||||
}}
|
||||
onSearch={v => {
|
||||
logger.info({
|
||||
message: 'onSearch',
|
||||
meta: { v },
|
||||
});
|
||||
debounceSetSearch.run(v);
|
||||
}}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { useMemo } from 'react';
|
||||
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import {
|
||||
ChunkType,
|
||||
DocumentSource,
|
||||
FormatType,
|
||||
type DocumentInfo,
|
||||
} from '@coze-arch/bot-api/knowledge';
|
||||
import { Space, Tag } from '@coze-arch/coze-design';
|
||||
|
||||
import { getSourceName } from '@/utils';
|
||||
import { DOCUMENT_UPDATE_TYPE_MAP } from '@/constant';
|
||||
|
||||
import styles from './index.module.less';
|
||||
|
||||
export interface DocTagProps {
|
||||
documentInfo?: DocumentInfo;
|
||||
}
|
||||
export const DocTag: React.FC<DocTagProps> = ({ documentInfo }) => {
|
||||
const updateFrequencyStr = useMemo(() => {
|
||||
let str: string = DOCUMENT_UPDATE_TYPE_MAP[documentInfo?.update_type ?? ''];
|
||||
if (documentInfo?.update_interval) {
|
||||
str = `${I18n.t('datasets_segment_tag_updateFrequency', {
|
||||
num: documentInfo.update_interval,
|
||||
})}`;
|
||||
}
|
||||
return str;
|
||||
}, [documentInfo]);
|
||||
|
||||
if (!documentInfo) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const renderSegmentTag = () => {
|
||||
const { format_type, chunk_strategy } = documentInfo;
|
||||
if (format_type !== FormatType.Text || !chunk_strategy) {
|
||||
return null;
|
||||
}
|
||||
if (chunk_strategy.chunk_type === ChunkType.CustomChunk) {
|
||||
return (
|
||||
<Tag color="primary" size="mini">
|
||||
{I18n.t('datasets_segment_tag_custom')}
|
||||
</Tag>
|
||||
);
|
||||
}
|
||||
if (chunk_strategy.chunk_type === ChunkType.LevelChunk) {
|
||||
return (
|
||||
<Tag color="primary" size="mini">
|
||||
{I18n.t('knowledge_level_016')}
|
||||
</Tag>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<Tag color="primary" size="mini">
|
||||
{I18n.t('datasets_segment_tag_auto')}
|
||||
</Tag>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<Space className={styles['doc-tag-wrapper']} spacing={4}>
|
||||
<Tag color="primary" size="mini">
|
||||
{getSourceName(documentInfo)}
|
||||
</Tag>
|
||||
{documentInfo.source_type === DocumentSource.Web && (
|
||||
<Tag color="primary" size="mini">
|
||||
{updateFrequencyStr}
|
||||
</Tag>
|
||||
)}
|
||||
{renderSegmentTag()}
|
||||
</Space>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* 按照功能导出所有 hooks
|
||||
*/
|
||||
|
||||
// 文档管理
|
||||
export { useDocumentManagement } from './use-case/use-document-management';
|
||||
|
||||
// 文档信息
|
||||
export { useDocumentInfo } from './life-cycle/use-document-info';
|
||||
|
||||
// 文档片段数据
|
||||
export { useSliceData } from './life-cycle/use-slice-data';
|
||||
|
||||
// 层级分段数据
|
||||
export { useLevelSegments } from './use-case/use-level-segments';
|
||||
|
||||
// 文档片段计数
|
||||
export { useSliceCounter } from './use-case/use-slice-counter';
|
||||
|
||||
// 文件预览
|
||||
export { useFilePreview } from './use-case/use-file-preview';
|
||||
|
||||
// 模态框
|
||||
export { useModals } from './use-case/use-modals';
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { useShallow } from 'zustand/react/shallow';
|
||||
import { useKnowledgeStore } from '@coze-data/knowledge-stores';
|
||||
import { DocumentStatus } from '@coze-arch/bot-api/knowledge';
|
||||
|
||||
import { type ProgressMap } from '@/types';
|
||||
|
||||
/**
|
||||
* 处理文档基本信息的 hook
|
||||
*/
|
||||
export const useDocumentInfo = (progressMap: ProgressMap) => {
|
||||
const { documentList, dataSetDetail, curDocId } = useKnowledgeStore(
|
||||
useShallow(state => ({
|
||||
curDocId: state.curDocId,
|
||||
documentList: state.documentList,
|
||||
dataSetDetail: state.dataSetDetail,
|
||||
})),
|
||||
);
|
||||
|
||||
// 当前文档
|
||||
const curDoc = documentList?.find(i => i.document_id === curDocId);
|
||||
|
||||
// 处理状态
|
||||
const isProcessing = curDoc?.status === DocumentStatus.Processing;
|
||||
const processFinished = curDocId
|
||||
? progressMap[curDocId]?.status === DocumentStatus.Enable
|
||||
: false;
|
||||
|
||||
// 数据集ID
|
||||
const datasetId = dataSetDetail?.dataset_id ?? '';
|
||||
|
||||
return {
|
||||
curDoc,
|
||||
curDocId,
|
||||
isProcessing,
|
||||
processFinished,
|
||||
datasetId,
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { useMemo } from 'react';
|
||||
|
||||
import { useShallow } from 'zustand/react/shallow';
|
||||
import { type BasicTarget } from 'ahooks/lib/utils/domTarget';
|
||||
import { DataNamespace, dataReporter } from '@coze-data/reporter';
|
||||
import { useKnowledgeStore } from '@coze-data/knowledge-stores';
|
||||
import { type DocumentChunk } from '@coze-data/knowledge-common-components/text-knowledge-editor/scenes/base';
|
||||
import { REPORT_EVENTS as ReportEventNames } from '@coze-arch/report-events';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import { Toast } from '@coze-arch/coze-design';
|
||||
import { ChunkType } from '@coze-arch/bot-api/knowledge';
|
||||
|
||||
import { useScrollListSliceReq } from '@/service';
|
||||
|
||||
import { createBaseDocumentChunkBySliceInfo } from '../../utils/document-utils';
|
||||
|
||||
interface UseSliceDataParams {
|
||||
curDocId: string;
|
||||
datasetId: string;
|
||||
curChunkType?: ChunkType;
|
||||
processFinished: boolean;
|
||||
target?: BasicTarget;
|
||||
rollbackDocumentSelection: () => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理文档片段数据获取的 hook
|
||||
*/
|
||||
export const useSliceData = ({
|
||||
curDocId,
|
||||
datasetId,
|
||||
curChunkType,
|
||||
processFinished,
|
||||
target,
|
||||
rollbackDocumentSelection,
|
||||
}: UseSliceDataParams) => {
|
||||
const { searchValue } = useKnowledgeStore(
|
||||
useShallow(state => ({
|
||||
searchValue: state.searchValue,
|
||||
})),
|
||||
);
|
||||
|
||||
// 获取文档内容
|
||||
const {
|
||||
loading,
|
||||
data: sliceData,
|
||||
mutate,
|
||||
reload,
|
||||
} = useScrollListSliceReq({
|
||||
target,
|
||||
params: {
|
||||
keyword: searchValue,
|
||||
document_id:
|
||||
// 如果是层级分段则不请求
|
||||
curChunkType !== ChunkType.LevelChunk ? curDocId : '',
|
||||
},
|
||||
reloadDeps: [searchValue, curDocId, datasetId, processFinished],
|
||||
onError: error => {
|
||||
/** 拉取 slice 失败时,回退 curDocId,避免文档标题和内容不一致,用户迷惑 */
|
||||
dataReporter.errorEvent(DataNamespace.KNOWLEDGE, {
|
||||
eventName: ReportEventNames.KnowledgeGetSliceList,
|
||||
error,
|
||||
});
|
||||
|
||||
Toast.error(I18n.t('knowledge_document_view'));
|
||||
rollbackDocumentSelection();
|
||||
},
|
||||
});
|
||||
|
||||
// 使用 useMemo 缓存 chunks 数组,避免因 progressMap 更新导致不必要的重新创建
|
||||
const renderData = useMemo(
|
||||
() =>
|
||||
sliceData?.list.map(item => createBaseDocumentChunkBySliceInfo(item)) ??
|
||||
[],
|
||||
[sliceData?.list],
|
||||
);
|
||||
|
||||
// 处理内容变化
|
||||
const handleContentChange = (chunks: DocumentChunk[]) => {
|
||||
mutate({
|
||||
...sliceData,
|
||||
list: chunks,
|
||||
total: Number(sliceData?.total ?? '0'),
|
||||
});
|
||||
};
|
||||
|
||||
return {
|
||||
loading,
|
||||
sliceData,
|
||||
renderData,
|
||||
handleContentChange,
|
||||
reload,
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { useRef } from 'react';
|
||||
|
||||
import { useShallow } from 'zustand/react/shallow';
|
||||
import { useKnowledgeStore } from '@coze-data/knowledge-stores';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import { Toast } from '@coze-arch/coze-design';
|
||||
import { UpdateType } from '@coze-arch/bot-api/knowledge';
|
||||
|
||||
import { useUpdateDocument } from '@/service/document';
|
||||
|
||||
export const useDocumentManagement = (props?: {
|
||||
reloadDataset?: () => void;
|
||||
}) => {
|
||||
const { curDocId, setCurDocId, documentList } = useKnowledgeStore(
|
||||
useShallow(state => ({
|
||||
curDocId: state.curDocId,
|
||||
setCurDocId: state.setCurDocId,
|
||||
documentList: state.documentList,
|
||||
})),
|
||||
);
|
||||
|
||||
// 缓存上一个文档ID,用于加载失败后回滚
|
||||
const prevDocIdRef = useRef<string | null>(null);
|
||||
|
||||
// 更新文档名称
|
||||
const { run: updateDocument } = useUpdateDocument({
|
||||
onSuccess: () => {
|
||||
Toast.success(I18n.t('Update_success'));
|
||||
props?.reloadDataset?.();
|
||||
},
|
||||
});
|
||||
|
||||
// 选择文档
|
||||
const handleSelectDocument = (docId: string) => {
|
||||
prevDocIdRef.current = curDocId || null;
|
||||
setCurDocId(docId);
|
||||
};
|
||||
|
||||
// 重命名文档
|
||||
const handleRenameDocument = (docId: string, newName: string) => {
|
||||
updateDocument({
|
||||
document_id: docId,
|
||||
document_name: newName,
|
||||
});
|
||||
};
|
||||
|
||||
// 更新文档频率
|
||||
const handleUpdateDocumentFrequency = (
|
||||
docId: string,
|
||||
formData: { updateInterval?: number; updateType?: UpdateType },
|
||||
) => {
|
||||
if (!documentList) {
|
||||
return;
|
||||
}
|
||||
|
||||
const updatedDocList = documentList.map(doc => {
|
||||
if (doc.document_id === docId) {
|
||||
return {
|
||||
...doc,
|
||||
update_interval: formData?.updateInterval,
|
||||
update_type: formData.updateInterval
|
||||
? UpdateType.Cover
|
||||
: UpdateType.NoUpdate,
|
||||
};
|
||||
}
|
||||
return doc;
|
||||
});
|
||||
|
||||
return updatedDocList;
|
||||
};
|
||||
|
||||
// 回滚文档选择
|
||||
const rollbackDocumentSelection = () => {
|
||||
if (prevDocIdRef.current) {
|
||||
setCurDocId(prevDocIdRef.current);
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
prevDocIdRef,
|
||||
updateDocument,
|
||||
handleSelectDocument,
|
||||
handleRenameDocument,
|
||||
handleUpdateDocumentFrequency,
|
||||
rollbackDocumentSelection,
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { useState, useEffect } from 'react';
|
||||
|
||||
export const useFilePreview = (curDocId: string) => {
|
||||
const [showOriginalFile, setShowOriginalFile] = useState(false);
|
||||
|
||||
// 切换文档时,重置预览状态
|
||||
useEffect(() => {
|
||||
if (showOriginalFile) {
|
||||
setShowOriginalFile(false);
|
||||
}
|
||||
}, [curDocId]);
|
||||
|
||||
const handleToggleOriginalFile = (checked: boolean) => {
|
||||
setShowOriginalFile(checked);
|
||||
};
|
||||
|
||||
return {
|
||||
showOriginalFile,
|
||||
handleToggleOriginalFile,
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { useEffect } from 'react';
|
||||
|
||||
import { useKnowledgeStore } from '@coze-data/knowledge-stores';
|
||||
|
||||
import { useDocumentManagement } from './use-document-management';
|
||||
|
||||
export const useInitSelectFirstDoc = () => {
|
||||
const documentList = useKnowledgeStore(state => state.documentList);
|
||||
const { handleSelectDocument } = useDocumentManagement();
|
||||
useEffect(() => {
|
||||
if (documentList?.length) {
|
||||
handleSelectDocument(documentList[0]?.document_id ?? '');
|
||||
}
|
||||
}, [documentList]);
|
||||
};
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { useState, useMemo, useEffect } from 'react';
|
||||
|
||||
import { useShallow } from 'zustand/react/shallow';
|
||||
import { useKnowledgeStore } from '@coze-data/knowledge-stores';
|
||||
import { type ILevelSegment } from '@coze-data/knowledge-stores';
|
||||
import { useTosContent } from '@coze-data/knowledge-common-hooks';
|
||||
import { withTitle } from '@coze-data/knowledge-common-components/text-knowledge-editor/scenes/level';
|
||||
import { ChunkType, type DocumentInfo } from '@coze-arch/bot-api/knowledge';
|
||||
|
||||
import { createLevelDocumentChunkByLevelSegment } from '../../utils/document-utils';
|
||||
|
||||
interface UseLevelSegmentsParams {
|
||||
curDoc?: DocumentInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理层级分段数据的 hook
|
||||
*/
|
||||
export const useLevelSegments = ({ curDoc }: UseLevelSegmentsParams) => {
|
||||
// 用于层级分段选中滚动
|
||||
const [selectionIDs, setSelectionIDs] = useState<string[]>([]);
|
||||
|
||||
const { levelSegments, setLevelSegments } = useKnowledgeStore(
|
||||
useShallow(state => ({
|
||||
levelSegments: state.levelSegments,
|
||||
setLevelSegments: state.setLevelSegments,
|
||||
})),
|
||||
);
|
||||
|
||||
// 获取层级分段 slice 列表
|
||||
const { content: treeContent, loading: tosLoading } = useTosContent(
|
||||
curDoc?.chunk_strategy?.chunk_type === ChunkType.LevelChunk
|
||||
? curDoc?.doc_tree_tos_url
|
||||
: undefined,
|
||||
);
|
||||
|
||||
// 使用 useMemo 缓存转换后的层级分段数据
|
||||
const renderLevelSegmentsData = useMemo(
|
||||
() =>
|
||||
levelSegments.map(item => createLevelDocumentChunkByLevelSegment(item)),
|
||||
[levelSegments],
|
||||
);
|
||||
|
||||
// 处理层级分段变更
|
||||
const handleLevelSegmentsChange = (chunks: ILevelSegment[]) => {
|
||||
setLevelSegments(chunks);
|
||||
};
|
||||
|
||||
// 处理删除层级分段
|
||||
const handleLevelSegmentDelete = (chunk: ILevelSegment) => {
|
||||
setLevelSegments(
|
||||
levelSegments.filter(item => item.slice_id !== chunk.slice_id),
|
||||
);
|
||||
};
|
||||
|
||||
// 初始化时加载层级分段
|
||||
useEffect(() => {
|
||||
setLevelSegments(withTitle(treeContent?.chunks ?? [], curDoc?.name ?? ''));
|
||||
}, [treeContent]);
|
||||
|
||||
return {
|
||||
levelSegments,
|
||||
renderLevelSegmentsData,
|
||||
selectionIDs,
|
||||
setSelectionIDs,
|
||||
tosLoading,
|
||||
handleLevelSegmentsChange,
|
||||
handleLevelSegmentDelete,
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { type ReactNode } from 'react';
|
||||
|
||||
import {
|
||||
useDeleteUnitModal,
|
||||
useUpdateFrequencyModal,
|
||||
} from '@coze-data/knowledge-modal-base';
|
||||
import {
|
||||
type FormatType,
|
||||
type DocumentSource,
|
||||
type UpdateType,
|
||||
} from '@coze-arch/bot-api/knowledge';
|
||||
|
||||
export interface UseModalsProps {
|
||||
docId?: string;
|
||||
documentType?: FormatType;
|
||||
documentSource?: DocumentSource;
|
||||
onDelete?: () => void;
|
||||
onUpdateFrequency?: (formData: {
|
||||
updateInterval?: number;
|
||||
updateType?: UpdateType;
|
||||
}) => void;
|
||||
}
|
||||
|
||||
export interface UseModalsReturn {
|
||||
deleteModalNode: ReactNode;
|
||||
showDeleteModal: () => void;
|
||||
updateFrequencyModalNode: ReactNode;
|
||||
showUpdateFrequencyModal: (params: {
|
||||
updateInterval?: number;
|
||||
updateType?: UpdateType;
|
||||
}) => void;
|
||||
}
|
||||
|
||||
export const useModals = (props: UseModalsProps): UseModalsReturn => {
|
||||
const { docId, documentType, documentSource, onDelete, onUpdateFrequency } =
|
||||
props;
|
||||
|
||||
// 删除模态框
|
||||
const { node: deleteModalNode, delete: showDeleteModal } = useDeleteUnitModal(
|
||||
{
|
||||
docId,
|
||||
onDel: () => {
|
||||
onDelete?.();
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
// 更新频率模态框
|
||||
const { node: updateFrequencyModalNode, edit: showUpdateFrequencyModal } =
|
||||
useUpdateFrequencyModal({
|
||||
docId,
|
||||
onFinish: formData => {
|
||||
onUpdateFrequency?.(formData);
|
||||
},
|
||||
type: documentType,
|
||||
documentSource,
|
||||
});
|
||||
|
||||
return {
|
||||
deleteModalNode,
|
||||
showDeleteModal,
|
||||
updateFrequencyModalNode,
|
||||
showUpdateFrequencyModal,
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { useShallow } from 'zustand/react/shallow';
|
||||
import { useKnowledgeStore } from '@coze-data/knowledge-stores';
|
||||
|
||||
/**
|
||||
* 处理文档片段计数的 hook
|
||||
*/
|
||||
export const useSliceCounter = () => {
|
||||
const { dataSetDetail, setDataSetDetail } = useKnowledgeStore(
|
||||
useShallow(state => ({
|
||||
dataSetDetail: state.dataSetDetail,
|
||||
setDataSetDetail: state.setDataSetDetail,
|
||||
})),
|
||||
);
|
||||
|
||||
// 处理添加块时更新计数
|
||||
const handleIncreaseSliceCount = () => {
|
||||
if (!dataSetDetail) {
|
||||
return;
|
||||
}
|
||||
|
||||
setDataSetDetail({
|
||||
...dataSetDetail,
|
||||
slice_count:
|
||||
// @ts-expect-error -- linter-disable-autofix
|
||||
dataSetDetail.slice_count > -1
|
||||
? // @ts-expect-error -- linter-disable-autofix
|
||||
dataSetDetail.slice_count + 1
|
||||
: 0,
|
||||
});
|
||||
};
|
||||
|
||||
// 处理删除块时更新计数
|
||||
const handleDecreaseSliceCount = () => {
|
||||
if (!dataSetDetail) {
|
||||
return;
|
||||
}
|
||||
|
||||
setDataSetDetail({
|
||||
...dataSetDetail,
|
||||
slice_count:
|
||||
// @ts-expect-error -- linter-disable-autofix
|
||||
dataSetDetail.slice_count > -1
|
||||
? // @ts-expect-error -- linter-disable-autofix
|
||||
dataSetDetail.slice_count - 1
|
||||
: 0,
|
||||
});
|
||||
};
|
||||
|
||||
return {
|
||||
handleIncreaseSliceCount,
|
||||
handleDecreaseSliceCount,
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,344 @@
|
||||
/* stylelint-disable declaration-no-important */
|
||||
@import '../../assets/common.less';
|
||||
|
||||
.slice-list-ui-content {
|
||||
overflow: auto;
|
||||
flex: 1;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.empty-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding-bottom: 5%;
|
||||
}
|
||||
|
||||
.slice-modal-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.tag {
|
||||
margin-left: 6px;
|
||||
}
|
||||
}
|
||||
|
||||
.serial-number-text {
|
||||
font-size: 12px;
|
||||
color: var(--coz-fg-secondary);
|
||||
|
||||
}
|
||||
|
||||
.unit-table-view {
|
||||
@apply !coz-bg-max;
|
||||
|
||||
.serial-number {
|
||||
padding-left: 0 !important;
|
||||
font-size: 14px !important;
|
||||
color: var(--coz-fg-secondary);
|
||||
}
|
||||
|
||||
|
||||
:global {
|
||||
.coz-tag {
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.data-tags {
|
||||
min-width: 173px;
|
||||
}
|
||||
|
||||
.semi-table-wrapper {
|
||||
margin-top: 0 !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.slice-article {
|
||||
position: relative;
|
||||
|
||||
overflow-y: auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
height: calc(100% - 24px);
|
||||
padding: 0 16px;
|
||||
|
||||
background-color: var(--coz-bg-plus);
|
||||
border: 1px solid var(--coz-stroke-primary);
|
||||
border-radius: 8px;
|
||||
|
||||
.slice-article-content {
|
||||
padding: 12px 2px;
|
||||
}
|
||||
}
|
||||
|
||||
.text-slice-toolbar {
|
||||
position: sticky;
|
||||
z-index: 10;
|
||||
top: 0;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
padding: 12px 0;
|
||||
|
||||
background-color: var(--coz-bg-plus);
|
||||
border-bottom: 1px solid var(--coz-stroke-primary);
|
||||
|
||||
.content-left-slot {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
|
||||
.doc-tag-wrapper {
|
||||
margin-left: 4px;
|
||||
|
||||
:global {
|
||||
.semi-tag-content {
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.menu_wrapper {
|
||||
border-radius: 8px !important;
|
||||
}
|
||||
|
||||
.menu {
|
||||
width: 160px;
|
||||
padding: 4px;
|
||||
|
||||
:global {
|
||||
.semi-dropdown-item {
|
||||
height: 32px;
|
||||
padding: 8px;
|
||||
font-size: 12px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.semi-icon>svg {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
}
|
||||
|
||||
.semi-dropdown-item-disabled>.semi-dropdown-item-icon {
|
||||
opacity: 0.3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.slice-list-table {
|
||||
overflow-y: hidden;
|
||||
grid-auto-rows: min-content;
|
||||
grid-gap: 16px;
|
||||
|
||||
height: 100%;
|
||||
padding: 0 24px 13px;
|
||||
|
||||
}
|
||||
|
||||
.table-view-container-box {
|
||||
max-height: calc(100% - 51px);
|
||||
// overflow-y: scroll;
|
||||
}
|
||||
|
||||
.add-row-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 48px;
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.spin {
|
||||
:global {
|
||||
.semi-spin-wrapper {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.semi-tabs-content {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.semi-spin-children {
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.doc-selector-dropdown {
|
||||
:global {
|
||||
.option-prefix-icon {
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.semi-select-option {
|
||||
cursor: pointer;
|
||||
|
||||
position: relative;
|
||||
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
align-items: center;
|
||||
|
||||
box-sizing: border-box;
|
||||
padding: 8px 16px;
|
||||
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
line-height: 16px;
|
||||
word-break: break-word;
|
||||
|
||||
border-radius: 4px;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.doc-selector-dropdown,
|
||||
.doc-selector {
|
||||
overflow: hidden;
|
||||
|
||||
max-width: 723px;
|
||||
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
|
||||
opacity: 1;
|
||||
|
||||
:global {
|
||||
.semi-input-wrapper {
|
||||
width: 100% !important;
|
||||
min-width: 256px;
|
||||
}
|
||||
|
||||
.coz-select-option-item.selected {
|
||||
.doc-name-item {
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.doc-option {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
max-width: 603px;
|
||||
|
||||
color: var(--coz-fg-primary);
|
||||
}
|
||||
|
||||
.doc-name {
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex: 1;
|
||||
|
||||
margin: 0 8px;
|
||||
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
line-height: 20px;
|
||||
color: var(--coz-fg-primary);
|
||||
|
||||
&-selected {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
&-prev {
|
||||
overflow: hidden;
|
||||
display: inline-block;
|
||||
flex: 1;
|
||||
|
||||
text-overflow: ellipsis;
|
||||
white-space:nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.borderless-filter-render {
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.borderless-filter-text {
|
||||
font-weight: 600;
|
||||
color: #1c1f23;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
.filter-icon {
|
||||
margin-bottom: -2px;
|
||||
margin-left: 2px;
|
||||
}
|
||||
|
||||
.doc-selector-trigger {
|
||||
cursor: pointer;
|
||||
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
align-items: center;
|
||||
|
||||
height: 32px;
|
||||
|
||||
font-size: 14px;
|
||||
color: var(--coz-fg-primary);
|
||||
|
||||
border-radius: 8px;
|
||||
|
||||
&:hover {
|
||||
// background-color: var(--coz-mg-secondary-pressed, rgba(6, 7, 9, 14%));
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
&-icon {
|
||||
cursor: pointer;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
|
||||
border-radius: 6px;
|
||||
|
||||
&:hover {
|
||||
background-color: var(--coz-mg-secondary-pressed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.edit-doc-name-container {
|
||||
&-title {
|
||||
margin-bottom: 12px;
|
||||
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
line-height: 20px;
|
||||
color: var(--coz-fg-plus);
|
||||
}
|
||||
|
||||
&-input {
|
||||
padding-bottom: 12px;
|
||||
|
||||
&-error {
|
||||
padding: 2px 8px 0;
|
||||
font-size: 12px;
|
||||
line-height: 16px;
|
||||
color: var(--coz-fg-hglt-red);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { TextKnowledgeWorkspace } from './components/main';
|
||||
|
||||
export { TextKnowledgeWorkspace };
|
||||
export type { TextKnowledgeWorkspaceProps } from './components/main';
|
||||
@@ -0,0 +1,344 @@
|
||||
/* stylelint-disable declaration-no-important */
|
||||
@import '../../../assets/common.less';
|
||||
|
||||
.slice-list-ui-content {
|
||||
overflow: auto;
|
||||
flex: 1;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.empty-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding-bottom: 5%;
|
||||
}
|
||||
|
||||
.slice-modal-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.tag {
|
||||
margin-left: 6px;
|
||||
}
|
||||
}
|
||||
|
||||
.serial-number-text {
|
||||
font-size: 12px;
|
||||
color: var(--coz-fg-secondary);
|
||||
|
||||
}
|
||||
|
||||
.unit-table-view {
|
||||
@apply !coz-bg-max;
|
||||
|
||||
.serial-number {
|
||||
padding-left: 0 !important;
|
||||
font-size: 14px !important;
|
||||
color: var(--coz-fg-secondary);
|
||||
}
|
||||
|
||||
|
||||
:global {
|
||||
.coz-tag {
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.data-tags {
|
||||
min-width: 173px;
|
||||
}
|
||||
|
||||
.semi-table-wrapper {
|
||||
margin-top: 0 !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.slice-article {
|
||||
position: relative;
|
||||
|
||||
overflow-y: auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
height: calc(100% - 24px);
|
||||
padding: 0 16px;
|
||||
|
||||
background-color: var(--coz-bg-plus);
|
||||
border: 1px solid var(--coz-stroke-primary);
|
||||
border-radius: 8px;
|
||||
|
||||
.slice-article-content {
|
||||
padding: 12px 2px;
|
||||
}
|
||||
}
|
||||
|
||||
.text-slice-toolbar {
|
||||
position: sticky;
|
||||
z-index: 10;
|
||||
top: 0;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
padding: 12px 0;
|
||||
|
||||
background-color: var(--coz-bg-plus);
|
||||
border-bottom: 1px solid var(--coz-stroke-primary);
|
||||
|
||||
.content-left-slot {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
|
||||
.doc-tag-wrapper {
|
||||
margin-left: 4px;
|
||||
|
||||
:global {
|
||||
.semi-tag-content {
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.menu_wrapper {
|
||||
border-radius: 8px !important;
|
||||
}
|
||||
|
||||
.menu {
|
||||
width: 160px;
|
||||
padding: 4px;
|
||||
|
||||
:global {
|
||||
.semi-dropdown-item {
|
||||
height: 32px;
|
||||
padding: 8px;
|
||||
font-size: 12px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.semi-icon>svg {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
}
|
||||
|
||||
.semi-dropdown-item-disabled>.semi-dropdown-item-icon {
|
||||
opacity: 0.3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.slice-list-table {
|
||||
overflow-y: hidden;
|
||||
grid-auto-rows: min-content;
|
||||
grid-gap: 16px;
|
||||
|
||||
height: 100%;
|
||||
padding: 0 24px 13px;
|
||||
|
||||
}
|
||||
|
||||
.table-view-container-box {
|
||||
max-height: calc(100% - 51px);
|
||||
// overflow-y: scroll;
|
||||
}
|
||||
|
||||
.add-row-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 48px;
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.spin {
|
||||
:global {
|
||||
.semi-spin-wrapper {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.semi-tabs-content {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.semi-spin-children {
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.doc-selector-dropdown {
|
||||
:global {
|
||||
.option-prefix-icon {
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.semi-select-option {
|
||||
cursor: pointer;
|
||||
|
||||
position: relative;
|
||||
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
align-items: center;
|
||||
|
||||
box-sizing: border-box;
|
||||
padding: 8px 16px;
|
||||
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
line-height: 16px;
|
||||
word-break: break-word;
|
||||
|
||||
border-radius: 4px;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.doc-selector-dropdown,
|
||||
.doc-selector {
|
||||
overflow: hidden;
|
||||
|
||||
max-width: 723px;
|
||||
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
|
||||
opacity: 1;
|
||||
|
||||
:global {
|
||||
.semi-input-wrapper {
|
||||
width: 100% !important;
|
||||
min-width: 256px;
|
||||
}
|
||||
|
||||
.coz-select-option-item.selected {
|
||||
.doc-name-item {
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.doc-option {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
max-width: 603px;
|
||||
|
||||
color: var(--coz-fg-primary);
|
||||
}
|
||||
|
||||
.doc-name {
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex: 1;
|
||||
|
||||
margin: 0 8px;
|
||||
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
line-height: 20px;
|
||||
color: var(--coz-fg-primary);
|
||||
|
||||
&-selected {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
&-prev {
|
||||
overflow: hidden;
|
||||
display: inline-block;
|
||||
flex: 1;
|
||||
|
||||
text-overflow: ellipsis;
|
||||
white-space:nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.borderless-filter-render {
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.borderless-filter-text {
|
||||
font-weight: 600;
|
||||
color: #1c1f23;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
.filter-icon {
|
||||
margin-bottom: -2px;
|
||||
margin-left: 2px;
|
||||
}
|
||||
|
||||
.doc-selector-trigger {
|
||||
cursor: pointer;
|
||||
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
align-items: center;
|
||||
|
||||
height: 32px;
|
||||
|
||||
font-size: 14px;
|
||||
color: var(--coz-fg-primary);
|
||||
|
||||
border-radius: 8px;
|
||||
|
||||
&:hover {
|
||||
// background-color: var(--coz-mg-secondary-pressed, rgba(6, 7, 9, 14%));
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
&-icon {
|
||||
cursor: pointer;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
|
||||
border-radius: 6px;
|
||||
|
||||
&:hover {
|
||||
background-color: var(--coz-mg-secondary-pressed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.edit-doc-name-container {
|
||||
&-title {
|
||||
margin-bottom: 12px;
|
||||
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
line-height: 20px;
|
||||
color: var(--coz-fg-plus);
|
||||
}
|
||||
|
||||
&-input {
|
||||
padding-bottom: 12px;
|
||||
|
||||
&-error {
|
||||
padding: 2px 8px 0;
|
||||
font-size: 12px;
|
||||
line-height: 16px;
|
||||
color: var(--coz-fg-hglt-red);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { nanoid } from 'nanoid';
|
||||
import { type DocumentChunk } from '@coze-data/knowledge-common-components/text-knowledge-editor/scenes/base';
|
||||
import { type SliceInfo } from '@coze-arch/bot-api/knowledge';
|
||||
|
||||
export const createBaseDocumentChunkBySliceInfo = (
|
||||
props: SliceInfo,
|
||||
): DocumentChunk => ({
|
||||
text_knowledge_editor_chunk_uuid: nanoid(),
|
||||
...props,
|
||||
});
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/* eslint-disable complexity */
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import {
|
||||
DocumentStatus,
|
||||
type DocumentInfo,
|
||||
} from '@coze-arch/bot-api/knowledge';
|
||||
import { IconCozInfoCircle } from '@coze-arch/coze-design/icons';
|
||||
import { Tag, Tooltip, Typography } from '@coze-arch/coze-design';
|
||||
|
||||
import { getBasicConfig } from '@/utils/preview';
|
||||
import { getUnitType } from '@/utils';
|
||||
import { type ProgressMap } from '@/types';
|
||||
|
||||
const FINISH_PROGRESS = 100;
|
||||
export const getDocumentOptions = (
|
||||
documentList: DocumentInfo[],
|
||||
progressMap: ProgressMap = {},
|
||||
) => {
|
||||
const basicConfig = getBasicConfig();
|
||||
return documentList.map(doc => {
|
||||
const unitType = getUnitType({
|
||||
format_type: doc?.format_type,
|
||||
source_type: doc?.source_type,
|
||||
});
|
||||
const config = basicConfig[unitType];
|
||||
|
||||
return {
|
||||
value: doc.document_id,
|
||||
text: doc.name,
|
||||
label: (
|
||||
<div
|
||||
className="flex flex-row items-center justify-center max-w-[603px] coz-fg-primary"
|
||||
key={doc?.document_id}
|
||||
>
|
||||
<div className="flex text-[16px]">{config?.icon}</div>
|
||||
<Typography.Text
|
||||
ellipsis={{ showTooltip: { opts: { theme: 'dark' } } }}
|
||||
fontSize="14px"
|
||||
className="w-full grow truncate ml-[8px]"
|
||||
>
|
||||
{doc.name}
|
||||
</Typography.Text>
|
||||
|
||||
<div className="flex items-center shrink-0 ml-[4px]">
|
||||
{Object.keys(progressMap).includes(doc?.document_id ?? '') &&
|
||||
progressMap?.[doc?.document_id ?? '']?.progress <
|
||||
FINISH_PROGRESS ? (
|
||||
<Tag color="blue" size="mini" className="font-medium">
|
||||
{I18n.t('datasets_segment_tag_processing')}
|
||||
{` ${progressMap[doc?.document_id ?? '']?.progress}%`}
|
||||
</Tag>
|
||||
) : null}
|
||||
{doc?.status === DocumentStatus.Failed ? (
|
||||
<Tooltip theme="dark" content={doc?.status_descript}>
|
||||
<IconCozInfoCircle className="coz-fg-hglt-red" />
|
||||
</Tooltip>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
};
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { nanoid } from 'nanoid';
|
||||
import { type ILevelSegment } from '@coze-data/knowledge-stores';
|
||||
import { type DocumentChunk } from '@coze-data/knowledge-common-components/text-knowledge-editor/scenes/base';
|
||||
import { type LevelDocumentChunk } from '@coze-data/knowledge-common-components/text-knowledge-editor';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import { IconCozInfoCircle } from '@coze-arch/coze-design/icons';
|
||||
import { Tag, Tooltip, Typography } from '@coze-arch/coze-design';
|
||||
import { type OptionProps } from '@coze-arch/bot-semi/Select';
|
||||
import {
|
||||
DocumentStatus,
|
||||
type DocumentInfo,
|
||||
type SliceInfo,
|
||||
} from '@coze-arch/bot-api/knowledge';
|
||||
|
||||
import { getBasicConfig } from '@/utils/preview';
|
||||
import { getUnitType } from '@/utils';
|
||||
import { type ProgressMap } from '@/types';
|
||||
|
||||
const FINISH_PROGRESS = 100;
|
||||
|
||||
/**
|
||||
* 创建基础文档块
|
||||
*/
|
||||
export const createBaseDocumentChunkBySliceInfo = (
|
||||
props: SliceInfo,
|
||||
): DocumentChunk => ({
|
||||
text_knowledge_editor_chunk_uuid: nanoid(),
|
||||
...props,
|
||||
});
|
||||
|
||||
/**
|
||||
* 创建层级文档块
|
||||
*/
|
||||
export const createLevelDocumentChunkByLevelSegment = (
|
||||
props: ILevelSegment,
|
||||
): LevelDocumentChunk => ({
|
||||
text_knowledge_editor_chunk_uuid: nanoid(),
|
||||
sequence: props.slice_sequence?.toString(),
|
||||
content: props.text,
|
||||
...props,
|
||||
});
|
||||
|
||||
/**
|
||||
* 获取文档选项
|
||||
*/
|
||||
export const getDocumentOptions = (
|
||||
documentList: DocumentInfo[],
|
||||
progressMap: ProgressMap = {},
|
||||
): OptionProps[] => {
|
||||
const basicConfig = getBasicConfig();
|
||||
return documentList.map(doc => {
|
||||
const unitType = getUnitType({
|
||||
format_type: doc?.format_type,
|
||||
source_type: doc?.source_type,
|
||||
});
|
||||
const config = basicConfig[unitType];
|
||||
|
||||
return {
|
||||
value: doc.document_id,
|
||||
text: doc.name,
|
||||
label: (
|
||||
<div
|
||||
className="flex flex-row items-center justify-center max-w-[603px] coz-fg-primary"
|
||||
key={doc?.document_id}
|
||||
>
|
||||
<div className="flex text-[16px]">{config?.icon}</div>
|
||||
<Typography.Text
|
||||
ellipsis={{ showTooltip: { opts: { theme: 'dark' } } }}
|
||||
fontSize="14px"
|
||||
className="w-full grow truncate ml-[8px]"
|
||||
>
|
||||
{doc.name}
|
||||
</Typography.Text>
|
||||
|
||||
<div className="flex items-center shrink-0 ml-[4px]">
|
||||
{Object.keys(progressMap).includes(doc?.document_id ?? '') &&
|
||||
progressMap?.[doc?.document_id ?? '']?.progress <
|
||||
FINISH_PROGRESS ? (
|
||||
<Tag color="blue" size="mini" className="font-medium">
|
||||
{I18n.t('datasets_segment_tag_processing')}
|
||||
{` ${progressMap[doc?.document_id ?? '']?.progress}%`}
|
||||
</Tag>
|
||||
) : null}
|
||||
{doc?.status === DocumentStatus.Failed ? (
|
||||
<Tooltip theme="dark" content={doc?.status_descript}>
|
||||
<IconCozInfoCircle className="coz-fg-hglt-red" />
|
||||
</Tooltip>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
),
|
||||
};
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { nanoid } from 'nanoid';
|
||||
import { type ILevelSegment } from '@coze-data/knowledge-stores';
|
||||
import { type LevelDocumentChunk } from '@coze-data/knowledge-common-components/text-knowledge-editor';
|
||||
|
||||
export const createLevelDocumentChunkByLevelSegment = (
|
||||
props: ILevelSegment,
|
||||
): LevelDocumentChunk => ({
|
||||
text_knowledge_editor_chunk_uuid: nanoid(),
|
||||
sequence: props.slice_sequence?.toString(),
|
||||
content: props.text,
|
||||
...props,
|
||||
});
|
||||
Reference in New Issue
Block a user