feat: manually mirror opencoze's code from bytedance

Change-Id: I09a73aadda978ad9511264a756b2ce51f5761adf
This commit is contained in:
fanlv
2025-07-20 17:36:12 +08:00
commit 890153324f
14811 changed files with 1923430 additions and 0 deletions

View File

@@ -0,0 +1,137 @@
/*
* 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 { useShallow } from 'zustand/react/shallow';
import { DataErrorBoundary, DataNamespace } from '@coze-data/reporter';
import {
useDataCallbacks,
useKnowledgeStore,
} from '@coze-data/knowledge-stores';
import { useReportTti } from '@coze-arch/report-tti';
import { I18n } from '@coze-arch/i18n';
import { Layout } from '@coze-arch/coze-design';
import { renderHtmlTitle } from '@coze-arch/bot-utils';
import { type DocumentInfo, type Dataset } from '@coze-arch/bot-api/knowledge';
import { FormatType } from '@coze-arch/bot-api/knowledge';
import { type ProgressMap } from '@/types';
import { usePollingTaskProgress } from '@/service';
import { useReloadKnowledgeIDE } from '@/hooks/use-case/use-reload-knowledge-ide';
import {
type KnowledgeIDEBaseLayoutProps,
type KnowledgeRenderContext,
} from '../module';
export const KnowledgeIDEBaseLayout = ({
keepDocTitle,
className,
renderNavBar,
renderContent,
}: KnowledgeIDEBaseLayoutProps) => {
const { onUpdateDisplayName, onStatusChange } = useDataCallbacks();
const { setDataSetDetail, dataSetDetail, setDocumentList, documentList } =
useKnowledgeStore(
useShallow(state => ({
setDataSetDetail: state.setDataSetDetail,
dataSetDetail: state.dataSetDetail,
setDocumentList: state.setDocumentList,
documentList: state.documentList,
})),
);
const [progressMap, setProgressMap] = useState<ProgressMap>({});
const pollingTaskProgressInternal = usePollingTaskProgress();
const { reload, loading: isReloading, reset } = useReloadKnowledgeIDE();
// 初始化
useEffect(() => {
reload();
return () => {
reset();
};
}, []);
// 回调 project IDE tab
useEffect(() => {
if (dataSetDetail?.name) {
onUpdateDisplayName?.(dataSetDetail.name);
onStatusChange?.('normal');
}
}, [dataSetDetail?.name]);
useReportTti({
isLive: !!documentList?.length,
});
useEffect(() => {
const progressIds = dataSetDetail?.processing_file_id_list;
if (progressIds && progressIds.length) {
pollingTaskProgressInternal(progressIds, {
onProgressing: res => {
setProgressMap(res);
},
onFinish: () => {
reload();
},
dataSetId: dataSetDetail?.dataset_id,
isImage: dataSetDetail?.format_type === FormatType.Image,
});
}
}, [dataSetDetail]);
// 构建渲染上下文
const renderContext: KnowledgeRenderContext = {
layoutProps: {
keepDocTitle,
renderContent,
renderNavBar,
},
dataInfo: {
dataSetDetail,
documentList,
},
statusInfo: {
isReloading,
progressMap,
},
dataActions: {
refreshData: reload,
updateDataSetDetail: (data: Dataset) => setDataSetDetail(data || {}),
updateDocumentList: (data: DocumentInfo[]) => setDocumentList(data || []),
},
};
// 编辑简介
return (
<DataErrorBoundary namespace={DataNamespace.KNOWLEDGE}>
<Layout
className={
className ||
'flex flex-col p-[24px] pt-[16px] gap-[16px] !bg-transparent '
}
title={renderHtmlTitle(
`${dataSetDetail?.name} - ${I18n.t('tab_dataset_list')}`,
)}
keepDocTitle={keepDocTitle}
>
{/* 导航栏 */}
{renderNavBar?.(renderContext)}
{/* 内容区 */}
{renderContent?.(renderContext)}
</Layout>
</DataErrorBoundary>
);
};

View File

@@ -0,0 +1,362 @@
/* stylelint-disable declaration-no-important */
@import '../../../assets/common.less';
.slice-list-ui-content {
overflow: auto;
flex: 1;
padding: 0;
}
.spin {
:global {
.semi-spin-wrapper {
position: absolute;
}
.semi-tabs-content {
padding: 0;
}
.semi-spin-children {
height: 100%;
}
}
}
.column-type {
margin-left: 6px;
}
.list-empty {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
}
.loading-more {
display: flex;
grid-column: 1 / -1;
align-items: center;
justify-content: center;
width: 100%;
height: 38px;
margin-top: 16px;
font-size: 14px;
line-height: 20px;
color: rgb(28 31 35 / 60%);
}
.header {
padding-bottom: 32px;
}
.breadcrumb {
display: flex;
align-items: center;
}
.btn-icon {
.common-svg-icon(16px, rgba(51, 112, 255, 1));
}
.disable-icon {
.common-svg-icon(16px, var(--semi-color-disabled-text));
}
.doc-icon {
.common-svg-icon(36px, null);
}
.doc-icon-note {
.common-svg-icon(36px, null);
}
.icon-size-16 {
.common-svg-icon(16px, null);
}
.slice-list {
overflow-y: auto;
display: grid;
grid-auto-rows: min-content;
grid-gap: 16px;
grid-template-columns: repeat(auto-fill, minmax(322px, 1fr));
padding: 0 24px 13px;
}
.table-view-title {
display: flex;
flex-direction: row;
align-items: center;
&-content {
cursor: pointer;
}
.semantic-tag {
margin-left: 8px;
}
}
.slice-list-table {
overflow-y: hidden;
grid-auto-rows: min-content;
grid-gap: 16px;
height: 100%;
padding: 0 24px 13px;
}
.slice-modal-title {
display: flex;
align-items: center;
.tag {
margin-left: 6px;
}
}
.slice-article {
position: relative;
overflow-y: auto;
display: flex;
flex-direction: column;
height: calc(100% - 24px);
margin: 0 24px;
padding: 12px 100px;
background-color: white;
border: 1px solid rgb(29 28 35 / 12%);
border-radius: 8px;
}
@media (min-width: 1600px) {
.slice-list {
grid-template-columns: repeat(4, minmax(322px, 1fr));
}
}
.brief {
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 24px 15px;
border-bottom: 1px solid #E7E7E7;
.info {
display: flex;
align-items: center;
}
.edit-icon {
color: rgb(29 28 35 / 60%);
}
.avatar {
flex-grow: 0;
flex-shrink: 0;
width: 48px;
height: 48px;
}
.content {
overflow: hidden;
flex-grow: 1;
margin-left: 18px;
}
.action-right {
margin-left: auto;
}
.tags {
margin-top: 5px;
}
.title {
max-width: 800px;
margin-right: 5px;
font-size: 20px;
font-weight: 600;
line-height: 28px;
color: var(--light-usage-text-color-text-0, #1c1d23);
}
.description {
overflow: hidden;
margin-top: 6px;
font-size: 14px;
font-weight: 700;
font-style: normal;
line-height: 22px;
color: var(--light-usage-text-color-text-1, rgb(28 29 35 / 80%));
text-overflow: ellipsis;
}
:global {
.semi-tag-blue-light {
color: var(--light-color-brand-brand-6, #304cdb);
background: var(--light-color-brand-brand-1, #d9e2ff);
}
.semi-button {
padding: 8px 12px;
}
.icon-with-suffix-overlay {
.icon {
width: 36px;
height: 36px;
[role="img"] {
.common-svg-icon(24px, null);
}
}
.suffix {
top: 27px;
left: 27px;
width: 18px;
height: 18px;
[role="img"] {
.common-svg-icon(12px, null);
}
}
}
}
}
.slice-search {
display: flex;
align-items: center;
justify-content: space-between;
padding: 28px 24px 20px;
.search-input {
width: 255px;
border-radius: 8px;
}
.slice-title {
font-size: 18px;
font-weight: 600;
line-height: 24px;
color: var(--light-usage-text-color-text-0, #1c1d23);
}
:global {
/* stylelint-disable-next-line rule-empty-line-before */
.semi-button-primary.semi-button-borderless,
.semi-button-primary.semi-button-light {
color: var(--light-color-grey-grey-9, #1c1d23);
}
}
.input-prefix {
padding: 0 8px 0 16px;
}
}
.hidden-tooltip {
display: none;
}
.data-render {
display: flex;
gap: 12px;
}
.serial-number-text {
font-size: 12px;
color: var(--coz-fg-secondary);
}
.unit-table-view {
.serial-number {
padding-left: 0 !important;
font-size: 14px !important;
}
:global {
.data-tags {
min-width: 173px;
}
}
}
.menu {
width: 176px;
padding: 4px;
:global {
color: rgb(28 29 35);
.semi-dropdown-item {
padding: 5px 8px;
font-size: 12px;
border-radius: 6px;
}
.semi-icon>svg {
height: 14px;
}
.semi-dropdown-item-disabled>.semi-dropdown-item-icon {
opacity: 0.3;
}
}
}
.knowledge-preview-modal {
:global {
.semi-modal-content {
max-height: 100vh !important;
padding: 0;
}
.semi-modal-body {
padding: 0!important;
}
.semi-modal-body-wrapper {
margin: 0
}
.semi-modal-body-wrapper,
.semi-modal-body,
.semi-modal-body>div {
height: 100%
}
}
}
.text-render-container {
width: 100%;
}
.warning {
:global {
.text-content {
color: #FF2500;
}
}
}

View File

@@ -0,0 +1,70 @@
/*
* 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 max-params */
import { useState } from 'react';
import { useDataModal } from '@coze-data/utils';
import {
KnowledgeParamsStoreProvider,
type IKnowledgeParams,
type PluginNavType,
} from '@coze-data/knowledge-stores';
import styles from './index.module.less';
export interface UseKnowledgeIDEFullScreenModalProps {
biz: IKnowledgeParams['biz'];
renderKnowledgeIDE: (props: { onClose: () => void }) => React.ReactNode;
createResourceNavigate?: ({
datasetID,
}: {
datasetID: string;
}) => PluginNavType;
}
export const useKnowledgeIDEFullScreenModal = ({
biz,
renderKnowledgeIDE,
}: UseKnowledgeIDEFullScreenModalProps) => {
const [curDatasetID, setCurDatasetID] = useState('');
const { modal, open, close } = useDataModal({
hideOkButton: true,
hideCancelButton: true,
showCloseIcon: false,
closable: false,
fullScreen: true,
footer: null,
className: styles['knowledge-preview-modal'],
});
return {
node: modal(
<div className={styles['knowledge-preview-modal-content']}>
<KnowledgeParamsStoreProvider
params={{ datasetID: curDatasetID, biz }}
resourceNavigate={{}}
>
{renderKnowledgeIDE({ onClose: close })}
</KnowledgeParamsStoreProvider>
</div>,
),
open: (datasetID: string) => {
setCurDatasetID(datasetID);
open();
},
close,
};
};

View File

@@ -0,0 +1,17 @@
/*
* 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 { KnowledgeIDEBaseLayoutProps } from './module';

View File

@@ -0,0 +1,74 @@
/*
* 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 Dataset, type DocumentInfo } from '@coze-arch/bot-api/knowledge';
import { type ProgressMap } from '@/types';
export interface KnowledgeIDEBaseLayoutProps {
keepDocTitle?: boolean;
className?: string;
renderNavBar?: (context: KnowledgeRenderContext) => ReactNode;
renderContent?: (context: KnowledgeRenderContext) => ReactNode;
}
/**
* 知识库查询相关操作
*/
export interface KnowledgeDataActions {
/** 重新加载知识库数据与文档列表 */
refreshData: () => void;
/** 更新知识库数据集详情 */
updateDataSetDetail: (data: Dataset) => void;
/** 更新文档列表数据 */
updateDocumentList: (data: DocumentInfo[]) => void;
}
/**
* 知识库状态信息
*/
export interface KnowledgeStatusInfo {
/** 知识库是否正在加载 */
isReloading: boolean;
/** 文件处理进度信息 */
progressMap: ProgressMap;
}
/**
* 知识库数据信息
*/
export interface KnowledgeDataInfo {
/** 知识库数据集详情 */
dataSetDetail: Dataset;
/** 文档列表 */
documentList: DocumentInfo[];
}
/**
* 知识库渲染上下文
*/
export interface KnowledgeRenderContext {
/** 组件属性配置 */
layoutProps: KnowledgeIDEBaseLayoutProps;
/** 知识库数据信息 */
dataInfo: KnowledgeDataInfo;
/** 知识库状态信息 */
statusInfo: KnowledgeStatusInfo;
/** 知识库数据操作 */
dataActions: KnowledgeDataActions;
}