feat: manually mirror opencoze's code from bytedance
Change-Id: I09a73aadda978ad9511264a756b2ce51f5761adf
This commit is contained in:
@@ -0,0 +1,31 @@
|
||||
import { mergeConfig } from 'vite';
|
||||
import svgr from 'vite-plugin-svgr';
|
||||
|
||||
/** @type { import('@storybook/react-vite').StorybookConfig } */
|
||||
const config = {
|
||||
stories: ['../stories/**/*.mdx', '../stories/**/*.stories.tsx'],
|
||||
addons: [
|
||||
'@storybook/addon-links',
|
||||
'@storybook/addon-essentials',
|
||||
'@storybook/addon-onboarding',
|
||||
'@storybook/addon-interactions',
|
||||
],
|
||||
framework: {
|
||||
name: '@storybook/react-vite',
|
||||
options: {},
|
||||
},
|
||||
docs: {
|
||||
autodocs: 'tag',
|
||||
},
|
||||
viteFinal: config =>
|
||||
mergeConfig(config, {
|
||||
plugins: [
|
||||
svgr({
|
||||
svgrOptions: {
|
||||
native: false,
|
||||
},
|
||||
}),
|
||||
],
|
||||
}),
|
||||
};
|
||||
export default config;
|
||||
@@ -0,0 +1,14 @@
|
||||
/** @type { import('@storybook/react').Preview } */
|
||||
const preview = {
|
||||
parameters: {
|
||||
actions: { argTypesRegex: "^on[A-Z].*" },
|
||||
controls: {
|
||||
matchers: {
|
||||
color: /(background|color)$/i,
|
||||
date: /Date$/i,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export default preview;
|
||||
@@ -0,0 +1,5 @@
|
||||
const { defineConfig } = require('@coze-arch/stylelint-config');
|
||||
|
||||
module.exports = defineConfig({
|
||||
extends: [],
|
||||
});
|
||||
@@ -0,0 +1,16 @@
|
||||
# @coze-data/knowledge-resource-processor-base
|
||||
|
||||
> Project template for react component with storybook.
|
||||
|
||||
## Features
|
||||
|
||||
- [x] eslint & ts
|
||||
- [x] esm bundle
|
||||
- [x] umd bundle
|
||||
- [x] storybook
|
||||
|
||||
## Commands
|
||||
|
||||
- init: `rush update`
|
||||
- dev: `npm run dev`
|
||||
- build: `npm run build`
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"operationSettings": [
|
||||
{
|
||||
"operationName": "test:cov",
|
||||
"outputFolderNames": ["coverage"]
|
||||
},
|
||||
{
|
||||
"operationName": "ts-check",
|
||||
"outputFolderNames": ["dist"]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
const { defineConfig } = require('@coze-arch/eslint-config');
|
||||
|
||||
module.exports = defineConfig({
|
||||
packageRoot: __dirname,
|
||||
preset: 'web',
|
||||
rules: {},
|
||||
});
|
||||
@@ -0,0 +1,150 @@
|
||||
{
|
||||
"name": "@coze-data/knowledge-resource-processor-base",
|
||||
"version": "0.0.1",
|
||||
"description": "知识库资源处理,包含导入,切片流程",
|
||||
"license": "Apache-2.0",
|
||||
"author": "haozhenfei@bytedance.com",
|
||||
"maintainers": [],
|
||||
"exports": {
|
||||
".": "./src/index.tsx",
|
||||
"./types": "./src/types/index.ts",
|
||||
"./types/*": "./src/types/*/index.ts",
|
||||
"./constants": "./src/constants/index.ts",
|
||||
"./constants/*": "./src/constants/*/index.ts",
|
||||
"./utils": "./src/utils/index.ts",
|
||||
"./utils/*": "./src/utils/*/index.ts",
|
||||
"./hooks": "./src/hooks/index.ts",
|
||||
"./hooks/*": "./src/hooks/*/index.ts",
|
||||
"./services": "./src/services/index.ts",
|
||||
"./services/*": "./src/services/*/index.ts",
|
||||
"./components": "./src/components/index.tsx",
|
||||
"./components/*": "./src/components/*/index.tsx",
|
||||
"./features/*": "./src/features/*/index.tsx",
|
||||
"./layout/*": "./src/layout/*/index.tsx"
|
||||
},
|
||||
"main": "src/index.tsx",
|
||||
"typesVersions": {
|
||||
"*": {
|
||||
"types": [
|
||||
"./src/types/index.ts"
|
||||
],
|
||||
"types/*": [
|
||||
"./src/types/*/index.ts"
|
||||
],
|
||||
"constants": [
|
||||
"./src/constants/index.ts"
|
||||
],
|
||||
"constants/*": [
|
||||
"./src/constants/*/index.ts"
|
||||
],
|
||||
"hooks": [
|
||||
"./src/hooks/index.ts"
|
||||
],
|
||||
"hooks/*": [
|
||||
"./src/hooks/*/index.ts"
|
||||
],
|
||||
"services": [
|
||||
"./src/services/index.ts"
|
||||
],
|
||||
"services/*": [
|
||||
"./src/services/*/index.ts"
|
||||
],
|
||||
"utils": [
|
||||
"./src/utils/index.ts"
|
||||
],
|
||||
"utils/*": [
|
||||
"./src/utils/*/index.ts"
|
||||
],
|
||||
"components": [
|
||||
"./src/components/index.tsx"
|
||||
],
|
||||
"components/*": [
|
||||
"./src/components/*/index.tsx"
|
||||
],
|
||||
"features/*": [
|
||||
"./src/features/*/index.tsx"
|
||||
],
|
||||
"layout/*": [
|
||||
"./src/layout/*/index.tsx"
|
||||
]
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"build": "exit 0",
|
||||
"lint": "eslint ./ --cache",
|
||||
"test": "vitest --run --passWithNoTests",
|
||||
"test:cov": "npm run test -- --coverage"
|
||||
},
|
||||
"dependencies": {
|
||||
"@coze-arch/bot-api": "workspace:*",
|
||||
"@coze-arch/bot-error": "workspace:*",
|
||||
"@coze-arch/bot-flags": "workspace:*",
|
||||
"@coze-arch/bot-http": "workspace:*",
|
||||
"@coze-arch/bot-icons": "workspace:*",
|
||||
"@coze-arch/bot-md-box-adapter": "workspace:*",
|
||||
"@coze-arch/bot-semi": "workspace:*",
|
||||
"@coze-arch/bot-studio-store": "workspace:*",
|
||||
"@coze-arch/bot-utils": "workspace:*",
|
||||
"@coze-arch/coze-design": "0.0.6-alpha.346d77",
|
||||
"@coze-arch/foundation-sdk": "workspace:*",
|
||||
"@coze-arch/i18n": "workspace:*",
|
||||
"@coze-arch/idl": "workspace:*",
|
||||
"@coze-arch/pdfjs-shadow": "workspace:*",
|
||||
"@coze-arch/report-events": "workspace:*",
|
||||
"@coze-arch/report-tti": "workspace:*",
|
||||
"@coze-arch/utils": "workspace:*",
|
||||
"@coze-common/table-view": "workspace:*",
|
||||
"@coze-common/virtual-list": "workspace:*",
|
||||
"@coze-data/e2e": "workspace:*",
|
||||
"@coze-data/knowledge-common-components": "workspace:*",
|
||||
"@coze-data/knowledge-common-hooks": "workspace:*",
|
||||
"@coze-data/knowledge-common-services": "workspace:*",
|
||||
"@coze-data/knowledge-modal-base": "workspace:*",
|
||||
"@coze-data/knowledge-resource-processor-core": "workspace:*",
|
||||
"@coze-data/knowledge-stores": "workspace:*",
|
||||
"@coze-data/reporter": "workspace:*",
|
||||
"@coze-data/utils": "workspace:*",
|
||||
"@coze-studio/components": "workspace:*",
|
||||
"@dnd-kit/core": "^6.0.8",
|
||||
"@dnd-kit/modifiers": "^7.0.0",
|
||||
"@dnd-kit/sortable": "^7.0.2",
|
||||
"@dnd-kit/utilities": "^3.2.1",
|
||||
"@douyinfe/semi-icons": "^2.36.0",
|
||||
"@douyinfe/semi-illustrations": "^2.36.0",
|
||||
"ahooks": "^3.7.8",
|
||||
"classnames": "^2.3.2",
|
||||
"cropperjs": "^1.5.12",
|
||||
"immer": "^10.0.3",
|
||||
"lodash-es": "^4.17.21",
|
||||
"nanoid": "^4.0.2",
|
||||
"react-arborist": "^3.4.0",
|
||||
"react-pdf": "9.1.1",
|
||||
"semver": "^7.3.7",
|
||||
"usehooks-ts": "^3.1.0",
|
||||
"zustand": "^4.4.7"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@coze-arch/bot-typings": "workspace:*",
|
||||
"@coze-arch/eslint-config": "workspace:*",
|
||||
"@coze-arch/stylelint-config": "workspace:*",
|
||||
"@coze-arch/ts-config": "workspace:*",
|
||||
"@coze-arch/vitest-config": "workspace:*",
|
||||
"@testing-library/jest-dom": "^6.1.5",
|
||||
"@testing-library/react": "^14.1.2",
|
||||
"@testing-library/react-hooks": "^8.0.1",
|
||||
"@types/lodash-es": "^4.17.10",
|
||||
"@types/react": "18.2.37",
|
||||
"@types/react-dom": "18.2.15",
|
||||
"@vitest/coverage-v8": "~3.0.5",
|
||||
"react": "~18.2.0",
|
||||
"react-dom": "~18.2.0",
|
||||
"stylelint": "^15.11.0",
|
||||
"vite-plugin-svgr": "~3.3.0",
|
||||
"vitest": "~3.0.5"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=18.2.0",
|
||||
"react-dom": ">=18.2.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
.common-svg-icon(@size: 14px, @color: #3370ff) {
|
||||
>svg {
|
||||
width: @size;
|
||||
height: @size;
|
||||
|
||||
>path {
|
||||
fill: @color;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M3.40426 10.334L3.75781 10.6875C3.95307 10.8828 4.26966 10.8828 4.46492 10.6875L8.35401 6.79845C8.74453 6.40792 8.74453 5.77476 8.35401 5.38424L4.46492 1.49515C4.26966 1.29988 3.95307 1.29988 3.75781 1.49515L3.40426 1.8487C3.209 2.04396 3.209 2.36054 3.40426 2.55581L6.93979 6.09134L3.40426 9.62688C3.209 9.82214 3.209 10.1387 3.40426 10.334Z"
|
||||
fill="#888892" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 484 B |
Binary file not shown.
|
After Width: | Height: | Size: 36 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 54 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 35 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 22 KiB |
@@ -0,0 +1,181 @@
|
||||
/*
|
||||
* 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 { nanoid } from 'nanoid';
|
||||
import { transSliceContentOutput } from '@coze-data/knowledge-modal-base';
|
||||
import {
|
||||
DocumentEditor,
|
||||
useInitEditor,
|
||||
EditorToolbar,
|
||||
type Chunk,
|
||||
} from '@coze-data/knowledge-common-components/text-knowledge-editor';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import { Form, Input, Modal, Toast } from '@coze-arch/coze-design';
|
||||
import { MemoryApi } from '@coze-arch/bot-api';
|
||||
|
||||
import { useGetWebInfo } from './hooks/get-web-info';
|
||||
import { editorToolbarActionRegistry } from './editor-toolbar-actions-contributes';
|
||||
import { editorContextActionRegistry } from './editor-context-actions-contributes';
|
||||
|
||||
import styles from './index.module.less';
|
||||
|
||||
const MAX_DOC_NAME_LEN = 100;
|
||||
export interface UseBrowseDetailModalReturnValue {
|
||||
open: () => void;
|
||||
node: JSX.Element;
|
||||
}
|
||||
|
||||
export interface ViewOnlinePageDetailProps {
|
||||
id?: string;
|
||||
url?: string;
|
||||
content?: string;
|
||||
title?: string;
|
||||
}
|
||||
|
||||
export interface BrowseUrlModalProps {
|
||||
name: string;
|
||||
webID?: string;
|
||||
onSubmit: (name: string, content?: string) => void;
|
||||
onCancel?: () => void;
|
||||
}
|
||||
|
||||
export const BrowseUrlModal = ({
|
||||
name,
|
||||
webID,
|
||||
onSubmit,
|
||||
onCancel,
|
||||
}: BrowseUrlModalProps) => {
|
||||
const [docName, setDocName] = useState<string>(name);
|
||||
const { data: pageList, runAsync, mutate } = useGetWebInfo();
|
||||
|
||||
const [initChunk, setInitChunk] = useState<Chunk>({
|
||||
text_knowledge_editor_chunk_uuid: nanoid(),
|
||||
content: '',
|
||||
});
|
||||
|
||||
const { editor } = useInitEditor({
|
||||
chunk: initChunk,
|
||||
editorProps: {
|
||||
attributes: {
|
||||
class: 'h-[360px] overflow-y-auto',
|
||||
},
|
||||
},
|
||||
onChange: v => {
|
||||
mutate(
|
||||
([] as ViewOnlinePageDetailProps[]).concat({
|
||||
...pageList?.[0],
|
||||
content: v.content ?? '',
|
||||
}),
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
setDocName(name);
|
||||
}, [name]);
|
||||
|
||||
useEffect(() => {
|
||||
if (webID) {
|
||||
runAsync(webID).then(data => {
|
||||
setInitChunk({
|
||||
text_knowledge_editor_chunk_uuid: nanoid(),
|
||||
content: data[0].content ?? '',
|
||||
});
|
||||
});
|
||||
}
|
||||
}, [webID, runAsync, editor]);
|
||||
|
||||
return (
|
||||
<Modal
|
||||
title={I18n.t('knowledge_insert_img_001')}
|
||||
width={792}
|
||||
visible
|
||||
cancelText={I18n.t('Cancel')}
|
||||
okText={I18n.t('datasets_segment_detailModel_save')}
|
||||
maskClosable={false}
|
||||
onOk={async () => {
|
||||
const pageInfo = pageList?.[0];
|
||||
const content = transSliceContentOutput(pageInfo.content as string);
|
||||
await MemoryApi.SubmitWebContentV2({
|
||||
web_id: pageInfo.id,
|
||||
content,
|
||||
});
|
||||
Toast.success({
|
||||
content: I18n.t('datasets_url_saveSuccess'),
|
||||
showClose: false,
|
||||
});
|
||||
onSubmit?.(docName, content);
|
||||
onCancel?.();
|
||||
}}
|
||||
onCancel={() => {
|
||||
onCancel?.();
|
||||
}}
|
||||
>
|
||||
<Form<Record<string, unknown>> layout="vertical" showValidateIcon={false}>
|
||||
<Form.Slot
|
||||
label={{ text: I18n.t('knowledge_upload_text_custom_doc_name') }}
|
||||
>
|
||||
<Input
|
||||
className={styles['doc-name-input']}
|
||||
value={docName}
|
||||
onChange={(v: string) => setDocName(v)}
|
||||
maxLength={MAX_DOC_NAME_LEN}
|
||||
placeholder={I18n.t('knowledge_upload_text_custom_doc_name_tips')}
|
||||
/>
|
||||
</Form.Slot>
|
||||
<Form.Slot
|
||||
className={styles['form-segment-content']}
|
||||
label={{ text: I18n.t('knowledge_upload_text_custom_doc_content') }}
|
||||
>
|
||||
<DocumentEditor
|
||||
editor={editor}
|
||||
placeholder={I18n.t(
|
||||
'knowledge_upload_text_custom_doc_content_tips',
|
||||
)}
|
||||
editorContextMenuItemsRegistry={editorContextActionRegistry}
|
||||
editorBottomSlot={
|
||||
<EditorToolbar
|
||||
editor={editor}
|
||||
actionRegistry={editorToolbarActionRegistry}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
{pageList?.[0]?.url ? (
|
||||
<div className={styles['browse-source-url']}>
|
||||
{I18n.t('knowledge_insert_img_003', {
|
||||
url: pageList[0]?.url,
|
||||
})}
|
||||
</div>
|
||||
) : null}
|
||||
</Form.Slot>
|
||||
</Form>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
export const useBrowseUrlModal = (props: BrowseUrlModalProps) => {
|
||||
const [visible, setVisible] = useState(false);
|
||||
|
||||
return {
|
||||
open: () => setVisible(true),
|
||||
close: () => setVisible(false),
|
||||
node: visible ? (
|
||||
<BrowseUrlModal {...props} onCancel={() => setVisible(false)} />
|
||||
) : null,
|
||||
};
|
||||
};
|
||||
@@ -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 { UploadImageMenu } from '@coze-data/knowledge-common-components/text-knowledge-editor/features/editor-actions/upload-image';
|
||||
import {
|
||||
createEditorActionFeatureRegistry,
|
||||
type EditorActionRegistry,
|
||||
} from '@coze-data/knowledge-common-components/text-knowledge-editor/features/editor-actions';
|
||||
export const editorContextActionRegistry: EditorActionRegistry = (() => {
|
||||
const editorContextActionFeatureRegistry = createEditorActionFeatureRegistry(
|
||||
'editor-context-actions',
|
||||
);
|
||||
editorContextActionFeatureRegistry.registerSome([
|
||||
{
|
||||
type: 'upload-image',
|
||||
module: {
|
||||
Component: UploadImageMenu,
|
||||
},
|
||||
},
|
||||
]);
|
||||
return editorContextActionFeatureRegistry;
|
||||
})();
|
||||
@@ -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 { UploadImageButton } from '@coze-data/knowledge-common-components/text-knowledge-editor/features/editor-actions/upload-image';
|
||||
import {
|
||||
createEditorActionFeatureRegistry,
|
||||
type EditorActionRegistry,
|
||||
} from '@coze-data/knowledge-common-components/text-knowledge-editor/features/editor-actions';
|
||||
export const editorToolbarActionRegistry: EditorActionRegistry = (() => {
|
||||
const editorToolbarActionFeatureRegistry = createEditorActionFeatureRegistry(
|
||||
'editor-toolbar-actions',
|
||||
);
|
||||
editorToolbarActionFeatureRegistry.registerSome([
|
||||
{
|
||||
type: 'upload-image',
|
||||
module: {
|
||||
Component: UploadImageButton,
|
||||
},
|
||||
},
|
||||
]);
|
||||
return editorToolbarActionFeatureRegistry;
|
||||
})();
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* 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 { useRequest } from 'ahooks';
|
||||
import { KnowledgeApi } from '@coze-arch/bot-api';
|
||||
|
||||
import { type ViewOnlinePageDetailProps } from '@/types';
|
||||
|
||||
/**
|
||||
* 将API返回的网页信息转换为视图数据
|
||||
*/
|
||||
const transformWebInfoToViewData = (webInfo: {
|
||||
id?: string;
|
||||
url?: string;
|
||||
title?: string;
|
||||
content?: string;
|
||||
}): ViewOnlinePageDetailProps => ({
|
||||
id: webInfo?.id,
|
||||
url: webInfo?.url,
|
||||
title: webInfo?.title,
|
||||
content: webInfo?.content,
|
||||
});
|
||||
|
||||
export const useGetWebInfo = (): {
|
||||
data: ViewOnlinePageDetailProps[];
|
||||
loading: boolean;
|
||||
runAsync: (webID: string) => Promise<ViewOnlinePageDetailProps[]>;
|
||||
mutate: (data: ViewOnlinePageDetailProps[]) => void;
|
||||
} => {
|
||||
const { data, mutate, loading, runAsync } = useRequest(
|
||||
async (webID: string) => {
|
||||
const { data: responseData } = await KnowledgeApi.GetWebInfo({
|
||||
web_ids: [webID],
|
||||
include_content: true,
|
||||
});
|
||||
|
||||
// 如果没有数据,返回空数组
|
||||
if (!responseData?.[webID]?.web_info) {
|
||||
return [] as ViewOnlinePageDetailProps[];
|
||||
}
|
||||
|
||||
const webInfo = responseData[webID].web_info;
|
||||
const mainPageData = transformWebInfoToViewData(webInfo);
|
||||
const result = [mainPageData];
|
||||
|
||||
// 处理子页面数据
|
||||
if (webInfo?.subpages?.length) {
|
||||
const subpagesData = webInfo.subpages.map(transformWebInfoToViewData);
|
||||
result.push(...subpagesData);
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
);
|
||||
|
||||
return {
|
||||
data: data || [],
|
||||
loading,
|
||||
runAsync,
|
||||
mutate,
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,106 @@
|
||||
/* stylelint-disable declaration-no-important */
|
||||
.browse-detail-modal {
|
||||
padding-bottom: 40px;
|
||||
|
||||
&-main {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
margin-bottom: 16px;
|
||||
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
line-height: 20px;
|
||||
color: rgb(28 31 35 / 100%);
|
||||
|
||||
&-image {
|
||||
display: flex;
|
||||
flex-shrink: 0;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
margin-right: 7px;
|
||||
|
||||
background-color: rgb(152 205 253 / 100%);
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
&-title {
|
||||
max-width: 40%;
|
||||
}
|
||||
|
||||
&-url {
|
||||
max-width: 40%;
|
||||
margin-left: 7px;
|
||||
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
line-height: 16px;
|
||||
color: rgb(28 31 35 / 35%);
|
||||
}
|
||||
}
|
||||
|
||||
&-collapse {
|
||||
overflow-y: auto;
|
||||
max-height: 400px;
|
||||
background-color: #f5f5f5;
|
||||
border-radius: 4px;
|
||||
|
||||
:global {
|
||||
.semi-collapse-item {
|
||||
border-color: #efefef !important;
|
||||
}
|
||||
|
||||
.semi-input-textarea-wrapper {
|
||||
background-color: rgb(0 0 0 / 0%) !important;
|
||||
border: none !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.browse-modal-header {
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
align-items: center;
|
||||
padding: 24px 0;
|
||||
|
||||
&-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
&-icon {
|
||||
margin-right: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.modal.upgrade-level {
|
||||
:global {
|
||||
.semi-modal-body {
|
||||
height: 0;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.semi-modal-content {
|
||||
background-color: var(--semi-color-tertiary-light-default);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.browse-detail-tooltip {
|
||||
width: 200px;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
.browse-source-url {
|
||||
margin-top: 12px;
|
||||
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
font-style: normal;
|
||||
line-height: 16px;
|
||||
color: rgb(29 28 36 / 35%)
|
||||
}
|
||||
@@ -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 { useBrowseUrlModal } from './browser-url-modal';
|
||||
@@ -0,0 +1,37 @@
|
||||
.card-radio-group {
|
||||
gap: 4px;
|
||||
|
||||
:global {
|
||||
.semi-radio {
|
||||
padding: 12px;
|
||||
border-radius: 8px;
|
||||
|
||||
&:hover {
|
||||
background-color: var(--coz-mg-secondary-hovered);
|
||||
}
|
||||
|
||||
&:active {
|
||||
background-color: var(--coz-mg-secondary-pressed);
|
||||
}
|
||||
|
||||
&.semi-radio-checked {
|
||||
padding: 11.5px;
|
||||
background-color: var(--coz-mg-card);
|
||||
border-width: 1.5px;
|
||||
}
|
||||
}
|
||||
|
||||
.semi-radio-content {
|
||||
flex-grow: 1;
|
||||
|
||||
.semi-radio-addon {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.semi-radio-extra {
|
||||
font-size: 12px;
|
||||
line-height: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* 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 PropsWithChildren } from 'react';
|
||||
|
||||
import classNames from 'classnames';
|
||||
import { RadioGroup, type RadioGroupProps } from '@coze-arch/coze-design';
|
||||
|
||||
import styles from './index.module.less';
|
||||
|
||||
export type CardRadioGroupProps<T = unknown> = PropsWithChildren<
|
||||
Pick<RadioGroupProps, 'value' | 'className'>
|
||||
> & {
|
||||
onChange?: (value: T) => void;
|
||||
};
|
||||
|
||||
/**
|
||||
* 始终使用卡片风格,并符合 UI 设计样式的 {@link RadioGroup}
|
||||
*/
|
||||
export function CardRadioGroup<T = unknown>({
|
||||
value,
|
||||
onChange,
|
||||
className,
|
||||
children,
|
||||
}: CardRadioGroupProps<T>) {
|
||||
return (
|
||||
<RadioGroup
|
||||
type="pureCard"
|
||||
direction="vertical"
|
||||
value={value}
|
||||
onChange={e => {
|
||||
onChange?.(e.target.value as T);
|
||||
}}
|
||||
className={classNames(styles['card-radio-group'], className)}
|
||||
>
|
||||
{children}
|
||||
</RadioGroup>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* 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, type PropsWithChildren } from 'react';
|
||||
|
||||
import classNames from 'classnames';
|
||||
import { IconCozArrowRight } from '@coze-arch/coze-design/icons';
|
||||
import { Collapsible, Typography } from '@coze-arch/coze-design';
|
||||
|
||||
export interface CollapsePanelProps extends PropsWithChildren {
|
||||
header: React.ReactNode;
|
||||
keepDOM?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* 用 Collapsible 封装的更符合 UI 设计的折叠面板
|
||||
*/
|
||||
export function CollapsePanel({
|
||||
header,
|
||||
keepDOM,
|
||||
children,
|
||||
}: CollapsePanelProps) {
|
||||
const [open, setOpen] = useState(true);
|
||||
|
||||
return (
|
||||
<div className="mb-[4px]">
|
||||
<div
|
||||
className={classNames(
|
||||
'h-[40px] flex items-center gap-[4px] shrink-0 rounded',
|
||||
'cursor-pointer hover:coz-mg-secondary-hovered active:coz-mg-secondary-pressed',
|
||||
)}
|
||||
onClick={() => setOpen(!open)}
|
||||
>
|
||||
<IconCozArrowRight
|
||||
className={classNames('coz-fg-secondary text-[14px] m-[4px]', {
|
||||
'rotate-90': open,
|
||||
})}
|
||||
/>
|
||||
<Typography.Text fontSize="14px" weight={400}>
|
||||
{header}
|
||||
</Typography.Text>
|
||||
</div>
|
||||
<Collapsible
|
||||
className="ml-[26px] [&>div]:pt-[4px]"
|
||||
isOpen={open}
|
||||
keepDOM={keepDOM}
|
||||
>
|
||||
{children}
|
||||
</Collapsible>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -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 { I18n } from '@coze-arch/i18n';
|
||||
import { Banner } from '@coze-arch/coze-design';
|
||||
|
||||
export const ConfigurationBanner = () => (
|
||||
<Banner
|
||||
style={{ marginTop: '10px' }}
|
||||
type="warning"
|
||||
description={I18n.t('knowledge_limit_20')}
|
||||
/>
|
||||
);
|
||||
@@ -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 { IllustrationNoResult } from '@douyinfe/semi-illustrations';
|
||||
import { UIEmpty } from '@coze-arch/bot-semi';
|
||||
|
||||
import styles from './index.module.less';
|
||||
|
||||
interface ConfigurationErrorProps {
|
||||
fetchTableInfo: () => void;
|
||||
}
|
||||
export const ConfigurationError = (props: ConfigurationErrorProps) => {
|
||||
const { fetchTableInfo } = props;
|
||||
return (
|
||||
<UIEmpty
|
||||
className={styles['load-failure']}
|
||||
empty={{
|
||||
title: 'Read failure',
|
||||
description: '',
|
||||
icon: <IllustrationNoResult></IllustrationNoResult>,
|
||||
btnText: 'Retry',
|
||||
btnOnClick: fetchTableInfo,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,24 @@
|
||||
/* stylelint-disable font-family-no-missing-generic-family-keyword */
|
||||
.load-failure {
|
||||
min-height: 400px;
|
||||
}
|
||||
|
||||
.loading {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
width: 100%;
|
||||
min-height: 400px;
|
||||
|
||||
&-content {
|
||||
margin-left: 8px;
|
||||
|
||||
font-family: "SF Pro Display";
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
font-style: normal;
|
||||
line-height: 20px;
|
||||
color: rgb(29 28 35 / 35%);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* 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 { Spin } from '@coze-arch/coze-design';
|
||||
|
||||
import styles from './index.module.less';
|
||||
|
||||
export const ConfigurationLoading = () => (
|
||||
<div className={styles.loading}>
|
||||
<Spin spinning></Spin>
|
||||
<div className={styles['loading-content']}>
|
||||
{I18n.t('knowledge_1221_03')}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* 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 cls from 'classnames';
|
||||
import { Typography } from '@coze-arch/coze-design';
|
||||
|
||||
interface IDocumentItemProps {
|
||||
id: string;
|
||||
onClick: (id: string) => void;
|
||||
selected: boolean;
|
||||
title: string;
|
||||
status?: 'pending' | 'finished' | 'failed';
|
||||
addonAfter?: ReactNode;
|
||||
}
|
||||
|
||||
export const DocumentItem: React.FC<IDocumentItemProps> = props => {
|
||||
const { id, onClick, title, selected, addonAfter } = props;
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cls(
|
||||
'w-full h-8 px-2 py-[6px] rounded-[8px] hover:coz-mg-primary cursor-pointer flex flex-nowrap',
|
||||
selected && 'coz-mg-primary',
|
||||
)}
|
||||
onClick={() => onClick(id)}
|
||||
>
|
||||
<Typography.Text
|
||||
className="w-full coz-fg-primary text-[14px] leading-[20px] grow truncate"
|
||||
ellipsis
|
||||
>
|
||||
{title}
|
||||
</Typography.Text>
|
||||
{addonAfter}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default DocumentItem;
|
||||
@@ -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 classNames from 'classnames';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import { Tag, Tooltip } from '@coze-arch/coze-design';
|
||||
|
||||
import {
|
||||
getFilterPagesString,
|
||||
getSortedFilterPages,
|
||||
} from '../../utils/render-document-filter-value';
|
||||
import { DocumentItem } from './document-item';
|
||||
|
||||
interface FilterPageConfig {
|
||||
pageIndex: number;
|
||||
isFilter: boolean;
|
||||
}
|
||||
|
||||
interface Document {
|
||||
// TODO: 扩充
|
||||
id: string;
|
||||
title: string;
|
||||
/** 是否存在过滤内容 */
|
||||
filterPageConfigList: FilterPageConfig[];
|
||||
}
|
||||
|
||||
interface IDocumentListProps {
|
||||
documents: Document[];
|
||||
value: string;
|
||||
onChange: (value: string) => void;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export const DocumentList = (props: IDocumentListProps) => (
|
||||
<div className={classNames('flex flex-col gap-1 h-full', props.className)}>
|
||||
<div className="w-full pl-2 h-6 items-center flex">
|
||||
<div className="coz-fg-secondary text-[12px] font-[400] leading-4 shrink-0">
|
||||
{I18n.t('kl_write_105')}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col gap-1 h-[150px] !overflow-scroll shrink-0">
|
||||
{props.documents.map(document => {
|
||||
if (!document.id) {
|
||||
return null;
|
||||
}
|
||||
const filterPages = getSortedFilterPages(document.filterPageConfigList);
|
||||
const isFiltered = Boolean(filterPages.length);
|
||||
const filterPagesString = getFilterPagesString(filterPages);
|
||||
|
||||
return (
|
||||
<DocumentItem
|
||||
id={document.id}
|
||||
selected={document.id === props.value}
|
||||
onClick={id => {
|
||||
props.onChange(id);
|
||||
}}
|
||||
title={document.title}
|
||||
addonAfter={
|
||||
isFiltered ? (
|
||||
<Tooltip
|
||||
content={I18n.t('data_filter_values', {
|
||||
filterPages: filterPagesString,
|
||||
})}
|
||||
>
|
||||
<Tag color="primary" className="flex-shrink-0">
|
||||
{I18n.t('knowledge_new_002')}
|
||||
</Tag>
|
||||
</Tooltip>
|
||||
) : null
|
||||
}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
@@ -0,0 +1,41 @@
|
||||
.auth-empty-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: calc(100% - 112px);
|
||||
|
||||
.auth-empty {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.auth-empty-image {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
width: 140px;
|
||||
height: 140px;
|
||||
}
|
||||
|
||||
.auth-empty-description {
|
||||
margin-top: 16px;
|
||||
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
line-height: 22px;
|
||||
color: var(--coz-fg-primary);
|
||||
}
|
||||
|
||||
.auth-empty-second-desc {
|
||||
margin-top: 4px;
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
color: var(--coz-fg-secondary);
|
||||
}
|
||||
|
||||
.auth-empty-button {
|
||||
margin-top: 21px;
|
||||
}
|
||||
}
|
||||
@@ -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 classNames from 'classnames';
|
||||
import { Button } from '@coze-arch/coze-design';
|
||||
|
||||
import style from './index.module.less';
|
||||
|
||||
export interface CommonEmptyAuthProps {
|
||||
illustrationIcon: JSX.Element;
|
||||
description: string;
|
||||
authUrl?: string;
|
||||
btnText?: string;
|
||||
className?: string;
|
||||
onClick?: () => void;
|
||||
secondDesc?: string;
|
||||
}
|
||||
export const AuthEmpty = (props: CommonEmptyAuthProps) => {
|
||||
const {
|
||||
description,
|
||||
authUrl,
|
||||
onClick,
|
||||
btnText,
|
||||
illustrationIcon,
|
||||
className,
|
||||
secondDesc,
|
||||
} = props;
|
||||
const handleClick = () => {
|
||||
if (authUrl) {
|
||||
window.open(authUrl, '_self');
|
||||
} else {
|
||||
onClick?.();
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={classNames(style['auth-empty-wrapper'], className)}>
|
||||
<div className={style['auth-empty']}>
|
||||
<div className={style['auth-empty-image']}>{illustrationIcon}</div>
|
||||
<div className={style['auth-empty-description']}>{description}</div>
|
||||
{secondDesc ? (
|
||||
<div className={style['auth-empty-second-desc']}>{secondDesc}</div>
|
||||
) : null}
|
||||
{btnText ? (
|
||||
<Button
|
||||
color="highlight"
|
||||
className={style['auth-empty-button']}
|
||||
onClick={handleClick}
|
||||
>
|
||||
{btnText}
|
||||
</Button>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* 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 { AuthEmpty } from './common-empty-auth';
|
||||
export type { CommonEmptyAuthProps } from './common-empty-auth';
|
||||
@@ -0,0 +1,41 @@
|
||||
.auth-empty-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: calc(100% - 112px);
|
||||
|
||||
.auth-empty {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.auth-empty-image {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
width: 140px;
|
||||
height: 140px;
|
||||
}
|
||||
|
||||
.auth-empty-description {
|
||||
margin-top: 16px;
|
||||
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
line-height: 22px;
|
||||
color: var(--Light-usage-text---color-text-0, #1D1C23);
|
||||
}
|
||||
|
||||
.auth-empty-second-desc {
|
||||
margin-top: 4px;
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
color: var(--Light-usage-text---color-text-2, rgba(29, 28, 35, 60%));
|
||||
}
|
||||
|
||||
.auth-empty-button {
|
||||
margin-top: 21px;
|
||||
}
|
||||
}
|
||||
@@ -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 classNames from 'classnames';
|
||||
import { UIButton } from '@coze-arch/bot-semi';
|
||||
|
||||
import style from './index.module.less';
|
||||
|
||||
interface Props {
|
||||
illustrationIcon: JSX.Element;
|
||||
description: string;
|
||||
btnText?: string;
|
||||
className?: string;
|
||||
onClick?: () => void;
|
||||
secondDesc?: string;
|
||||
}
|
||||
export const Empty = (props: Props) => {
|
||||
const {
|
||||
description,
|
||||
onClick,
|
||||
btnText,
|
||||
illustrationIcon,
|
||||
className,
|
||||
secondDesc,
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<div className={classNames(style['auth-empty-wrapper'], className)}>
|
||||
<div className={style['auth-empty']}>
|
||||
<div className={style['auth-empty-image']}>{illustrationIcon}</div>
|
||||
<div className={style['auth-empty-description']}>{description}</div>
|
||||
{secondDesc ? (
|
||||
<div className={style['auth-empty-second-desc']}>{secondDesc}</div>
|
||||
) : null}
|
||||
{btnText ? (
|
||||
<UIButton
|
||||
type="tertiary"
|
||||
className={style['auth-empty-button']}
|
||||
onClick={onClick}
|
||||
>
|
||||
{btnText}
|
||||
</UIButton>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,17 @@
|
||||
.frequency-form-item {
|
||||
.title {
|
||||
display: block;
|
||||
flex-shrink: 0;
|
||||
|
||||
box-sizing: border-box;
|
||||
margin-bottom: 8px;
|
||||
|
||||
font-size: 12px;
|
||||
line-height: 16px;
|
||||
color: var(--coz-fg-secondary);
|
||||
}
|
||||
|
||||
.content {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
@@ -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 { type FC } from 'react';
|
||||
|
||||
import { KnowledgeE2e } from '@coze-data/e2e';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import { Select, Typography } from '@coze-arch/coze-design';
|
||||
|
||||
import { getFrequencyMap } from '../../utils';
|
||||
import { FrequencyDay } from '../../constants';
|
||||
|
||||
import styles from './index.module.less';
|
||||
|
||||
interface Props {
|
||||
value: number;
|
||||
onChange: (v: number) => void;
|
||||
}
|
||||
|
||||
export const FrequencyFormItem: FC<Props> = ({ value, onChange }) => (
|
||||
<div
|
||||
className={styles['frequency-form-item']}
|
||||
data-testid={KnowledgeE2e.OnlineUploadModalFrequencySelect}
|
||||
>
|
||||
<Typography.Text className={styles.title}>
|
||||
{I18n.t('datasets_frequencyModal_frequency')}
|
||||
</Typography.Text>
|
||||
<div className={styles.content}>
|
||||
<Select
|
||||
placeholder={I18n.t('datasets_frequencyModal_frequency')}
|
||||
style={{ width: '100%' }}
|
||||
value={value}
|
||||
onChange={v => onChange(v as number)}
|
||||
>
|
||||
{[
|
||||
FrequencyDay.ZERO,
|
||||
FrequencyDay.ONE,
|
||||
FrequencyDay.THREE,
|
||||
FrequencyDay.SEVEN,
|
||||
FrequencyDay.THIRTY,
|
||||
].map(frequency => (
|
||||
<Select.Option key={frequency} value={frequency}>
|
||||
{getFrequencyMap(frequency)}
|
||||
</Select.Option>
|
||||
))}
|
||||
</Select>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
export { UploadFooter } from './upload-footer';
|
||||
export { useBrowseUrlModal } from './browser-url-modal';
|
||||
export {
|
||||
TableSettingBar,
|
||||
type TableSettingBarProps,
|
||||
type TablePreviewProps,
|
||||
TablePreview,
|
||||
type TableStructureProps,
|
||||
TableStructure,
|
||||
TableStructureTitle,
|
||||
} from './table-format';
|
||||
export { UnitProgress } from './unit-progress';
|
||||
export { UploadUnitFile } from './upload-unit-file';
|
||||
export { UploadUnitTable } from './upload-unit-table';
|
||||
export { ConfigurationError } from './configuration/error';
|
||||
export { ConfigurationLoading } from './configuration/loading';
|
||||
export { ConfigurationBanner } from './configuration/banner';
|
||||
export { AuthEmpty } from './empty-auth';
|
||||
export { Empty } from './empty';
|
||||
export { FrequencyFormItem } from './frequency-form-item';
|
||||
export { CollapsePanel } from './collapse-panel';
|
||||
export { CardRadioGroup } from './card-radio-group';
|
||||
export { getProcessStatus } from './upload-unit-table/utils';
|
||||
export {
|
||||
type ColumnInfo,
|
||||
type UploadUnitTableProps,
|
||||
type RenderColumnsProps,
|
||||
} from './upload-unit-table/types';
|
||||
export {
|
||||
ActionRenderByDelete,
|
||||
ActionRenderByEditName,
|
||||
ActionRenderByRetry,
|
||||
} from './upload-unit-table';
|
||||
@@ -0,0 +1,117 @@
|
||||
/* stylelint-disable declaration-no-important */
|
||||
/* stylelint-disable no-duplicate-selectors */
|
||||
.progress-wrap {
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
align-items: center;
|
||||
align-self: stretch;
|
||||
|
||||
padding: 8px 10px;
|
||||
|
||||
background: var(--coz-mg-card);
|
||||
border:1px solid var(--coz-stroke-primary);
|
||||
border-radius: var(--default, 8px);
|
||||
|
||||
|
||||
|
||||
.content {
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.progress {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
|
||||
background: linear-gradient(180deg, rgba(148, 152, 247, 44%), rgba(255, 255, 255, 0%));
|
||||
}
|
||||
|
||||
.info {
|
||||
.main-text {
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
color: var(--coz-fg-primary);
|
||||
}
|
||||
|
||||
.sub-text {
|
||||
font-size: 12px;
|
||||
line-height: 16px;
|
||||
color: var(--coz-fg-secondary);
|
||||
}
|
||||
|
||||
.desc {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.tip-desc {
|
||||
display: none;
|
||||
}
|
||||
|
||||
:global {
|
||||
.semi-image {
|
||||
margin-right: 0!important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
.info {
|
||||
.desc {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.tip-desc {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
&.processing-failed {
|
||||
border: 1px solid var(--coz-stroke-hglt-red);
|
||||
|
||||
.sub-text {
|
||||
color: var(--coz-fg-hglt-red)!important;
|
||||
}
|
||||
}
|
||||
|
||||
&.processing {
|
||||
&:hover {
|
||||
.info {
|
||||
.desc {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.tip-desc {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.right {
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.percent {
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
font-style: normal;
|
||||
line-height: 20px;
|
||||
color: var(--coz-fg-primary);
|
||||
text-align: right;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.actions {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
.actions {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 { ProcessProgressItem } from './process-progress-item';
|
||||
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* 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 { Fragment } from 'react';
|
||||
|
||||
import cls from 'classnames';
|
||||
import { KnowledgeE2e } from '@coze-data/e2e';
|
||||
import { Typography, Space } from '@coze-arch/coze-design';
|
||||
|
||||
import { ProcessStatus, type ProcessProgressItemProps } from '../../types';
|
||||
|
||||
import styles from './index.module.less';
|
||||
|
||||
export const ProcessProgressItem: React.FC<ProcessProgressItemProps> = ({
|
||||
className,
|
||||
style,
|
||||
mainText,
|
||||
subText,
|
||||
percent = 10,
|
||||
percentFormat,
|
||||
avatar,
|
||||
status,
|
||||
actions,
|
||||
tipText = '',
|
||||
}) => {
|
||||
const renderProgress = () => {
|
||||
if (status === ProcessStatus.Processing) {
|
||||
return (
|
||||
<div className={styles.progress} style={{ width: `${percent}%` }}></div>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
const renderActions = () => {
|
||||
if (status === ProcessStatus.Processing) {
|
||||
return (
|
||||
<span className={styles.percent}>
|
||||
{percentFormat ? percentFormat : `${percent}%`}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={cls(styles.actions, 'process-progress-item-actions')}>
|
||||
{Array.isArray(actions) ? (
|
||||
<Space spacing="tight">
|
||||
{actions.map((action, idx) => (
|
||||
<Fragment key={idx}>{action}</Fragment>
|
||||
))}
|
||||
</Space>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
key={mainText}
|
||||
className={cls(
|
||||
styles['progress-wrap'],
|
||||
'flex justify-between relative mb-[8px]',
|
||||
status === ProcessStatus.Failed ? styles['processing-failed'] : '',
|
||||
status === ProcessStatus.Processing ? styles.processing : '',
|
||||
className,
|
||||
)}
|
||||
style={style}
|
||||
>
|
||||
<div
|
||||
className={cls(
|
||||
styles.content,
|
||||
'process-progress-item-content',
|
||||
'max-w-[calc(100%-100px)]',
|
||||
)}
|
||||
>
|
||||
<div className={cls('flex items-center', styles.info)}>
|
||||
{avatar}
|
||||
<div className={cls('pl-[10px] max-w-full')}>
|
||||
<div className={styles['main-text']}>
|
||||
<Typography.Text
|
||||
data-dtestid={`${KnowledgeE2e.CreateUnitListProgressName}.${mainText}`}
|
||||
className={'coz-fg-primary text-14px'}
|
||||
ellipsis={{
|
||||
showTooltip: {
|
||||
opts: { content: mainText },
|
||||
},
|
||||
}}
|
||||
>
|
||||
{mainText}
|
||||
</Typography.Text>
|
||||
</div>
|
||||
<div className={styles['sub-text']}>
|
||||
<div className={styles.desc}>{subText}</div>
|
||||
{tipText ? (
|
||||
<div className={styles['tip-desc']}>{tipText}</div>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className={cls(styles.right, 'process-progress-item-right')}>
|
||||
{renderActions()}
|
||||
</div>
|
||||
{renderProgress()}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,164 @@
|
||||
/* stylelint-disable no-descending-specificity */
|
||||
/* stylelint-disable max-nesting-depth */
|
||||
/* stylelint-disable font-family-no-missing-generic-family-keyword */
|
||||
/* stylelint-disable declaration-no-important */
|
||||
.table-preview {
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
|
||||
&-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
height: 32px;
|
||||
margin-bottom: 5px;
|
||||
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
font-style: normal;
|
||||
line-height: 20px;
|
||||
color: var(--coz-fg-plus);
|
||||
}
|
||||
|
||||
// .table-view-wrapper {
|
||||
// border: 1px solid #1D1C231F;
|
||||
// border-radius: 8px;
|
||||
|
||||
// :global {
|
||||
// .semi-table-wrapper {
|
||||
// margin-top: 0;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
.semantic-tag,
|
||||
.column-type {
|
||||
margin-left: 6px;
|
||||
}
|
||||
|
||||
.preview-tips {
|
||||
margin-top: 8px;
|
||||
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
line-height: 20px;
|
||||
color: var(--coz-fg-dim);
|
||||
text-align: left;
|
||||
letter-spacing: 0;
|
||||
}
|
||||
|
||||
.no-result {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
width: 100%;
|
||||
height: 448px;
|
||||
|
||||
&-tips {
|
||||
margin-top: 16px;
|
||||
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
font-style: normal;
|
||||
line-height: 22px;
|
||||
color: var(--coz-fg-plus);
|
||||
}
|
||||
}
|
||||
|
||||
&-content {
|
||||
// flex: 1;
|
||||
overflow: auto;
|
||||
|
||||
:global {
|
||||
th,tr {
|
||||
background-color: transparent !important;
|
||||
}
|
||||
|
||||
.semi-table-wrapper {
|
||||
height: 100%;
|
||||
margin-top: 0;
|
||||
|
||||
.coz-tag {
|
||||
font-weight: 400;
|
||||
}
|
||||
}
|
||||
|
||||
.coz-table-wrapper {
|
||||
.coz-table-list-hover .semi-table-row:hover>.semi-table-row-cell::before {
|
||||
background-color: transparent
|
||||
}
|
||||
|
||||
.coz-table-list-hover .semi-table-row:hover>.semi-table-row-cell:first-child {
|
||||
border-top-left-radius: 0;
|
||||
border-bottom-left-radius: 0;
|
||||
}
|
||||
|
||||
.coz-table-list {
|
||||
.semi-table-thead>.semi-table-row>.semi-table-row-head {
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
color: var(--coz-fg-secondary);
|
||||
}
|
||||
|
||||
.semi-table-tbody>.semi-table-row>.semi-table-row-cell {
|
||||
height: 56px;
|
||||
text-align: unset;
|
||||
|
||||
.semi-typography {
|
||||
color: var(--coz-fg-secondary);
|
||||
}
|
||||
}
|
||||
|
||||
.semi-table-container>.semi-table-body {
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
.semi-table-tbody>.semi-table-row:last-child>.semi-table-row-cell {
|
||||
border-bottom: 1px solid var(--coz-stroke-primary);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.semi-table-header {
|
||||
position: sticky;
|
||||
z-index: 99;
|
||||
overflow-y: hidden !important;
|
||||
// border-top-left-radius: 8px;
|
||||
// border-top-right-radius: 8px;
|
||||
}
|
||||
|
||||
|
||||
.semi-table-body {
|
||||
// max-height: calc(100% - 40px) !important;
|
||||
// max-height: 460px !important;
|
||||
// border-bottom-right-radius: 8px;
|
||||
// border-bottom-left-radius: 8px;
|
||||
}
|
||||
|
||||
.semi-table-colgroup .semi-table-col {
|
||||
min-width: 200px;
|
||||
}
|
||||
|
||||
.semi-table-tbody>.semi-table-row>.semi-table-row-cell {
|
||||
min-height: 40px;
|
||||
padding: 9px 16px !important;
|
||||
}
|
||||
|
||||
/** 去掉hover行样式 */
|
||||
.semi-table-tbody .semi-table-row:hover>.semi-table-row-cell {
|
||||
background-color: transparent !important;
|
||||
background-image: none !important;
|
||||
border-bottom: 1px solid var(--coz-stroke-primary);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.td-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
@@ -0,0 +1,180 @@
|
||||
/*
|
||||
* 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 React, { useMemo } from 'react';
|
||||
|
||||
import { IllustrationNoResult } from '@douyinfe/semi-illustrations';
|
||||
import { getDataTypeText } from '@coze-data/utils';
|
||||
import { KnowledgeE2e } from '@coze-data/e2e';
|
||||
import { ImageRender, type TableViewColumns } from '@coze-common/table-view';
|
||||
import { ColumnType } from '@coze-arch/idl/knowledge';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import { type ColumnProps } from '@coze-arch/bot-semi/Table';
|
||||
import { Table, Tag, Typography } from '@coze-arch/coze-design';
|
||||
|
||||
import { getSrcFromImg } from '@/utils/table';
|
||||
import { type TableInfo, type TableSettings } from '@/types';
|
||||
import { TableSettingFormFields } from '@/constants';
|
||||
|
||||
import styles from './index.module.less';
|
||||
|
||||
export interface TablePreviewProps {
|
||||
data: TableInfo;
|
||||
settings: TableSettings;
|
||||
}
|
||||
|
||||
interface PreviewColumn {
|
||||
[key: string]: string;
|
||||
}
|
||||
|
||||
const ColumnTypeComp = (props: { columnType: ColumnType }) => (
|
||||
<Tag color="primary" className={styles['column-type']} size="mini">
|
||||
{getDataTypeText(props.columnType)}
|
||||
</Tag>
|
||||
);
|
||||
|
||||
const baseClassName = 'table-preview';
|
||||
const maxDataLen = 10;
|
||||
export const TablePreview: React.FC<TablePreviewProps> = ({
|
||||
data,
|
||||
settings,
|
||||
}) => {
|
||||
const { sheet_list = [], table_meta = {}, preview_data = {} } = data;
|
||||
const startRow = Number(settings[TableSettingFormFields.DATA_START_ROW]) || 0;
|
||||
// 选中的表id
|
||||
const sheetId = useMemo(
|
||||
() => settings[TableSettingFormFields.SHEET] || 0,
|
||||
[settings],
|
||||
);
|
||||
// 选中的表名
|
||||
const sheetName = useMemo(
|
||||
() => (sheet_list || []).find(sheet => sheet?.id === sheetId)?.sheet_name,
|
||||
[sheet_list, sheetId],
|
||||
);
|
||||
// 选中的表的数据量
|
||||
const total = useMemo(
|
||||
() =>
|
||||
Number(
|
||||
(sheet_list || []).find(sheet => sheet?.id === sheetId)?.total_row || 0,
|
||||
) - startRow || 0,
|
||||
[sheet_list, sheetId],
|
||||
);
|
||||
const newColumns: ColumnProps<PreviewColumn | TableViewColumns>[] = (
|
||||
table_meta[sheetId] || []
|
||||
).map(meta => {
|
||||
const {
|
||||
sequence,
|
||||
column_name,
|
||||
is_semantic,
|
||||
column_type = ColumnType.Unknown,
|
||||
} = meta;
|
||||
if (column_type === ColumnType.Image) {
|
||||
return {
|
||||
title: (
|
||||
<div className={styles['td-title']}>
|
||||
<div>{column_name}</div>
|
||||
<ColumnTypeComp columnType={column_type}></ColumnTypeComp>
|
||||
</div>
|
||||
),
|
||||
dataIndex: sequence,
|
||||
render: (text, _record) => {
|
||||
const srcList = getSrcFromImg(text);
|
||||
return <ImageRender srcList={srcList} editable={false} />;
|
||||
},
|
||||
};
|
||||
}
|
||||
return {
|
||||
title: is_semantic ? (
|
||||
<div className={styles['td-title']}>
|
||||
{column_name}
|
||||
{is_semantic ? (
|
||||
<Tag
|
||||
size="mini"
|
||||
color="green"
|
||||
className={styles['semantic-tag']}
|
||||
data-testid={KnowledgeE2e.TableLocalPreviewSemantic}
|
||||
>
|
||||
{I18n.t('knowledge_1226_001')}
|
||||
</Tag>
|
||||
) : null}
|
||||
<ColumnTypeComp columnType={column_type}></ColumnTypeComp>
|
||||
</div>
|
||||
) : (
|
||||
<div className={styles['td-title']}>
|
||||
{column_name}
|
||||
<ColumnTypeComp columnType={column_type}></ColumnTypeComp>
|
||||
</div>
|
||||
),
|
||||
width: 180,
|
||||
dataIndex: sequence,
|
||||
ellipsis: { showTitle: false },
|
||||
render: text => (
|
||||
<Typography.Text ellipsis={{ showTooltip: true }}>
|
||||
{text}
|
||||
</Typography.Text>
|
||||
),
|
||||
};
|
||||
});
|
||||
const dataList = useMemo(() => {
|
||||
const previewData = preview_data[sheetId] || [];
|
||||
return previewData
|
||||
.slice(0, maxDataLen)
|
||||
.sort((a, b) =>
|
||||
(JSON.stringify(a) as unknown as number) >
|
||||
(JSON.stringify(b) as unknown as number)
|
||||
? 1
|
||||
: -1,
|
||||
);
|
||||
}, [preview_data, sheetId]);
|
||||
return (
|
||||
<div className={styles[baseClassName]}>
|
||||
{dataList.length ? (
|
||||
<>
|
||||
<div
|
||||
className={styles[`${baseClassName}-title`]}
|
||||
data-testid={KnowledgeE2e.TableLocalPreviewTitle}
|
||||
>
|
||||
{sheetName}
|
||||
</div>
|
||||
<div className={styles[`${baseClassName}-content`]}>
|
||||
<Table
|
||||
tableProps={{
|
||||
dataSource: dataList,
|
||||
columns: newColumns,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
className={styles['preview-tips']}
|
||||
data-testid={KnowledgeE2e.TableLocalPreviewFooterTotal}
|
||||
>
|
||||
{I18n.t('datasets_unit_tableformat_tips1', {
|
||||
TotalRows: total,
|
||||
ShowRows: Number(total) > maxDataLen ? maxDataLen : total,
|
||||
})}
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<div className={styles['no-result']}>
|
||||
<IllustrationNoResult></IllustrationNoResult>
|
||||
<div className={styles['no-result-tips']}>
|
||||
{I18n.t('knowledge_1221_02')}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,37 @@
|
||||
/* stylelint-disable font-family-no-missing-generic-family-keyword */
|
||||
.table-setting-bar {
|
||||
width: 100%;
|
||||
margin-bottom: 30px;
|
||||
|
||||
:global {
|
||||
.semi-form-horizontal .semi-form-field {
|
||||
flex: 1;
|
||||
|
||||
.semi-select {
|
||||
width: 100%;
|
||||
border-radius: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.semi-form-field-label-text {
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
font-style: normal;
|
||||
line-height: 24px;
|
||||
color: var(--coz-fg-plus);
|
||||
}
|
||||
|
||||
.semi-form-field-label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 24px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.semi-form-horizontal .semi-form-field:last-child {
|
||||
margin-right: 0;
|
||||
padding-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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 React, { useMemo, useRef } from 'react';
|
||||
|
||||
import { get, isNumber } from 'lodash-es';
|
||||
import classNames from 'classnames';
|
||||
import { KnowledgeE2e } from '@coze-data/e2e';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import { type FormApi } from '@coze-arch/bot-semi/Form';
|
||||
import { Form } from '@coze-arch/bot-semi';
|
||||
import { type GetDocumentTableInfoResponse } from '@coze-arch/bot-api/memory';
|
||||
import { FormSelect } from '@coze-arch/coze-design';
|
||||
|
||||
import { type TableSettings } from '@/types';
|
||||
import { TableSettingFormFields } from '@/constants';
|
||||
|
||||
import { initIndexOptions } from './utils';
|
||||
|
||||
import styles from './index.module.less';
|
||||
|
||||
export interface TableSettingBarProps {
|
||||
className?: string;
|
||||
data: GetDocumentTableInfoResponse;
|
||||
tableSettings: TableSettings;
|
||||
setTableSettings: (values: TableSettings) => void;
|
||||
}
|
||||
|
||||
const minOptLen = 2;
|
||||
export const TableSettingBar: React.FC<TableSettingBarProps> = ({
|
||||
className = '',
|
||||
data = {},
|
||||
tableSettings,
|
||||
setTableSettings,
|
||||
}) => {
|
||||
const { preview_data, sheet_list } = data;
|
||||
if (!preview_data || !sheet_list || !sheet_list.length) {
|
||||
return <></>;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line react-hooks/rules-of-hooks -- linter-disable-autofix
|
||||
const formApi = useRef<FormApi<TableSettings>>();
|
||||
// eslint-disable-next-line react-hooks/rules-of-hooks -- linter-disable-autofix
|
||||
const sheet = useMemo(
|
||||
() => get(sheet_list, tableSettings[TableSettingFormFields.SHEET]),
|
||||
[sheet_list, tableSettings],
|
||||
);
|
||||
// eslint-disable-next-line react-hooks/rules-of-hooks -- linter-disable-autofix
|
||||
const initValues = useMemo(() => tableSettings, [sheet_list]);
|
||||
|
||||
// eslint-disable-next-line react-hooks/rules-of-hooks -- linter-disable-autofix
|
||||
const settings = useMemo(() => {
|
||||
const options =
|
||||
!sheet.id && sheet.id !== 0
|
||||
? []
|
||||
: initIndexOptions(
|
||||
Number(sheet?.total_row) > 1 ? Number(sheet.total_row) : minOptLen,
|
||||
0,
|
||||
);
|
||||
return [
|
||||
{
|
||||
e2e: KnowledgeE2e.TableLocalTableConfigurationDataSheet,
|
||||
field: TableSettingFormFields.SHEET,
|
||||
label: I18n.t('datasets_createFileModel_tab_DataSheet'),
|
||||
options: sheet_list.map(s => ({
|
||||
value: s.id,
|
||||
label: s.sheet_name,
|
||||
})),
|
||||
},
|
||||
{
|
||||
e2e: KnowledgeE2e.TableLocalTableConfigurationSheetHeader,
|
||||
field: TableSettingFormFields.KEY_START_ROW,
|
||||
label: I18n.t('datasets_createFileModel_tab_header'),
|
||||
options: options.slice(0, options.length - 1),
|
||||
},
|
||||
{
|
||||
e2e: KnowledgeE2e.TableLocalTableConfigurationStarRow,
|
||||
field: TableSettingFormFields.DATA_START_ROW,
|
||||
label: I18n.t('datasets_createFileModel_tab_dataStarRow'),
|
||||
// 数据起始行需大于表头行
|
||||
options: options.slice(
|
||||
Number(tableSettings[TableSettingFormFields.KEY_START_ROW]) + 1,
|
||||
),
|
||||
},
|
||||
];
|
||||
}, [data, sheet]);
|
||||
|
||||
const handleFormChange = (
|
||||
values: TableSettings,
|
||||
changedValue: Partial<TableSettings>,
|
||||
) => {
|
||||
if (setTableSettings) {
|
||||
setTableSettings({ ...values });
|
||||
}
|
||||
|
||||
const curSheet = get(changedValue, TableSettingFormFields.SHEET);
|
||||
const curKeyStartRow = get(
|
||||
changedValue,
|
||||
TableSettingFormFields.KEY_START_ROW,
|
||||
);
|
||||
if (isNumber(curSheet) && formApi.current) {
|
||||
// 修改sheet,初始化表头行和数据行
|
||||
formApi.current.setValue(TableSettingFormFields.KEY_START_ROW, 0);
|
||||
formApi.current.setValue(TableSettingFormFields.DATA_START_ROW, 1);
|
||||
}
|
||||
if (curKeyStartRow && formApi.current) {
|
||||
const dataStartRow = get(values, TableSettingFormFields.DATA_START_ROW);
|
||||
if (!(curKeyStartRow < dataStartRow)) {
|
||||
formApi.current.setValue(
|
||||
TableSettingFormFields.DATA_START_ROW,
|
||||
curKeyStartRow + 1,
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={classNames(styles['table-setting-bar'], className)}>
|
||||
<Form<typeof initValues>
|
||||
layout="horizontal"
|
||||
initValues={initValues}
|
||||
getFormApi={api => (formApi.current = api)}
|
||||
onValueChange={(values, changedValue) => {
|
||||
handleFormChange(values, changedValue);
|
||||
}}
|
||||
>
|
||||
{settings.map(setting => {
|
||||
const { options, ...selectProps } = setting;
|
||||
return (
|
||||
<FormSelect
|
||||
data-testid={setting.e2e}
|
||||
key={setting.field}
|
||||
optionList={options}
|
||||
{...selectProps}
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
onChange={(v?: string | number | any[] | Record<string, any>) => {
|
||||
if (!v) {
|
||||
return;
|
||||
}
|
||||
handleFormChange(
|
||||
{ ...tableSettings, [setting.field]: v as unknown as number },
|
||||
{ [setting.field]: v as unknown as number },
|
||||
);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</Form>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -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 { I18n } from '@coze-arch/i18n';
|
||||
|
||||
export const initIndexOptions = (length: number, start: number) => {
|
||||
const MAX_VALUE = 50;
|
||||
const limit = length > MAX_VALUE ? MAX_VALUE : length;
|
||||
const res: Array<{
|
||||
label: string;
|
||||
value: number;
|
||||
}> = [];
|
||||
for (let i = start; i < limit; i++) {
|
||||
res.push({
|
||||
label: I18n.t('datasets_createFileModel_tab_dataStarRow_value', {
|
||||
LineNumber: i + 1,
|
||||
}),
|
||||
value: i,
|
||||
});
|
||||
}
|
||||
return res;
|
||||
};
|
||||
@@ -0,0 +1,234 @@
|
||||
/* stylelint-disable no-descending-specificity */
|
||||
/* stylelint-disable no-duplicate-selectors */
|
||||
/* stylelint-disable declaration-no-important */
|
||||
/* stylelint-disable max-nesting-depth */
|
||||
.table-structure-wrapper {
|
||||
overflow: hidden;
|
||||
flex: 1;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.structure-wrapper {
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
}
|
||||
|
||||
.drag-table {
|
||||
:global {
|
||||
.semi-table-container {
|
||||
.semi-table-tbody {
|
||||
.semi-table-row {
|
||||
.semi-table-row-cell {
|
||||
&:first-child {
|
||||
padding-left: 16px !important;
|
||||
}
|
||||
}
|
||||
|
||||
/** 暂时注释,后续还要用,待讨论 */
|
||||
// &:hover {
|
||||
// background: var(--coz-mg-secondary-hovered) !important;
|
||||
|
||||
// .semi-table-row-cell:first-child {
|
||||
// border-top-left-radius: 8px !important;
|
||||
// border-bottom-left-radius: 8px !important;
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
.table-structure {
|
||||
overflow: hidden;
|
||||
margin-top: 4px !important;
|
||||
border-radius: 8px;
|
||||
|
||||
:global {
|
||||
.semi-spin, .semi-spin-children, .semi-table-fixed-header,.semi-table-container {
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
&-required-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
&-col-required {
|
||||
margin-top: 4px;
|
||||
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
font-style: normal;
|
||||
line-height: 16px;
|
||||
color: var(--coz-fg-hglt-red);
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.input-suffix {
|
||||
display: inline-block;
|
||||
margin-right: 5px;
|
||||
font-size: 12px;
|
||||
// color: rgb(28 29 35 / 35%);
|
||||
}
|
||||
|
||||
.input-error-msg {
|
||||
position: relative;
|
||||
z-index: 100;
|
||||
|
||||
margin-top: 4px;
|
||||
margin-bottom: -20px;
|
||||
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
font-style: normal;
|
||||
line-height: 16px;
|
||||
color: var(--coz-fg-hglt-red);
|
||||
}
|
||||
|
||||
.semantic-radio {
|
||||
position: relative;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
height: 100%;
|
||||
// padding-top: 3px;
|
||||
padding-left: 2px;
|
||||
}
|
||||
|
||||
.column-item-action {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
height: 100%;
|
||||
padding-top: 3px;
|
||||
padding-left: 7px;
|
||||
|
||||
&-delete {
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
.column-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.column-item-value {
|
||||
font-size: 14px;
|
||||
line-height: 32px;
|
||||
color: var(--coz-fg-secondary);
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
:global {
|
||||
.structure-table-drag-icon {
|
||||
position: absolute;
|
||||
left: -16px;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.semi-table-row {
|
||||
&:hover,
|
||||
&:focus {
|
||||
.structure-table-drag-icon {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.semi-table-thead>.semi-table-row>.semi-table-row-head {
|
||||
font-size: 12px !important;
|
||||
color: var(--coz-fg-secondary) !important;
|
||||
}
|
||||
|
||||
.semi-table-container {
|
||||
.semi-table-body {
|
||||
height: calc(100% - 39px) !important;
|
||||
padding-bottom: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.select-error-text {
|
||||
padding-top: 0 !important;
|
||||
}
|
||||
|
||||
.singleline-select-error-content {
|
||||
height: 0;
|
||||
}
|
||||
|
||||
.semi-table-thead>.semi-table-row>.semi-table-row-head {
|
||||
&:first-child {
|
||||
padding-left: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
/** table去掉背景色 */
|
||||
.semi-table-thead>.semi-table-row>.semi-table-row-head, .semi-table-tbody>.semi-table-row, .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 {
|
||||
background-color: transparent !important;
|
||||
}
|
||||
|
||||
.semi-table-tbody {
|
||||
padding: 5px 0;
|
||||
|
||||
.semi-table-row {
|
||||
.semi-table-row-cell {
|
||||
height: 56px !important;
|
||||
padding: 12px 8px !important;
|
||||
border-bottom: 0;
|
||||
|
||||
// 此处不需要 UITable 默认的 border-radius
|
||||
&:first-child {
|
||||
padding-right: 28px !important;
|
||||
padding-left: 8px !important;
|
||||
border-radius: 0 !important;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
&:hover {
|
||||
cursor: auto;
|
||||
background: var(--coz-mg-secondary-hovered);
|
||||
|
||||
&>.semi-table-row-cell {
|
||||
background: transparent !important;
|
||||
border-bottom: 0 !important;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
.table-header-tooltip {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.table-structure-bar-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
height: 32px;
|
||||
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
font-style: normal;
|
||||
color: var(--coz-fg-plus);
|
||||
|
||||
.icon {
|
||||
margin-top: 3px;
|
||||
margin-left: 4px;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,630 @@
|
||||
/*
|
||||
* 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-lines */
|
||||
/* eslint-disable max-lines-per-function */
|
||||
import React, {
|
||||
useCallback,
|
||||
useMemo,
|
||||
useState,
|
||||
type FC,
|
||||
type CSSProperties,
|
||||
} from 'react';
|
||||
|
||||
import classNames from 'classnames';
|
||||
import { CSS as cssDndKit } from '@dnd-kit/utilities';
|
||||
import {
|
||||
SortableContext,
|
||||
arrayMove,
|
||||
useSortable,
|
||||
verticalListSortingStrategy,
|
||||
} from '@dnd-kit/sortable';
|
||||
import { restrictToVerticalAxis } from '@dnd-kit/modifiers';
|
||||
import {
|
||||
DndContext,
|
||||
PointerSensor,
|
||||
useSensors,
|
||||
useSensor,
|
||||
type DragEndEvent,
|
||||
} from '@dnd-kit/core';
|
||||
import {
|
||||
DataTypeSelect,
|
||||
getDataTypeOptions,
|
||||
getDataTypeText,
|
||||
} from '@coze-data/utils';
|
||||
import { OptType } from '@coze-data/knowledge-resource-processor-core';
|
||||
import { KnowledgeE2e } from '@coze-data/e2e';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import {
|
||||
IconCozInfoCircle,
|
||||
IconCozTrashCan,
|
||||
} from '@coze-arch/coze-design/icons';
|
||||
import {
|
||||
Input,
|
||||
Table,
|
||||
Tooltip,
|
||||
Checkbox,
|
||||
type CheckboxProps,
|
||||
} from '@coze-arch/coze-design';
|
||||
import { type ColumnProps, type TableProps } from '@coze-arch/bot-semi/Table';
|
||||
import { UIButton, Typography } from '@coze-arch/bot-semi';
|
||||
import { IconDragOutlined } from '@coze-arch/bot-icons';
|
||||
import { type DocTableColumn } from '@coze-arch/bot-api/memory';
|
||||
import { ColumnType } from '@coze-arch/bot-api/knowledge';
|
||||
|
||||
import { type IValidateRes, validateField, useOptFromQuery } from '@/utils';
|
||||
import { type TableItem } from '@/types/table';
|
||||
import { type SemanticValidateItem } from '@/types';
|
||||
|
||||
import styles from './index.module.less';
|
||||
|
||||
type Align = 'center' | 'left' | 'right' | undefined;
|
||||
enum ValidateStatus {
|
||||
Error = 'error',
|
||||
Default = 'default',
|
||||
}
|
||||
|
||||
export interface TableStructureProps extends TableProps {
|
||||
data: Array<
|
||||
DocTableColumn & {
|
||||
key?: string;
|
||||
autofocus?: boolean;
|
||||
errMsg?: string;
|
||||
}
|
||||
>;
|
||||
setData: (v: Array<DocTableColumn>) => void;
|
||||
initValid?: boolean;
|
||||
isBlurValid?: boolean;
|
||||
isPreview?: boolean;
|
||||
verifyMap?: SemanticValidateItem;
|
||||
baseKey?: string;
|
||||
showTitle?: boolean;
|
||||
tipsNode?: React.ReactNode;
|
||||
isDragTable?: boolean;
|
||||
}
|
||||
const NAME_MAX_STR_LEN = 30;
|
||||
const DESC_MAX_STR_LEN = 2000;
|
||||
const baseClassName = 'table-structure';
|
||||
const RequiredColRender = ({
|
||||
children,
|
||||
tooltip,
|
||||
dataTestId,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
tooltip?: string | React.ReactNode;
|
||||
dataTestId?: string;
|
||||
}) => (
|
||||
<div
|
||||
className={styles[`${baseClassName}-required-container`]}
|
||||
data-testid={dataTestId}
|
||||
>
|
||||
{children}
|
||||
<span className={styles[`${baseClassName}-col-required`]}> *</span>
|
||||
{tooltip}
|
||||
</div>
|
||||
);
|
||||
|
||||
interface InputRenderProps {
|
||||
onChange: (v: string) => void;
|
||||
validate?: (v: string, error: string) => IValidateRes;
|
||||
record: TableItem & { errMsg?: string };
|
||||
value: string;
|
||||
autofocus: boolean;
|
||||
initValid: boolean;
|
||||
isBlurValid: boolean;
|
||||
errorMsg?: string;
|
||||
isPreview?: boolean;
|
||||
placeholder?: string;
|
||||
maxStrLen: number;
|
||||
}
|
||||
const InputRender = ({
|
||||
onChange,
|
||||
record,
|
||||
value,
|
||||
autofocus = false,
|
||||
isBlurValid = false,
|
||||
initValid,
|
||||
validate,
|
||||
isPreview,
|
||||
placeholder,
|
||||
maxStrLen,
|
||||
}: InputRenderProps) => {
|
||||
const ValidateResult = (v: string) => {
|
||||
const validRes = validate?.(
|
||||
v,
|
||||
I18n.t('datasets_segment_tableStructure_field_errEmpty'),
|
||||
);
|
||||
return {
|
||||
valid: initValid ? !!(validate ? validRes?.valid : v && v !== '') : true,
|
||||
errorMsg:
|
||||
validRes?.errorMsg ||
|
||||
I18n.t('datasets_segment_tableStructure_field_errEmpty'),
|
||||
};
|
||||
};
|
||||
|
||||
const [inputValue, setInputValue] = useState(value);
|
||||
const [validObj, setValidObj] = useState(() => {
|
||||
const res = ValidateResult(value);
|
||||
return {
|
||||
valid: isBlurValid ? true : res.valid,
|
||||
errorMsg: res.errorMsg,
|
||||
};
|
||||
});
|
||||
|
||||
const validateValue = (v: string) => {
|
||||
const validRes = ValidateResult(v);
|
||||
setValidObj(validRes);
|
||||
};
|
||||
|
||||
const hasDisable = isPreview;
|
||||
const apiErrorMsg = record?.errMsg || '';
|
||||
|
||||
const validateStatus = useMemo(() => {
|
||||
if (apiErrorMsg) {
|
||||
return ValidateStatus.Error;
|
||||
}
|
||||
return !validObj.valid ? ValidateStatus.Error : ValidateStatus.Default;
|
||||
}, [validObj, apiErrorMsg]);
|
||||
|
||||
const renderErrorMsg = useCallback(() => {
|
||||
if (apiErrorMsg) {
|
||||
return <div className={styles['input-error-msg']}>{apiErrorMsg}</div>;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{!validObj.valid && (
|
||||
<div className={styles['input-error-msg']}>{validObj.errorMsg}</div>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}, [apiErrorMsg, validObj]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Input
|
||||
autoFocus={autofocus}
|
||||
value={inputValue}
|
||||
maxLength={maxStrLen}
|
||||
onChange={v => {
|
||||
setInputValue(v.substring(0, maxStrLen));
|
||||
!isBlurValid && validateValue(v);
|
||||
}}
|
||||
disabled={hasDisable}
|
||||
validateStatus={validateStatus}
|
||||
suffix={
|
||||
<span className={styles['input-suffix']}>
|
||||
{(inputValue || '').length}/{maxStrLen}
|
||||
</span>
|
||||
}
|
||||
onBlur={() => {
|
||||
onChange(inputValue?.substring(0, maxStrLen) || '');
|
||||
validateValue(inputValue);
|
||||
}}
|
||||
placeholder={placeholder}
|
||||
/>
|
||||
{renderErrorMsg()}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
// TODO 待解
|
||||
// eslint-disable-next-line @coze-arch/max-line-per-function
|
||||
export const TableStructure: React.FC<TableStructureProps> = ({
|
||||
data = [],
|
||||
setData,
|
||||
verifyMap = {},
|
||||
initValid = false,
|
||||
isBlurValid = false,
|
||||
isPreview = false,
|
||||
baseKey,
|
||||
showTitle = false,
|
||||
children: childrenNode,
|
||||
tipsNode,
|
||||
isDragTable = false,
|
||||
...tableProps
|
||||
}) => {
|
||||
const opt = useOptFromQuery();
|
||||
const isResegment = opt === OptType.RESEGMENT;
|
||||
|
||||
const columns: ColumnProps<TableItem>[] = [
|
||||
{
|
||||
title: () => (
|
||||
<RequiredColRender
|
||||
dataTestId={KnowledgeE2e.TableLocalTableConfigurationIndex}
|
||||
tooltip={
|
||||
<Tooltip
|
||||
className="whitespace-pre-line"
|
||||
content={I18n.t('knowledge_multi_index')}
|
||||
>
|
||||
<UIButton
|
||||
size="small"
|
||||
theme="borderless"
|
||||
type="tertiary"
|
||||
style={{
|
||||
marginLeft: 4,
|
||||
}}
|
||||
icon={<IconCozInfoCircle className="coz-fg-secondary" />}
|
||||
/>
|
||||
</Tooltip>
|
||||
}
|
||||
>
|
||||
<div
|
||||
className={styles['table-header-tooltip']}
|
||||
data-testid={KnowledgeE2e.TableLocalTableConfigurationIndex}
|
||||
>
|
||||
<span>{I18n.t('knowledge_table_structure_semantic')}</span>
|
||||
</div>
|
||||
</RequiredColRender>
|
||||
),
|
||||
dataIndex: 'is_semantic',
|
||||
width: 90,
|
||||
align: 'left' as Align,
|
||||
render: (value, record, index: number) => {
|
||||
const onChange: CheckboxProps['onChange'] = e => {
|
||||
const newData = [...data];
|
||||
newData[index].is_semantic = Boolean(e.target.checked);
|
||||
setData(newData);
|
||||
};
|
||||
const { sequence } = record;
|
||||
function hasFormItemDisable() {
|
||||
const disabled = Object.keys(verifyMap).length
|
||||
? !verifyMap[sequence || index]?.valid
|
||||
: false;
|
||||
return disabled || isPreview;
|
||||
}
|
||||
const hasDisable = hasFormItemDisable();
|
||||
|
||||
const Wrapper = ({ children }: { children: JSX.Element }) => {
|
||||
if (hasDisable && verifyMap[sequence || index]?.msg) {
|
||||
return (
|
||||
<Tooltip
|
||||
trigger="hover"
|
||||
content={verifyMap[sequence || index]?.msg}
|
||||
>
|
||||
{children}
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
return children;
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={styles['semantic-radio']}>
|
||||
{isDragTable ? (
|
||||
<IconDragOutlined className={'structure-table-drag-icon'} />
|
||||
) : null}
|
||||
<Wrapper>
|
||||
<Checkbox
|
||||
checked={value}
|
||||
disabled={hasDisable}
|
||||
onChange={onChange}
|
||||
data-testid={KnowledgeE2e.TableStructureIndexCheckbox}
|
||||
/>
|
||||
</Wrapper>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: () => (
|
||||
<RequiredColRender
|
||||
dataTestId={KnowledgeE2e.TableLocalTableConfigurationColumnName}
|
||||
>
|
||||
{I18n.t('knowledge_table_structure_column_name')}
|
||||
</RequiredColRender>
|
||||
),
|
||||
dataIndex: 'column_name',
|
||||
align: 'left' as Align,
|
||||
render: (value, record, index) => {
|
||||
const { autofocus = false } = record;
|
||||
const onChange = (v: string) => {
|
||||
const newData = [...data];
|
||||
newData[index].column_name = v;
|
||||
setData(newData);
|
||||
};
|
||||
|
||||
const validateFn = (v: string, emptyMsg: string) => {
|
||||
if (data?.filter(i => i.column_name === v).length >= 2) {
|
||||
return {
|
||||
valid: false,
|
||||
errorMsg: I18n.t('Manual_crawling_040'),
|
||||
};
|
||||
}
|
||||
return validateField(v, emptyMsg);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={styles['column-item']}>
|
||||
<InputRender
|
||||
initValid={initValid}
|
||||
isBlurValid={isBlurValid}
|
||||
key={`${baseKey}${record?.sequence}`}
|
||||
onChange={onChange}
|
||||
record={record}
|
||||
value={value}
|
||||
validate={validateFn}
|
||||
autofocus={autofocus}
|
||||
isPreview={isPreview}
|
||||
maxStrLen={NAME_MAX_STR_LEN}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: () => (
|
||||
<div data-testid={KnowledgeE2e.TableLocalTableConfigurationDesc}>
|
||||
{I18n.t('knowledge_table_structure_desc')}
|
||||
</div>
|
||||
),
|
||||
dataIndex: 'desc',
|
||||
align: 'left' as Align,
|
||||
render: (value, record, index) => {
|
||||
const onChange = (v: string) => {
|
||||
const newData = [...data];
|
||||
newData[index].desc = v;
|
||||
setData(newData);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={styles['column-item']}>
|
||||
<InputRender
|
||||
initValid={false}
|
||||
isBlurValid={false}
|
||||
key={`column-desc.${baseKey}${record?.sequence}`}
|
||||
placeholder={I18n.t('knowledge_variable_description_placeholder')}
|
||||
onChange={onChange}
|
||||
record={record}
|
||||
value={value}
|
||||
autofocus={false}
|
||||
isPreview={isPreview}
|
||||
maxStrLen={DESC_MAX_STR_LEN}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: () => (
|
||||
<RequiredColRender
|
||||
dataTestId={KnowledgeE2e.TableLocalTableConfigurationType}
|
||||
>
|
||||
{I18n.t('knowledge_table_structure_data_type')}
|
||||
</RequiredColRender>
|
||||
),
|
||||
dataIndex: 'column_type',
|
||||
align: 'left' as Align,
|
||||
render: (value, record, index) => {
|
||||
const valid = isBlurValid ? true : !!value;
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`pr-[16px] ${styles['column-item']}`}
|
||||
key={record.sequence}
|
||||
>
|
||||
{isPreview ? (
|
||||
<Typography.Text className={styles['column-item-value']}>
|
||||
{getDataTypeText(value)}
|
||||
</Typography.Text>
|
||||
) : (
|
||||
<DataTypeSelect
|
||||
value={value || ''}
|
||||
selectProps={{
|
||||
disabled: !record.is_new_column && isResegment,
|
||||
optionList: getDataTypeOptions().map(option => {
|
||||
if (option.value === ColumnType.Image) {
|
||||
return {
|
||||
...option,
|
||||
disabled: record.is_semantic,
|
||||
};
|
||||
}
|
||||
return option;
|
||||
}),
|
||||
placeholder: I18n.t('db_table_save_exception_fieldtype'),
|
||||
}}
|
||||
errorMsg={
|
||||
valid
|
||||
? undefined
|
||||
: I18n.t(
|
||||
'datasets_segment_tableStructure_field_type_errEmpty',
|
||||
)
|
||||
}
|
||||
handleChange={v => {
|
||||
const newData = [...data];
|
||||
newData[index].column_type = v as ColumnType;
|
||||
setData(newData);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: (
|
||||
<div data-testid={KnowledgeE2e.TableLocalTableConfigurationAction}>
|
||||
{I18n.t('datasets_unit_upload_field_action')}
|
||||
</div>
|
||||
),
|
||||
dataIndex: 'operate',
|
||||
width: 82,
|
||||
align: 'left' as Align,
|
||||
render: (_text, record, index) => (
|
||||
<div
|
||||
className={styles['column-item-action']}
|
||||
onClick={() => {
|
||||
setData(data.filter((_, i) => index !== i));
|
||||
}}
|
||||
>
|
||||
<Tooltip
|
||||
content={I18n.t(
|
||||
record.is_semantic
|
||||
? 'datasets_segment_tableStructure_delTips'
|
||||
: 'datasets_table_title_actions_delete',
|
||||
)}
|
||||
>
|
||||
<IconCozTrashCan
|
||||
aria-disabled={Boolean(record.is_semantic)}
|
||||
className={styles['column-item-action-delete']}
|
||||
/>
|
||||
</Tooltip>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
// 预览场景下,不需要操作列
|
||||
if (isPreview) {
|
||||
columns.pop();
|
||||
}
|
||||
|
||||
const sensors = useSensors(
|
||||
useSensor(PointerSensor, {
|
||||
activationConstraint: { distance: 1 },
|
||||
}),
|
||||
);
|
||||
|
||||
const handleDragEnd = (event: DragEndEvent) => {
|
||||
const { active, over } = event;
|
||||
if (active && over && active.id !== over.id) {
|
||||
const items = Array.from(data);
|
||||
const activeIndex = items.findIndex(item => item.key === active.id);
|
||||
const overIndex = items.findIndex(item => item.key === over.id);
|
||||
setData(arrayMove(items, activeIndex, overIndex));
|
||||
}
|
||||
};
|
||||
|
||||
const SortableRow: FC<{
|
||||
className: string;
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
'data-row-key': string;
|
||||
style: CSSProperties;
|
||||
}> = props => {
|
||||
const {
|
||||
attributes,
|
||||
listeners,
|
||||
setNodeRef,
|
||||
transform,
|
||||
transition,
|
||||
isDragging,
|
||||
} = useSortable({
|
||||
id: props['data-row-key'],
|
||||
});
|
||||
const style: CSSProperties = {
|
||||
...props.style,
|
||||
transform: cssDndKit.Transform.toString(transform),
|
||||
transition,
|
||||
cursor: isDragging ? 'grabbing' : 'grab',
|
||||
...(isDragging
|
||||
? {
|
||||
zIndex: 999,
|
||||
position: 'relative',
|
||||
background: 'rgba(217, 220, 250, 1)',
|
||||
}
|
||||
: {}),
|
||||
};
|
||||
|
||||
return (
|
||||
<tr
|
||||
{...props}
|
||||
ref={setNodeRef}
|
||||
style={style}
|
||||
{...attributes}
|
||||
{...listeners}
|
||||
></tr>
|
||||
);
|
||||
};
|
||||
|
||||
const renderTableContent = () => {
|
||||
if (isDragTable) {
|
||||
return (
|
||||
<DndContext
|
||||
// https://docs.dndkit.com/api-documentation/context-provider#autoscroll
|
||||
autoScroll={true}
|
||||
sensors={sensors}
|
||||
modifiers={[restrictToVerticalAxis]}
|
||||
onDragEnd={handleDragEnd}
|
||||
>
|
||||
<SortableContext
|
||||
items={data.map(item => item.key || '')}
|
||||
strategy={verticalListSortingStrategy}
|
||||
>
|
||||
<Table
|
||||
wrapperClassName={classNames(
|
||||
styles[`${baseClassName}-wrapper`],
|
||||
styles['drag-table'],
|
||||
)}
|
||||
key={baseKey}
|
||||
tableProps={{
|
||||
sticky: true,
|
||||
dataSource: data,
|
||||
columns,
|
||||
pagination: false,
|
||||
className: styles[baseClassName],
|
||||
components: {
|
||||
body: {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
row: SortableRow as any,
|
||||
},
|
||||
},
|
||||
...tableProps,
|
||||
}}
|
||||
/>
|
||||
</SortableContext>
|
||||
</DndContext>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Table
|
||||
wrapperClassName={styles[`${baseClassName}-wrapper`]}
|
||||
key={baseKey}
|
||||
tableProps={{
|
||||
sticky: true,
|
||||
dataSource: data,
|
||||
columns,
|
||||
pagination: false,
|
||||
className: styles[baseClassName],
|
||||
...tableProps,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={styles['structure-wrapper']}>
|
||||
{showTitle ? <TableStructureTitle /> : null}
|
||||
{tipsNode ? tipsNode : null}
|
||||
{renderTableContent()}
|
||||
{childrenNode}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const TableStructureTitle = () => (
|
||||
<div
|
||||
className={styles['table-structure-bar-title']}
|
||||
data-testid={KnowledgeE2e.TableLocalTableStructureTitle}
|
||||
>
|
||||
<span>{I18n.t('datasets_segment_tableStructure_title')}</span>
|
||||
<Tooltip content={I18n.t('knowledge_table_structure_column_tooltip')}>
|
||||
<IconCozInfoCircle
|
||||
className={classNames(styles.icon, 'coz-fg-secondary')}
|
||||
/>
|
||||
</Tooltip>
|
||||
</div>
|
||||
);
|
||||
@@ -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 {
|
||||
TableSettingBar,
|
||||
type TableSettingBarProps,
|
||||
} from './components/table-setting-bar';
|
||||
export {
|
||||
type TablePreviewProps,
|
||||
TablePreview,
|
||||
} from './components/table-preview';
|
||||
export {
|
||||
type TableStructureProps,
|
||||
TableStructure,
|
||||
TableStructureTitle,
|
||||
} from './components/table-structure';
|
||||
@@ -0,0 +1,58 @@
|
||||
@import '../../assets/common.less';
|
||||
|
||||
.embed-progress {
|
||||
flex: 1;
|
||||
|
||||
.progress-info {
|
||||
width: 100%;
|
||||
|
||||
.text {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
height: 32px;
|
||||
margin-bottom: 8px;
|
||||
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
font-style: normal;
|
||||
line-height: 20px;
|
||||
color: var(--coz-fg-primary);
|
||||
}
|
||||
|
||||
.progress-list {
|
||||
overflow-y: auto;
|
||||
max-height: 532px;
|
||||
}
|
||||
}
|
||||
|
||||
.banner {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.progress-success-icon {
|
||||
.common-svg-icon(16px, var(--semi-color-primary));
|
||||
}
|
||||
}
|
||||
|
||||
.data-processing {
|
||||
.finish-text {
|
||||
overflow: hidden;
|
||||
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
font-style: normal;
|
||||
line-height: 20px; /* 142.857% */
|
||||
color: var(--coz-fg-primary);
|
||||
text-align: right;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
:global {
|
||||
.process-progress-item-actions {
|
||||
/* stylelint-disable-next-line declaration-no-important */
|
||||
display: block !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 { UnitProgress } from './unit-progress';
|
||||
@@ -0,0 +1,227 @@
|
||||
/*
|
||||
* 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 { getFormatTypeFromUnitType } from '@coze-data/utils';
|
||||
import { useKnowledgeParams } from '@coze-data/knowledge-stores';
|
||||
import {
|
||||
type ProgressItem,
|
||||
CreateUnitStatus,
|
||||
UnitType,
|
||||
} from '@coze-data/knowledge-resource-processor-core';
|
||||
import { KnowledgeE2e } from '@coze-data/e2e';
|
||||
import { DocumentStatus } from '@coze-arch/idl/knowledge';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import { formatBytes } from '@coze-arch/bot-utils';
|
||||
|
||||
import { getTypeIcon } from '../upload-unit-table/utils';
|
||||
import { ProcessProgressItem } from '../process-progress-item';
|
||||
import { getFrequencyMap } from '../../utils';
|
||||
import { ProcessStatus } from '../../types';
|
||||
|
||||
const INIT_PERCENT = 10;
|
||||
|
||||
import styles from './index.module.less';
|
||||
|
||||
interface UnitProgressProps {
|
||||
progressList: ProgressItem[];
|
||||
createStatus: CreateUnitStatus;
|
||||
}
|
||||
|
||||
const OneHundred = 100;
|
||||
|
||||
function hoursToDays(hours: number | string) {
|
||||
const curHours = typeof hours === 'string' ? parseInt(hours) : hours;
|
||||
if (isNaN(curHours)) {
|
||||
return 0;
|
||||
}
|
||||
return curHours / 24;
|
||||
}
|
||||
|
||||
function formatRemainingTime(remainingSeconds: number) {
|
||||
const minutes = Math.floor(remainingSeconds / 60);
|
||||
const seconds = remainingSeconds % 60;
|
||||
return {
|
||||
minutes,
|
||||
seconds,
|
||||
};
|
||||
}
|
||||
|
||||
const renderSubText = (
|
||||
status: ProcessStatus,
|
||||
item: ProgressItem,
|
||||
hasURLImport?: boolean,
|
||||
) => {
|
||||
const statusDesc = item?.statusDesc || I18n.t('datasets_unit_upload_fail');
|
||||
if (status === ProcessStatus.Failed) {
|
||||
return (
|
||||
<div
|
||||
data-dtestid={`${KnowledgeE2e.CreateUnitListProgressName}.${'subText'}`}
|
||||
className={'text-12px'}
|
||||
>
|
||||
{statusDesc}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
let subDesc = '';
|
||||
if (hasURLImport) {
|
||||
// 更新频率
|
||||
const updateInterval = hoursToDays(item?.update_interval || 0);
|
||||
subDesc = getFrequencyMap(updateInterval);
|
||||
} else {
|
||||
subDesc = formatBytes((item?.size || 0) as number);
|
||||
}
|
||||
return (
|
||||
<div
|
||||
data-dtestid={`${KnowledgeE2e.CreateUnitListProgressName}.${item?.name}`}
|
||||
className={'coz-fg-secondary text-12px'}
|
||||
>
|
||||
{subDesc}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const UnitProgress: React.FC<UnitProgressProps> = ({
|
||||
progressList,
|
||||
createStatus,
|
||||
}) => {
|
||||
const params = useKnowledgeParams();
|
||||
|
||||
const headerTitle = useMemo(() => {
|
||||
let msg: string = I18n.t('datasets_createFileModel_step4_processing');
|
||||
if (createStatus === CreateUnitStatus.TASK_FINISH) {
|
||||
const allFailed = progressList.every(
|
||||
status => status.status === DocumentStatus.Failed,
|
||||
);
|
||||
|
||||
if (allFailed) {
|
||||
msg = I18n.t('datasets_createFileModel_step4_failed');
|
||||
} else {
|
||||
msg = I18n.t('datasets_createFileModel_step4_Finish');
|
||||
}
|
||||
}
|
||||
return msg;
|
||||
}, [createStatus, progressList]);
|
||||
|
||||
const unitType = params.type as UnitType;
|
||||
const formatType = getFormatTypeFromUnitType(unitType);
|
||||
const hasURLImport = [
|
||||
UnitType.TABLE_API,
|
||||
UnitType.TABLE_FEISHU,
|
||||
UnitType.TABLE_GOOGLE_DRIVE,
|
||||
UnitType.TABLE_LARK,
|
||||
UnitType.TEXT_FEISHU,
|
||||
UnitType.TEXT_LARK,
|
||||
UnitType.TEXT_NOTION,
|
||||
UnitType.TEXT_URL,
|
||||
UnitType.TEXT_GOOGLE_DRIVE,
|
||||
].includes(unitType);
|
||||
|
||||
const percentFormat = (percent: number, remainingTime: number) => {
|
||||
const { minutes, seconds } = formatRemainingTime(remainingTime as number);
|
||||
const remainingTimeText = I18n.t('knowledge_upload_remaining_time_text', {
|
||||
minutes,
|
||||
seconds,
|
||||
});
|
||||
|
||||
return percent < OneHundred
|
||||
? `${percent}% ${
|
||||
Number(remainingTime) > 0 ? `(${remainingTimeText})` : ''
|
||||
}`
|
||||
: null;
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={styles['embed-progress']}>
|
||||
<div className={styles['progress-info']}>
|
||||
<div
|
||||
className={styles.text}
|
||||
data-testid={KnowledgeE2e.CreateUnitProgressTitle}
|
||||
>
|
||||
{headerTitle}
|
||||
</div>
|
||||
<div className={styles['progress-list']}>
|
||||
{progressList.map(item => {
|
||||
const { status } = item;
|
||||
const getProcessStatus = () => {
|
||||
if (
|
||||
[DocumentStatus.Failed, DocumentStatus.AuditFailed].includes(
|
||||
status,
|
||||
)
|
||||
) {
|
||||
return ProcessStatus.Failed;
|
||||
}
|
||||
|
||||
if (
|
||||
[
|
||||
DocumentStatus.Processing,
|
||||
DocumentStatus.Resegment,
|
||||
DocumentStatus.Refreshing,
|
||||
].includes(status)
|
||||
) {
|
||||
return ProcessStatus.Processing;
|
||||
}
|
||||
|
||||
if (
|
||||
[DocumentStatus.Enable, DocumentStatus.Disable].includes(status)
|
||||
) {
|
||||
return ProcessStatus.Complete;
|
||||
}
|
||||
|
||||
return ProcessStatus.Processing;
|
||||
};
|
||||
|
||||
const curStatus = getProcessStatus();
|
||||
const percent = item?.progress || INIT_PERCENT;
|
||||
return (
|
||||
<ProcessProgressItem
|
||||
className={styles['data-processing']}
|
||||
key={item?.documentId}
|
||||
mainText={item?.name}
|
||||
subText={renderSubText(curStatus, item, hasURLImport)}
|
||||
tipText={renderSubText(curStatus, item, hasURLImport)}
|
||||
status={curStatus}
|
||||
avatar={getTypeIcon({
|
||||
type: item?.type,
|
||||
url: item?.url,
|
||||
formatType,
|
||||
})}
|
||||
percent={percent}
|
||||
percentFormat={percentFormat(
|
||||
percent,
|
||||
item?.remaining_time as number,
|
||||
)}
|
||||
actions={[
|
||||
ProcessStatus.Complete ? (
|
||||
<div
|
||||
className={styles['finish-text']}
|
||||
data-testid={`${
|
||||
KnowledgeE2e.CreateUnitListProgressSuccessIcon
|
||||
}.${item?.name || ''}`}
|
||||
>
|
||||
{I18n.t('datasets_unit_process_success')}
|
||||
</div>
|
||||
) : null,
|
||||
]}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,17 @@
|
||||
.upload-footer {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
|
||||
margin-top: auto;
|
||||
margin-bottom: 18px;
|
||||
padding-top: 24px;
|
||||
padding-bottom: 24px;
|
||||
|
||||
line-height: 32px;
|
||||
|
||||
:global {
|
||||
.semi-button {
|
||||
margin-left: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 { UploadFooter } from './upload-footer';
|
||||
@@ -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 { isArray, isObject, get } from 'lodash-es';
|
||||
import {
|
||||
FooterBtnStatus,
|
||||
type FooterControlsProps,
|
||||
type FooterControlProp,
|
||||
type FooterBtnProps,
|
||||
type FooterPrefixType,
|
||||
} from '@coze-data/knowledge-resource-processor-core';
|
||||
import { Button, Tooltip } from '@coze-arch/coze-design';
|
||||
|
||||
import styles from './index.module.less';
|
||||
|
||||
interface UploadFooterProps {
|
||||
controls: FooterControlsProps;
|
||||
}
|
||||
|
||||
/** 类型断言 入参是不是 按钮数组 */
|
||||
function isBtnArray(controls: unknown): controls is FooterBtnProps[] {
|
||||
return !!controls && isArray(controls);
|
||||
}
|
||||
|
||||
function isControlsObject(controls: unknown): controls is FooterControlProp {
|
||||
return (
|
||||
!!controls &&
|
||||
isObject(controls) &&
|
||||
!!get(controls, 'btns') &&
|
||||
!!get(controls, 'prefix')
|
||||
);
|
||||
}
|
||||
|
||||
export const UploadFooter = (props: UploadFooterProps) => {
|
||||
const { controls } = props;
|
||||
let btns: FooterBtnProps[] = [];
|
||||
let prefix: FooterPrefixType;
|
||||
if (isBtnArray(controls)) {
|
||||
btns = controls;
|
||||
}
|
||||
if (isControlsObject(controls)) {
|
||||
({ btns, prefix } = controls);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={styles['upload-footer']}>
|
||||
{prefix}
|
||||
{btns.map(btnItem => {
|
||||
const isShowHoverContent =
|
||||
btnItem.disableHoverContent &&
|
||||
btnItem.status === FooterBtnStatus.DISABLE;
|
||||
const buttonNode = (
|
||||
<Button
|
||||
data-testid={btnItem.e2e}
|
||||
key={btnItem.text}
|
||||
disabled={btnItem.status === FooterBtnStatus.DISABLE}
|
||||
loading={btnItem.status === FooterBtnStatus.LOADING}
|
||||
color={btnItem.type || 'hgltplus'}
|
||||
// theme={btnItem.theme || 'solid'}
|
||||
onClick={btnItem.onClick}
|
||||
>
|
||||
{btnItem.text}
|
||||
</Button>
|
||||
);
|
||||
if (!isShowHoverContent) {
|
||||
return buttonNode;
|
||||
}
|
||||
return (
|
||||
<Tooltip content={btnItem.disableHoverContent}>{buttonNode}</Tooltip>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -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 classNames from 'classnames';
|
||||
import { getKnowledgeIDEQuery } from '@coze-data/knowledge-common-services';
|
||||
import { useDataNavigate, useKnowledgeParams } from '@coze-data/knowledge-stores';
|
||||
import { IconCozArrowLeft } from '@coze-arch/coze-design/icons';
|
||||
import { IconButton, Typography } from '@coze-arch/coze-design';
|
||||
|
||||
interface UploadActionNavbarProps {
|
||||
title: string;
|
||||
}
|
||||
|
||||
// 上传页面导航栏
|
||||
export const UploadActionNavbar = ({ title }: UploadActionNavbarProps) => {
|
||||
const params = useKnowledgeParams();
|
||||
const resourceNavigate = useDataNavigate();
|
||||
|
||||
// TODO: hzf biz的分化在Scene层维护
|
||||
const fromProject = params.biz === 'project';
|
||||
const handleBack = () => {
|
||||
const query = getKnowledgeIDEQuery() as Record<string, string>;
|
||||
resourceNavigate.toResource?.('knowledge', params.datasetID, query);
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
className={classNames(
|
||||
'flex items-center justify-between shrink-0 h-[56px] coz-fg-primary',
|
||||
fromProject ? 'px-[12px]' : '',
|
||||
)}
|
||||
>
|
||||
<div className="flex items-center">
|
||||
<IconButton
|
||||
color="secondary"
|
||||
icon={<IconCozArrowLeft className="text-[16px]" />}
|
||||
iconPosition="left"
|
||||
className="!p-[8px]"
|
||||
onClick={handleBack}
|
||||
></IconButton>
|
||||
<Typography.Text fontSize="16px" weight={500} className="ml-[8px]">
|
||||
{title}
|
||||
</Typography.Text>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* 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 { UploadStatus } from '@coze-data/knowledge-resource-processor-core';
|
||||
import { REPORT_EVENTS } from '@coze-arch/report-events';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import { type UploadProps } from '@coze-arch/bot-semi/Upload';
|
||||
import { Toast } from '@coze-arch/coze-design';
|
||||
|
||||
import { getFileExtension, getUint8Array } from '../../utils';
|
||||
import { UNIT_MAX_MB, PDF_MAX_PAGES } from '../../constants';
|
||||
|
||||
export const getBeforeUpload: (params: {
|
||||
maxSizeMB: UploadProps['maxSize'];
|
||||
}) => UploadProps['beforeUpload'] =
|
||||
({ maxSizeMB }) =>
|
||||
async fileInfo => {
|
||||
// 不通过 maxSize 属性来限制的原因是
|
||||
// 只有 beforeUpload 钩子能改 validateMessage
|
||||
const res = {
|
||||
fileInstance: fileInfo.file.fileInstance,
|
||||
status: fileInfo.file.status,
|
||||
validateMessage: fileInfo.file.validateMessage,
|
||||
shouldUpload: true,
|
||||
autoRemove: false,
|
||||
};
|
||||
|
||||
const { fileInstance } = fileInfo.file;
|
||||
|
||||
if (!fileInstance) {
|
||||
return {
|
||||
...res,
|
||||
status: UploadStatus.UPLOAD_FAIL,
|
||||
shouldUpload: false,
|
||||
};
|
||||
}
|
||||
|
||||
const resultMaxSizeMB = maxSizeMB || UNIT_MAX_MB;
|
||||
|
||||
const maxSize = resultMaxSizeMB * 1024 * 1024;
|
||||
|
||||
if (fileInstance.size > maxSize) {
|
||||
Toast.warning({
|
||||
showClose: false,
|
||||
content: I18n.t('file_too_large', {
|
||||
max_size: `${resultMaxSizeMB}MB`,
|
||||
}),
|
||||
});
|
||||
|
||||
return {
|
||||
...res,
|
||||
shouldUpload: false,
|
||||
status: UploadStatus.VALIDATE_FAIL,
|
||||
validateMessage: I18n.t('file_too_large', {
|
||||
max_size: `${resultMaxSizeMB}MB`,
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
||||
if (getFileExtension(fileInstance.name).toLowerCase() === 'pdf') {
|
||||
try {
|
||||
// TODO: 后续其他位置的 pdfjs 调用也都应该改成异步加载
|
||||
const pdfjs = await import('@coze-arch/pdfjs-shadow');
|
||||
const { getDocument, initPdfJsWorker } = pdfjs;
|
||||
|
||||
initPdfJsWorker();
|
||||
const uint8Array = await getUint8Array(fileInstance);
|
||||
const pdfDocument = await getDocument({ data: uint8Array }).promise;
|
||||
if (pdfDocument.numPages > PDF_MAX_PAGES) {
|
||||
Toast.warning({
|
||||
showClose: false,
|
||||
content: I18n.t('atasets_createpdf_over250'),
|
||||
});
|
||||
return {
|
||||
shouldUpload: false,
|
||||
status: UploadStatus.VALIDATE_FAIL,
|
||||
};
|
||||
}
|
||||
} catch (e) {
|
||||
const error = e as Error;
|
||||
dataReporter.errorEvent(DataNamespace.KNOWLEDGE, {
|
||||
eventName: REPORT_EVENTS.KnowledgeParseFile,
|
||||
error,
|
||||
});
|
||||
if (error?.name === 'PasswordException') {
|
||||
Toast.error({
|
||||
showClose: false,
|
||||
content: I18n.t('pdf_encrypted'),
|
||||
});
|
||||
return {
|
||||
shouldUpload: false,
|
||||
status: UploadStatus.VALIDATE_FAIL,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
};
|
||||
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* 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 { UploadStatus } from '@coze-data/knowledge-resource-processor-core';
|
||||
import { REPORT_EVENTS } from '@coze-arch/report-events';
|
||||
import { type UploadProps } from '@coze-arch/bot-semi/Upload';
|
||||
import { CustomError } from '@coze-arch/bot-error';
|
||||
import { FileBizType } from '@coze-arch/bot-api/developer_api';
|
||||
import { DeveloperApi } from '@coze-arch/bot-api';
|
||||
|
||||
import { getBase64, getFileExtension } from '../../utils';
|
||||
|
||||
export const customRequest: UploadProps['customRequest'] = async options => {
|
||||
const { onSuccess, onError, onProgress, file } = options;
|
||||
|
||||
try {
|
||||
// 业务
|
||||
const { name, fileInstance } = file;
|
||||
|
||||
if (fileInstance) {
|
||||
const extension = getFileExtension(name);
|
||||
|
||||
const base64 = await getBase64(fileInstance);
|
||||
const result = await DeveloperApi.UploadFile(
|
||||
{
|
||||
file_head: {
|
||||
file_type: extension,
|
||||
biz_type: FileBizType.BIZ_BOT_DATASET,
|
||||
},
|
||||
data: base64,
|
||||
},
|
||||
{
|
||||
onUploadProgress: e => {
|
||||
const status = file?.status;
|
||||
const response = file?.response;
|
||||
// 成功或失败、检验失败后,或者有返回接口数据,不再更新进度条
|
||||
if (
|
||||
status === UploadStatus.SUCCESS ||
|
||||
status === UploadStatus.UPLOAD_FAIL ||
|
||||
status === UploadStatus.VALIDATE_FAIL ||
|
||||
response?.upload_url
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { total, loaded } = e;
|
||||
if (total !== undefined && loaded < total) {
|
||||
onProgress({
|
||||
total: e.total ?? fileInstance.size,
|
||||
loaded: e.loaded,
|
||||
});
|
||||
}
|
||||
},
|
||||
},
|
||||
);
|
||||
onSuccess(result.data);
|
||||
} else {
|
||||
onError({
|
||||
status: 0,
|
||||
});
|
||||
dataReporter.errorEvent(DataNamespace.KNOWLEDGE, {
|
||||
eventName: REPORT_EVENTS.KnowledgeUploadFile,
|
||||
error: new CustomError(
|
||||
REPORT_EVENTS.KnowledgeUploadFile,
|
||||
`${REPORT_EVENTS.KnowledgeUploadFile}: Failed to upload file`,
|
||||
),
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
const error = e as Error;
|
||||
onError({
|
||||
status: 0,
|
||||
});
|
||||
dataReporter.errorEvent(DataNamespace.KNOWLEDGE, {
|
||||
eventName: REPORT_EVENTS.KnowledgeUploadFile,
|
||||
error,
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,57 @@
|
||||
.upload {
|
||||
width: 100%;
|
||||
|
||||
:global {
|
||||
.semi-upload-drag-area {
|
||||
height: 202px;
|
||||
background-color: var(--coz-mg-card);
|
||||
border-radius: 8px;
|
||||
|
||||
&:hover,
|
||||
&.semi-upload-drag-area-legal {
|
||||
border-radius: var(--default, 8px);
|
||||
}
|
||||
}
|
||||
|
||||
.semi-upload-drag-area-sub-text {
|
||||
color: var(--coz-fg-dim);
|
||||
}
|
||||
|
||||
.semi-button-with-icon-only {
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.semi-upload-file-list {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.upload-icon {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
.create-enough-file {
|
||||
cursor: not-allowed;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
.picture {
|
||||
width: 122px;
|
||||
height: 122px;
|
||||
margin-bottom: 14px;
|
||||
}
|
||||
|
||||
.text {
|
||||
font-size: 12px;
|
||||
line-height: 16px;
|
||||
color: rgb(28 31 35 / 60%);
|
||||
}
|
||||
}
|
||||
@@ -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 { UploadUnitFile } from './upload-unit-file';
|
||||
@@ -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 { type FC } from 'react';
|
||||
|
||||
import { type RenderFileItemProps } from '@coze-arch/bot-semi/Upload';
|
||||
import {
|
||||
IconPDFFile,
|
||||
IconUnknowFile as IconUnknownFile,
|
||||
IconTextFile,
|
||||
IconDocxFile,
|
||||
} from '@coze-arch/bot-icons';
|
||||
|
||||
import { getFileExtension } from '../../utils/common';
|
||||
import { type FileType } from './types';
|
||||
|
||||
export const PreviewFile: FC<RenderFileItemProps> = props => {
|
||||
const type = (getFileExtension(props.name) || 'unknown') as FileType;
|
||||
|
||||
const components: Record<FileType, React.FC> = {
|
||||
unknown: IconUnknownFile,
|
||||
pdf: IconPDFFile,
|
||||
text: IconTextFile,
|
||||
docx: IconDocxFile,
|
||||
};
|
||||
|
||||
const ComponentToRender = components[type] || IconUnknownFile;
|
||||
|
||||
return <ComponentToRender />;
|
||||
};
|
||||
@@ -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 type FileType = 'unknown' | 'pdf' | 'docx' | 'text';
|
||||
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* 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, useCallback, useMemo, type FC } from 'react';
|
||||
|
||||
import classNames from 'classnames';
|
||||
import { IllustrationSuccess } from '@douyinfe/semi-illustrations';
|
||||
import { abortable, useUnmountSignal } from '@coze-data/utils';
|
||||
import { type UnitItem } from '@coze-data/knowledge-resource-processor-core';
|
||||
import { KnowledgeE2e } from '@coze-data/e2e';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import {
|
||||
type FileItem,
|
||||
type UploadProps,
|
||||
type OnChangeProps,
|
||||
} from '@coze-arch/bot-semi/Upload';
|
||||
import { IconCozUpload } from '@coze-arch/coze-design/icons';
|
||||
import { Toast, Upload } from '@coze-arch/coze-design';
|
||||
|
||||
import { UNIT_MAX_MB } from '../../constants';
|
||||
import {
|
||||
filterFileListByUnitList,
|
||||
filterFileList,
|
||||
filterUnitList,
|
||||
} from './utils';
|
||||
import { PreviewFile } from './preview-file';
|
||||
import { customRequest } from './custom-request';
|
||||
import { getBeforeUpload } from './before-upload';
|
||||
|
||||
import styles from './index.module.less';
|
||||
|
||||
interface UploadUnitFileProps extends UploadProps {
|
||||
unitList: UnitItem[];
|
||||
onFinish: (unitList: UnitItem[]) => void;
|
||||
limit: number;
|
||||
accept: string;
|
||||
setUnitList: (unitList: UnitItem[]) => void;
|
||||
showIllustration?: boolean;
|
||||
maxSizeMB?: number;
|
||||
}
|
||||
|
||||
export const UploadUnitFile: FC<UploadUnitFileProps> = props => {
|
||||
const {
|
||||
unitList,
|
||||
onFinish,
|
||||
setUnitList,
|
||||
showIllustration = true,
|
||||
multiple = true,
|
||||
maxSizeMB = UNIT_MAX_MB,
|
||||
...uploadProps
|
||||
} = props;
|
||||
const { limit } = uploadProps;
|
||||
|
||||
const [fileList, setFileList] = useState<FileItem[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
if (unitList.length < fileList.length) {
|
||||
setFileList(filterFileListByUnitList(fileList, unitList));
|
||||
}
|
||||
}, [unitList.length]);
|
||||
|
||||
const handleAcceptInvalid = useCallback(() => {
|
||||
Toast.warning({
|
||||
showClose: false,
|
||||
content: I18n.t('knowledge_upload_format_error'),
|
||||
});
|
||||
}, []);
|
||||
|
||||
const signal = useUnmountSignal();
|
||||
|
||||
const handleUploadProcess = abortable((data: OnChangeProps) => {
|
||||
setFileList(data.fileList);
|
||||
setUnitList(filterFileList(data.fileList));
|
||||
}, signal);
|
||||
|
||||
const handleUploadSuccess = abortable(() => {
|
||||
onFinish(filterUnitList(unitList, fileList));
|
||||
}, signal);
|
||||
|
||||
const uploadDisabled = useMemo(
|
||||
() => unitList.length >= limit,
|
||||
[unitList, limit],
|
||||
);
|
||||
const beforeUpload = getBeforeUpload({ maxSizeMB });
|
||||
return (
|
||||
<Upload
|
||||
draggable
|
||||
data-testid={KnowledgeE2e.UploadUnitFile}
|
||||
multiple={multiple}
|
||||
fileList={fileList}
|
||||
disabled={uploadDisabled}
|
||||
previewFile={PreviewFile}
|
||||
onAcceptInvalid={handleAcceptInvalid}
|
||||
beforeUpload={beforeUpload}
|
||||
customRequest={customRequest}
|
||||
onChange={handleUploadProcess}
|
||||
onSuccess={handleUploadSuccess}
|
||||
dragIcon={<IconCozUpload className={styles['upload-icon']} />}
|
||||
{...uploadProps}
|
||||
className={classNames(styles.upload, uploadProps.className)}
|
||||
>
|
||||
{unitList.length >= limit && showIllustration ? (
|
||||
<div
|
||||
className={styles['create-enough-file']}
|
||||
onClick={e => e.stopPropagation()}
|
||||
>
|
||||
<IllustrationSuccess className={styles.picture} />
|
||||
<div className={styles.text}>
|
||||
{I18n.t('knowledge_1218_001', {
|
||||
MaxDocs: limit,
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
</Upload>
|
||||
);
|
||||
};
|
||||
@@ -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 {
|
||||
UploadStatus,
|
||||
type UnitItem,
|
||||
} from '@coze-data/knowledge-resource-processor-core';
|
||||
import { KNOWLEDGE_UNIT_NAME_MAX_LEN } from '@coze-data/knowledge-modal-base';
|
||||
import { type FileItem } from '@coze-arch/bot-semi/Upload';
|
||||
|
||||
import { getFileExtension } from '../../utils/common';
|
||||
|
||||
interface GetFileListMapRes {
|
||||
[key: string]: FileItem;
|
||||
}
|
||||
|
||||
const getFileName = (uri: string) => uri.substring(0, uri.lastIndexOf('.'));
|
||||
|
||||
const getNameFromFileList = (unitList: FileItem[], index: number) =>
|
||||
unitList?.[index]?.name;
|
||||
|
||||
const getFileListMap = (fileList: FileItem[]): GetFileListMapRes =>
|
||||
fileList.reduce((acc: GetFileListMapRes, item) => {
|
||||
acc[item.uid || ''] = item;
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
/** 过滤 fileList,仅保留在 unitList 中的文件,即上传成功的文件 */
|
||||
export const filterFileListByUnitList = (
|
||||
fileList: FileItem[],
|
||||
unitList: UnitItem[],
|
||||
): FileItem[] =>
|
||||
fileList.filter(fileItem =>
|
||||
unitList?.find(unitItem => unitItem.uri === fileItem?.response?.upload_uri),
|
||||
);
|
||||
|
||||
const fileItem2UnitItem = (
|
||||
file: FileItem,
|
||||
config?: { filename?: string },
|
||||
): UnitItem => ({
|
||||
type: getFileExtension(file?.response?.upload_uri || file.name),
|
||||
uri: file?.response?.upload_uri,
|
||||
url: file?.response?.upload_url,
|
||||
name: (config?.filename ?? getFileName(file.name)).slice(
|
||||
0,
|
||||
KNOWLEDGE_UNIT_NAME_MAX_LEN,
|
||||
),
|
||||
size: file.size,
|
||||
status: file.status as UnitItem['status'],
|
||||
percent: file.percent || 0,
|
||||
fileInstance: file.fileInstance,
|
||||
uid: file.uid,
|
||||
validateMessage: (file.validateMessage as string) || '',
|
||||
});
|
||||
|
||||
export const filterFileList = (fileList: FileItem[]): UnitItem[] => {
|
||||
const filteredList: UnitItem[] = fileList
|
||||
.filter(
|
||||
item =>
|
||||
!(!item.shouldUpload && item.status === UploadStatus.VALIDATE_FAIL),
|
||||
)
|
||||
.map((file, index) => {
|
||||
const filename = getNameFromFileList(fileList, index);
|
||||
return fileItem2UnitItem(file, { filename });
|
||||
});
|
||||
return filteredList;
|
||||
};
|
||||
|
||||
export const filterUnitList = (
|
||||
unitList: UnitItem[],
|
||||
fileList: FileItem[],
|
||||
): UnitItem[] => {
|
||||
const fileListMap = getFileListMap(fileList);
|
||||
return unitList
|
||||
.filter(unit => {
|
||||
const file = fileListMap[unit.uid || ''];
|
||||
if (!file.shouldUpload && file.status === UploadStatus.VALIDATE_FAIL) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
})
|
||||
.map((unit, index) => {
|
||||
const file = fileListMap[unit.uid || ''];
|
||||
const filename = getNameFromFileList(fileList, index);
|
||||
return {
|
||||
...unit,
|
||||
...fileItem2UnitItem(file, { filename }),
|
||||
};
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* 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 UnitItem } from '@coze-data/knowledge-resource-processor-core';
|
||||
import { useEditUnitNameModal } from '@coze-data/knowledge-modal-base';
|
||||
import { KnowledgeE2e } from '@coze-data/e2e';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import {
|
||||
IconCozEdit,
|
||||
IconCozRefresh,
|
||||
IconCozTrashCan,
|
||||
} from '@coze-arch/coze-design/icons';
|
||||
import { IconButton, Tooltip } from '@coze-arch/coze-design';
|
||||
|
||||
import { type RenderColumnsProps } from '../types';
|
||||
import { getFrequencyMap } from '../../../utils';
|
||||
|
||||
export function getFileSizeInfo(record: UnitItem) {
|
||||
return (
|
||||
<div
|
||||
data-dtestid={`${KnowledgeE2e.LocalUploadListFileSize}.${record.name}`}
|
||||
className={'coz-fg-secondary text-12px'}
|
||||
>
|
||||
{record?.size}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export function getFrequencyInfo(record: UnitItem) {
|
||||
return (
|
||||
<div
|
||||
data-dtestid={`${KnowledgeE2e.LocalUploadListFrequency}.${record.name}`}
|
||||
className={'coz-fg-secondary text-12px'}
|
||||
>
|
||||
{getFrequencyMap(record.updateInterval || 0)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export function ActionRenderByDelete(props: RenderColumnsProps) {
|
||||
const { index, record, params } = props;
|
||||
const { onChange, unitList, onDelete } = params;
|
||||
|
||||
const handleDelete = () => {
|
||||
onChange(unitList.filter((u, i) => index !== i));
|
||||
if (typeof onDelete === 'function') {
|
||||
onDelete?.(record, index);
|
||||
}
|
||||
};
|
||||
return (
|
||||
<Tooltip spacing={12} content={I18n.t('Delete')} position="top">
|
||||
<IconButton
|
||||
color="secondary"
|
||||
icon={<IconCozTrashCan className="text-14px" />}
|
||||
iconPosition="left"
|
||||
size="small"
|
||||
onClick={handleDelete}
|
||||
></IconButton>
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
|
||||
export function ActionRenderByEditName(props: RenderColumnsProps) {
|
||||
const { index, record, params } = props;
|
||||
const { onChange, unitList } = params;
|
||||
|
||||
const { node, open } = useEditUnitNameModal({
|
||||
name: record?.name ?? '',
|
||||
onOk: (name: string) => {
|
||||
const arr = [...unitList];
|
||||
arr[index].name = name;
|
||||
onChange(arr);
|
||||
},
|
||||
});
|
||||
return (
|
||||
<>
|
||||
<Tooltip spacing={12} content={I18n.t('Edit')} position="top">
|
||||
<IconButton
|
||||
color="secondary"
|
||||
icon={<IconCozEdit className="text-14px" />}
|
||||
iconPosition="left"
|
||||
size="small"
|
||||
onClick={() => open()}
|
||||
/>
|
||||
</Tooltip>
|
||||
{node}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export function ActionRenderByRetry(props: RenderColumnsProps) {
|
||||
const { index, record, params } = props;
|
||||
if (params.disableRetry) {
|
||||
return null;
|
||||
}
|
||||
const { onRetry } = params;
|
||||
|
||||
const handleRetry = () => {
|
||||
onRetry?.(record, index);
|
||||
};
|
||||
return (
|
||||
<Tooltip
|
||||
spacing={12}
|
||||
content={I18n.t('datasets_unit_update_retry')}
|
||||
position="top"
|
||||
>
|
||||
<IconButton
|
||||
color="secondary"
|
||||
icon={<IconCozRefresh className="text-14px" />}
|
||||
iconPosition="left"
|
||||
size="small"
|
||||
onClick={handleRetry}
|
||||
></IconButton>
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
import { type FC } from 'react';
|
||||
|
||||
import { UITableAction } from '@coze-arch/bot-semi';
|
||||
|
||||
import { type ActionProps } from '../../types';
|
||||
|
||||
export const Action: FC<ActionProps> = ({
|
||||
onDelete,
|
||||
showEdit,
|
||||
deleteProps,
|
||||
editProps,
|
||||
}: ActionProps) => (
|
||||
<UITableAction
|
||||
deleteProps={{
|
||||
disabled: false,
|
||||
handleClick: onDelete,
|
||||
...deleteProps,
|
||||
}}
|
||||
editProps={{
|
||||
hide: !showEdit,
|
||||
...editProps,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
@@ -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 { Action } from './action';
|
||||
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* 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 { UploadStatusComp } from './upload-status';
|
||||
export { UnitName } from './unit-name';
|
||||
export { Action } from './action-render';
|
||||
@@ -0,0 +1,44 @@
|
||||
.unit-name-wrap {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-left: 3px;
|
||||
|
||||
:global {
|
||||
.semi-icon {
|
||||
margin-right: 12px;
|
||||
}
|
||||
|
||||
.view-name {
|
||||
display: inline-block;
|
||||
height: 32px;
|
||||
font-size: 14px;
|
||||
line-height: 32px;
|
||||
}
|
||||
|
||||
.input-suffix {
|
||||
display: inline-block;
|
||||
margin-right: 5px;
|
||||
font-size: 12px;
|
||||
color: rgb(28 29 35 / 35%);
|
||||
}
|
||||
|
||||
.unit-name-input {
|
||||
width: 100%;
|
||||
|
||||
.error {
|
||||
position: absolute;
|
||||
color: rgb(249 57 32 / 100%);
|
||||
}
|
||||
}
|
||||
|
||||
.unit-name-error {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.error {
|
||||
color: rgb(249 57 32 / 100%);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* 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';
|
||||
|
||||
import { KNOWLEDGE_UNIT_NAME_MAX_LEN } from '@coze-data/knowledge-modal-base';
|
||||
import { KnowledgeE2e } from '@coze-data/e2e';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import { UIInput } from '@coze-arch/bot-semi';
|
||||
|
||||
import { getTypeIcon } from '../../utils';
|
||||
import { type UnitNameProps } from '../../types';
|
||||
|
||||
import styles from './index.module.less';
|
||||
|
||||
export const UnitName: React.FC<UnitNameProps> = ({
|
||||
edit,
|
||||
onChange,
|
||||
disabled,
|
||||
record,
|
||||
formatType,
|
||||
}) => {
|
||||
const { type, name, validateMessage } = record;
|
||||
const [value, setValue] = useState(name); // 需要用自身state,否则出现无法输入中文的bug
|
||||
const getValidateMessage = (val: string) =>
|
||||
!val ? I18n.t('datasets_unit_exception_name_empty') : validateMessage;
|
||||
useEffect(() => {
|
||||
setValue(name);
|
||||
}, [name]);
|
||||
return (
|
||||
<div
|
||||
className={styles['unit-name-wrap']}
|
||||
data-testid={`${KnowledgeE2e.FeishuUploadListName}.${name}`}
|
||||
>
|
||||
{getTypeIcon({ type, formatType })}
|
||||
{edit ? (
|
||||
<div className="unit-name-input">
|
||||
<UIInput
|
||||
disabled={disabled}
|
||||
value={value}
|
||||
onChange={val => {
|
||||
setValue(val);
|
||||
onChange(val);
|
||||
}}
|
||||
maxLength={KNOWLEDGE_UNIT_NAME_MAX_LEN}
|
||||
validateStatus={!name ? 'error' : 'default'}
|
||||
suffix={
|
||||
<span className="input-suffix">
|
||||
{(name || '').length}/{KNOWLEDGE_UNIT_NAME_MAX_LEN}
|
||||
</span>
|
||||
}
|
||||
/>
|
||||
<div className="error">{getValidateMessage(name)}</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="unit-name-error">
|
||||
<span className="view-name">{name}</span>
|
||||
{validateMessage ? (
|
||||
<div className="error">{validateMessage}</div>
|
||||
) : null}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* 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, type FC } from 'react';
|
||||
|
||||
import { KNOWLEDGE_UNIT_NAME_MAX_LEN } from '@coze-data/knowledge-modal-base';
|
||||
import { KnowledgeE2e } from '@coze-data/e2e';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import { UIInput } from '@coze-arch/bot-semi';
|
||||
import { FormatType } from '@coze-arch/bot-api/memory';
|
||||
|
||||
import { validateField } from '@/utils';
|
||||
|
||||
import { getTypeIcon } from '../../utils';
|
||||
import { type UnitNameProps } from '../../types';
|
||||
|
||||
import styles from './index.module.less';
|
||||
|
||||
export const UnitName: FC<UnitNameProps> = ({
|
||||
edit,
|
||||
onChange,
|
||||
disabled,
|
||||
record,
|
||||
formatType,
|
||||
canValidator = true,
|
||||
inModal = false,
|
||||
}) => {
|
||||
const { type, name, validateMessage, dynamicErrorMessage } = record;
|
||||
const [value, setValue] = useState(name); // 需要用自身state,否则出现无法输入中文的bug
|
||||
const [validData, setValidData] = useState({ valid: true, errorMsg: '' });
|
||||
|
||||
const getValidateMessage = (val: string) =>
|
||||
!val ? I18n.t('datasets_unit_exception_name_empty') : validateMessage;
|
||||
|
||||
const validator = (val: string) => {
|
||||
const validObj = validateField(val, getValidateMessage(name));
|
||||
setValidData(
|
||||
formatType === FormatType.Table
|
||||
? validObj
|
||||
: {
|
||||
valid: !!name,
|
||||
errorMsg: '',
|
||||
},
|
||||
);
|
||||
};
|
||||
useEffect(() => {
|
||||
setValue(name);
|
||||
canValidator && !disabled && validator(name);
|
||||
}, [name, disabled]);
|
||||
|
||||
return (
|
||||
<div className={styles['unit-name-wrap']}>
|
||||
{getTypeIcon({ type, formatType, url: record.url, inModal })}
|
||||
{edit ? (
|
||||
<div className="unit-name-input">
|
||||
<UIInput
|
||||
data-dtestid={`${KnowledgeE2e.LocalUploadListName}.${record.name}`}
|
||||
disabled={disabled}
|
||||
autoFocus={true}
|
||||
value={value}
|
||||
onChange={val => {
|
||||
setValue(val);
|
||||
onChange(val);
|
||||
}}
|
||||
onBlur={() => {
|
||||
canValidator && validator(name);
|
||||
}}
|
||||
maxLength={KNOWLEDGE_UNIT_NAME_MAX_LEN}
|
||||
validateStatus={
|
||||
!validData.valid || dynamicErrorMessage ? 'error' : 'default'
|
||||
}
|
||||
suffix={
|
||||
<span className="input-suffix">
|
||||
{(name || '').length}/{KNOWLEDGE_UNIT_NAME_MAX_LEN}
|
||||
</span>
|
||||
}
|
||||
/>
|
||||
<div className="error">
|
||||
{!disabled &&
|
||||
(validData.errorMsg ||
|
||||
getValidateMessage(name) ||
|
||||
dynamicErrorMessage)}
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<span
|
||||
className="view-name"
|
||||
data-dtestid={`${KnowledgeE2e.LocalUploadListNameView}.${record.name}`}
|
||||
>
|
||||
{name}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,44 @@
|
||||
.upload-status-wrap {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
line-height: 22px;
|
||||
|
||||
:global {
|
||||
.semi-icon {
|
||||
float: left;
|
||||
margin: 0 5px -3px 0;
|
||||
}
|
||||
|
||||
.semi-progress-horizontal {
|
||||
margin-top: 2px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.retry {
|
||||
cursor: pointer;
|
||||
|
||||
:global {
|
||||
.semi-icon {
|
||||
float: left;
|
||||
margin: 3px 3px 0 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.retry-text {
|
||||
margin-left: 3px;
|
||||
color: rgb(77 83 232 / 100%);
|
||||
}
|
||||
|
||||
|
||||
.disabled-retry {
|
||||
.retry-text {
|
||||
cursor: not-allowed;
|
||||
color: #ccc;
|
||||
}
|
||||
}
|
||||
|
||||
.no-retry-text {
|
||||
cursor: not-allowed;
|
||||
}
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
/* eslint-disable complexity */
|
||||
import classNames from 'classnames';
|
||||
import {
|
||||
UploadStatus,
|
||||
EntityStatus,
|
||||
} from '@coze-data/knowledge-resource-processor-core';
|
||||
import { KnowledgeE2e } from '@coze-data/e2e';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import { Tooltip, Progress, Spin } from '@coze-arch/bot-semi';
|
||||
import {
|
||||
IconUploadFileSuccess,
|
||||
IconUploadFileFail,
|
||||
} from '@coze-arch/bot-icons';
|
||||
import { WebStatus } from '@coze-arch/bot-api/knowledge';
|
||||
|
||||
import { type UploadStateProps } from '../../types';
|
||||
|
||||
import styles from './index.module.less';
|
||||
|
||||
export const UploadStatusComp: React.FC<UploadStateProps> = ({
|
||||
record,
|
||||
onRetry,
|
||||
index,
|
||||
needLoading,
|
||||
overlayClassName,
|
||||
disableRetry,
|
||||
noRetry,
|
||||
}) => {
|
||||
const { status } = record;
|
||||
if (
|
||||
status === UploadStatus.UPLOADING ||
|
||||
status === UploadStatus.VALIDATING ||
|
||||
status === UploadStatus.WAIT ||
|
||||
status === WebStatus.Handling ||
|
||||
status === EntityStatus.EntityStatusProcess
|
||||
) {
|
||||
return (
|
||||
<span
|
||||
data-dtestid={`${KnowledgeE2e.LocalUploadListStatus}.${record.name}`}
|
||||
className={classNames(styles['upload-status-wrap'], overlayClassName)}
|
||||
>
|
||||
<span>{I18n.t('datasets_unit_upload_state')}</span>
|
||||
{needLoading ? (
|
||||
<Spin spinning={true} />
|
||||
) : (
|
||||
<Progress percent={record.percent} />
|
||||
)}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
if (
|
||||
status === UploadStatus.SUCCESS ||
|
||||
status === WebStatus.Finish ||
|
||||
status === EntityStatus.EntityStatusSuccess
|
||||
) {
|
||||
return (
|
||||
<span
|
||||
className={styles['upload-status-wrap']}
|
||||
data-dtestid={`${KnowledgeE2e.LocalUploadListStatus}.${record.name}`}
|
||||
>
|
||||
<IconUploadFileSuccess />
|
||||
<span>{I18n.t('datasets_unit_upload_success')}</span>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
if (status === UploadStatus.VALIDATE_FAIL) {
|
||||
return (
|
||||
<span
|
||||
className={styles['upload-status-wrap']}
|
||||
data-dtestid={`${KnowledgeE2e.LocalUploadListStatus}.${record.name}`}
|
||||
>
|
||||
<IconUploadFileFail />
|
||||
</span>
|
||||
);
|
||||
}
|
||||
if (
|
||||
status === UploadStatus.UPLOAD_FAIL ||
|
||||
status === WebStatus.Failed ||
|
||||
status === EntityStatus.EntityStatusFail
|
||||
) {
|
||||
return (
|
||||
<div
|
||||
data-dtestid={`${KnowledgeE2e.LocalUploadListStatus}.${record.name}`}
|
||||
className={classNames(
|
||||
`${styles['upload-status-wrap']} ${styles.retry}`,
|
||||
overlayClassName,
|
||||
disableRetry ? styles['disabled-retry'] : '',
|
||||
noRetry ? styles['no-retry-text'] : '',
|
||||
)}
|
||||
onClick={() => {
|
||||
!disableRetry && !noRetry && onRetry && onRetry(record, index);
|
||||
}}
|
||||
>
|
||||
{!record.statusDescript ? (
|
||||
<IconUploadFileFail />
|
||||
) : (
|
||||
<Tooltip content={record.statusDescript} trigger="hover">
|
||||
<IconUploadFileFail />
|
||||
</Tooltip>
|
||||
)}
|
||||
{!noRetry && (
|
||||
<div className={classNames(styles['retry-text'])}>
|
||||
{I18n.t('datasets_unit_update_retry')}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
@@ -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 { UploadUnitTable } from './upload-unit-table';
|
||||
export { type RenderColumnsProps } from './types';
|
||||
export {
|
||||
ActionRenderByDelete,
|
||||
ActionRenderByEditName,
|
||||
ActionRenderByRetry,
|
||||
getFrequencyInfo,
|
||||
getFileSizeInfo,
|
||||
} from './actions';
|
||||
export { getProcessStatus } from './utils';
|
||||
export { type ColumnInfo, type UploadUnitTableProps } from './types';
|
||||
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* 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,
|
||||
type UnitItem,
|
||||
} from '@coze-data/knowledge-resource-processor-core';
|
||||
import { type UIActionItemProps } from '@coze-arch/bot-semi';
|
||||
import { type FormatType } from '@coze-arch/bot-api/memory';
|
||||
|
||||
export interface UploadStateProps {
|
||||
record: UnitItem;
|
||||
onRetry?: (record: UnitItem, index: number) => void;
|
||||
index: number;
|
||||
needLoading?: boolean;
|
||||
overlayClassName?: string;
|
||||
disableRetry?: boolean;
|
||||
// 不显示重试文案
|
||||
noRetry?: boolean;
|
||||
}
|
||||
|
||||
export interface UnitNameProps {
|
||||
canValidator?: boolean;
|
||||
edit?: boolean;
|
||||
disabled?: boolean;
|
||||
inModal?: boolean;
|
||||
formatType: FormatType;
|
||||
onChange: (value: string) => void;
|
||||
record: UnitItem;
|
||||
}
|
||||
|
||||
export interface ActionProps {
|
||||
showEdit?: boolean;
|
||||
onDelete: () => void;
|
||||
deleteProps?: UIActionItemProps;
|
||||
editProps?: UIActionItemProps;
|
||||
record?: UnitItem;
|
||||
}
|
||||
|
||||
export enum ActionType {
|
||||
Edit = 'edit',
|
||||
Delete = 'delete',
|
||||
}
|
||||
|
||||
export type HandleChange = (
|
||||
unitList: UnitItem[],
|
||||
action?: {
|
||||
type: ActionType;
|
||||
index: number;
|
||||
},
|
||||
) => void;
|
||||
|
||||
export interface ColumnInfo {
|
||||
subText?: ReactNode;
|
||||
actions?: ReactNode[];
|
||||
formatType?: FormatType;
|
||||
}
|
||||
|
||||
export interface UploadUnitTableProps {
|
||||
type: UnitType;
|
||||
unitList: UnitItem[];
|
||||
onChange: HandleChange;
|
||||
edit: boolean;
|
||||
canValidator?: boolean;
|
||||
onRetry?: (record: UnitItem, index: number) => void;
|
||||
disableRetry?: boolean;
|
||||
onDelete?: (record: UnitItem, index: number) => void;
|
||||
showEdit?: boolean;
|
||||
inModal?: boolean;
|
||||
getColumns?: (record: UnitItem, index: number) => ColumnInfo;
|
||||
}
|
||||
export interface GetColumnsParams extends UploadUnitTableProps {
|
||||
formatType: FormatType;
|
||||
}
|
||||
|
||||
export interface RenderColumnsProps {
|
||||
params: UploadUnitTableProps;
|
||||
record: UnitItem;
|
||||
index: number;
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* 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 React, { type FC, type ReactNode } from 'react';
|
||||
|
||||
import { KnowledgeE2e } from '@coze-data/e2e';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
|
||||
import { ProcessProgressItem } from '../process-progress-item/process-progress-item';
|
||||
import { ProcessStatus } from '../../types';
|
||||
import { getProcessStatus, getTypeIcon } from './utils';
|
||||
import { type ColumnInfo, type UploadUnitTableProps } from './types';
|
||||
|
||||
const INIT_PERCENT = 10;
|
||||
|
||||
const renderSubText = (
|
||||
status: ProcessStatus,
|
||||
statusDesc: string,
|
||||
subText: ReactNode,
|
||||
) => {
|
||||
if (status === ProcessStatus.Failed) {
|
||||
return (
|
||||
<div
|
||||
data-dtestid={`${KnowledgeE2e.CreateUnitListProgressName}.${'subText'}`}
|
||||
className={'text-12px'}
|
||||
>
|
||||
{statusDesc || I18n.t('datasets_unit_upload_fail')}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return subText;
|
||||
};
|
||||
|
||||
export const UploadUnitTable: FC<UploadUnitTableProps> = props => {
|
||||
const { unitList = [], getColumns } = props;
|
||||
if (unitList.length === 0) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<div className="upload-container">
|
||||
{unitList.map((item, index) => {
|
||||
const curStatus = getProcessStatus(item?.status);
|
||||
const statusDescript = item?.statusDescript || '';
|
||||
|
||||
// 使用getColumns获取每个项目的信息
|
||||
const columnInfo: ColumnInfo = getColumns
|
||||
? getColumns(item, index)
|
||||
: {};
|
||||
const { subText, actions, formatType } = columnInfo;
|
||||
|
||||
return (
|
||||
<ProcessProgressItem
|
||||
key={item.uid}
|
||||
mainText={item.name || '--'}
|
||||
subText={renderSubText(curStatus, statusDescript, subText)}
|
||||
tipText={
|
||||
<span
|
||||
data-dtestid={`${KnowledgeE2e.LocalUploadListStatus}.${item.name}`}
|
||||
>
|
||||
{curStatus === ProcessStatus.Failed
|
||||
? statusDescript || I18n.t('datasets_unit_upload_fail')
|
||||
: I18n.t('datasets_unit_upload_success')}
|
||||
</span>
|
||||
}
|
||||
status={curStatus}
|
||||
avatar={getTypeIcon({ ...item, formatType })}
|
||||
actions={actions}
|
||||
percent={item.percent || INIT_PERCENT}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
* 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 {
|
||||
EntityStatus,
|
||||
UploadStatus,
|
||||
} from '@coze-data/knowledge-resource-processor-core';
|
||||
import { WebStatus } from '@coze-arch/idl/knowledge';
|
||||
import { Image } from '@coze-arch/bot-semi';
|
||||
import {
|
||||
IconUploadPDF,
|
||||
IconUploadCSV,
|
||||
IconUploadDoc,
|
||||
IconUploadTxt,
|
||||
IconUploadTableUrl,
|
||||
IconUploadXLS,
|
||||
IconUploadTextUrl,
|
||||
IconUploadMD,
|
||||
} from '@coze-arch/bot-icons';
|
||||
import { FormatType } from '@coze-arch/bot-api/knowledge';
|
||||
|
||||
import { ProcessStatus } from '../../types';
|
||||
|
||||
enum UploadType {
|
||||
PDF = 'pdf',
|
||||
DOCX = 'docx',
|
||||
TXT = 'txt',
|
||||
XLSX = 'xlsx',
|
||||
XLTX = 'xltx',
|
||||
CSV = 'csv',
|
||||
PNG = 'png',
|
||||
JPG = 'jpg',
|
||||
JPEG = 'jpeg',
|
||||
WEBP = 'webp',
|
||||
XLS = 'xls',
|
||||
MD = 'md',
|
||||
}
|
||||
export const getTypeIcon = (params: {
|
||||
type: string | undefined;
|
||||
formatType?: FormatType;
|
||||
url?: string;
|
||||
inModal?: boolean;
|
||||
}) => {
|
||||
const { type, formatType, url } = params;
|
||||
// const iconClassName = inModal ? styles['icon-size-24'] : styles.icon;
|
||||
if (
|
||||
formatType === FormatType.Image &&
|
||||
[UploadType.JPG, UploadType.JPEG, UploadType.PNG, UploadType.WEBP].includes(
|
||||
type as UploadType,
|
||||
)
|
||||
) {
|
||||
return (
|
||||
<Image
|
||||
src={url}
|
||||
width={24}
|
||||
height={24}
|
||||
style={{
|
||||
borderRadius: '4px',
|
||||
marginRight: '12px',
|
||||
flexShrink: 0,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
if (type === UploadType.MD) {
|
||||
return <IconUploadMD />;
|
||||
}
|
||||
if (type === UploadType.PDF) {
|
||||
return <IconUploadPDF />;
|
||||
}
|
||||
if (type === UploadType.DOCX) {
|
||||
return <IconUploadDoc />;
|
||||
}
|
||||
if (type === UploadType.TXT) {
|
||||
return <IconUploadTxt />;
|
||||
}
|
||||
if (
|
||||
type === UploadType.XLSX ||
|
||||
type === UploadType.XLTX ||
|
||||
type === UploadType.XLS
|
||||
) {
|
||||
return <IconUploadXLS />;
|
||||
}
|
||||
if (type === UploadType.CSV) {
|
||||
return <IconUploadCSV />;
|
||||
}
|
||||
|
||||
return formatType === FormatType.Table ? (
|
||||
<IconUploadTableUrl />
|
||||
) : (
|
||||
<IconUploadTextUrl />
|
||||
);
|
||||
};
|
||||
|
||||
export const getProcessStatus = (
|
||||
status: UploadStatus | WebStatus | EntityStatus,
|
||||
) => {
|
||||
if (
|
||||
status === UploadStatus.UPLOADING ||
|
||||
status === UploadStatus.VALIDATING ||
|
||||
status === UploadStatus.WAIT ||
|
||||
status === WebStatus.Handling ||
|
||||
status === EntityStatus.EntityStatusProcess
|
||||
) {
|
||||
return ProcessStatus.Processing;
|
||||
}
|
||||
|
||||
if (
|
||||
status === UploadStatus.SUCCESS ||
|
||||
status === WebStatus.Finish ||
|
||||
status === EntityStatus.EntityStatusSuccess
|
||||
) {
|
||||
return ProcessStatus.Complete;
|
||||
}
|
||||
|
||||
if (
|
||||
status === UploadStatus.VALIDATE_FAIL ||
|
||||
status === UploadStatus.UPLOAD_FAIL ||
|
||||
status === WebStatus.Failed ||
|
||||
status === EntityStatus.EntityStatusFail
|
||||
) {
|
||||
return ProcessStatus.Failed;
|
||||
}
|
||||
return ProcessStatus.Processing;
|
||||
};
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* 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 const SUCCESSFUL_UPLOAD_PROGRESS = 100;
|
||||
|
||||
export const POLLING_TIME = 3000;
|
||||
|
||||
export const MAX_UNIT_NAME_LEN = 100;
|
||||
|
||||
export const BOT_DATA_REFACTOR_CLASS_NAME = 'data-refactor';
|
||||
|
||||
export const TABLE_ACCEPT_LOCAL_FILE = ['.xls', '.xlsx', '.csv'];
|
||||
|
||||
interface TextUploadChannelConfig {
|
||||
acceptFileTypes: string[];
|
||||
fileFormatString: string;
|
||||
addUnitMaxLimit: number;
|
||||
}
|
||||
|
||||
export type Channel = 'DOUYIN' | 'DEFAULT';
|
||||
|
||||
const textUploadChannelConfigMap: Record<Channel, TextUploadChannelConfig> = {
|
||||
DOUYIN: {
|
||||
acceptFileTypes: ['.pdf', '.txt', '.doc', '.docx'],
|
||||
fileFormatString: 'PDF、TXT、DOC、DOCX',
|
||||
addUnitMaxLimit: 100,
|
||||
},
|
||||
DEFAULT: {
|
||||
acceptFileTypes: ['.pdf', '.txt', '.doc', '.docx', '.md'],
|
||||
fileFormatString: 'PDF、TXT、DOC、DOCX、MD',
|
||||
addUnitMaxLimit: 300,
|
||||
},
|
||||
};
|
||||
|
||||
export const getTextUploadChannelConfig = (
|
||||
channel?: Channel,
|
||||
): TextUploadChannelConfig =>
|
||||
(channel && textUploadChannelConfigMap[channel]) ||
|
||||
textUploadChannelConfigMap.DEFAULT;
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* 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 enum FrequencyDay {
|
||||
ZERO = 0,
|
||||
ONE = 1,
|
||||
THREE = 3,
|
||||
SEVEN = 7,
|
||||
THIRTY = 30,
|
||||
}
|
||||
export enum TableSettingFormFields {
|
||||
SHEET = 'sheet_id',
|
||||
KEY_START_ROW = 'header_line_idx',
|
||||
DATA_START_ROW = 'start_line_idx',
|
||||
}
|
||||
|
||||
/** 知识库上传文件最大 size 100MB */
|
||||
export const UNIT_MAX_MB = 100;
|
||||
|
||||
export const PDF_MAX_PAGES = 500;
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* 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 {
|
||||
SUCCESSFUL_UPLOAD_PROGRESS,
|
||||
POLLING_TIME,
|
||||
MAX_UNIT_NAME_LEN,
|
||||
BOT_DATA_REFACTOR_CLASS_NAME,
|
||||
} from './common';
|
||||
export {
|
||||
TableStatus,
|
||||
MAX_TABLE_META_COLUMN_LEN,
|
||||
MAX_TABLE_META_STR_LEN,
|
||||
DEFAULT_TABLE_SETTINGS_FROM_ONE,
|
||||
DEFAULT_TABLE_SETTINGS_FROM_ZERO,
|
||||
TableSettingFormFields,
|
||||
} from './table';
|
||||
export { defaultCustomSegmentRule, getSeperatorOptionList } from './text';
|
||||
export { FrequencyDay, UNIT_MAX_MB, PDF_MAX_PAGES } from './components';
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/** table common constants */
|
||||
|
||||
export enum TableStatus {
|
||||
ERROR = 'error',
|
||||
LOADING = 'loading',
|
||||
NORMAL = 'normal',
|
||||
}
|
||||
|
||||
export const MAX_TABLE_META_COLUMN_LEN = 50;
|
||||
|
||||
export const MAX_TABLE_META_STR_LEN = 30;
|
||||
|
||||
/** table-local resegment unit steps */
|
||||
export enum TableLocalResegmentStep {
|
||||
CONFIGURATION,
|
||||
PREVIEW,
|
||||
PROCESSING,
|
||||
}
|
||||
|
||||
export enum TableSettingFormFields {
|
||||
SHEET = 'sheet_id',
|
||||
KEY_START_ROW = 'header_line_idx',
|
||||
DATA_START_ROW = 'start_line_idx',
|
||||
}
|
||||
|
||||
export const DEFAULT_TABLE_SETTINGS_FROM_ONE = {
|
||||
[TableSettingFormFields.SHEET]: 0,
|
||||
[TableSettingFormFields.KEY_START_ROW]: 0,
|
||||
[TableSettingFormFields.DATA_START_ROW]: 1,
|
||||
};
|
||||
|
||||
export const DEFAULT_TABLE_SETTINGS_FROM_ZERO = {
|
||||
[TableSettingFormFields.SHEET]: 0,
|
||||
[TableSettingFormFields.KEY_START_ROW]: 0,
|
||||
[TableSettingFormFields.DATA_START_ROW]: 0,
|
||||
};
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* 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 { type CustomSegmentRule, SeperatorType } from '../types';
|
||||
|
||||
const getSeperatorSelect = () => ({
|
||||
[SeperatorType.LINE_BREAK]: I18n.t('datasets_Custom_segmentID_linebreak'),
|
||||
[SeperatorType.LINE_BREAK2]: I18n.t('datasets_Custom_segmentID_2linebreak'),
|
||||
[SeperatorType.CN_PERIOD]: I18n.t('datasets_Custom_segmentID_cnperiod'),
|
||||
[SeperatorType.CN_EXCLAMATION]: I18n.t(
|
||||
'datasets_Custom_segmentID_cn_exclamation',
|
||||
),
|
||||
[SeperatorType.EN_PERIOD]: I18n.t('datasets_Custom_segmentID_enperiod'),
|
||||
[SeperatorType.EN_EXCLAMATION]: I18n.t(
|
||||
'datasets_Custom_segmentID_en_exclamation',
|
||||
),
|
||||
[SeperatorType.CN_QUESTION]: I18n.t('datasets_Custom_segmentID_cn_question'),
|
||||
[SeperatorType.EN_QUESTION]: I18n.t('datasets_Custom_segmentID_en_question'),
|
||||
[SeperatorType.CUSTOM]: I18n.t('datasets_Custom_segmentID_custom'),
|
||||
});
|
||||
|
||||
export const getSeperatorOptionList = () =>
|
||||
Object.entries(getSeperatorSelect()).map(([k, label]) => ({
|
||||
value: k,
|
||||
label,
|
||||
}));
|
||||
|
||||
const defaultMaxTokens = 800;
|
||||
|
||||
const defaultOverlap = 10;
|
||||
|
||||
export const defaultCustomSegmentRule: CustomSegmentRule = {
|
||||
separator: {
|
||||
type: SeperatorType.LINE_BREAK,
|
||||
customValue: '###',
|
||||
},
|
||||
maxTokens: defaultMaxTokens,
|
||||
preProcessRules: [],
|
||||
overlap: defaultOverlap,
|
||||
};
|
||||
@@ -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 {
|
||||
type FooterControlsProps,
|
||||
type UploadConfig,
|
||||
} from '@coze-data/knowledge-resource-processor-core';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
|
||||
import { useImageDisplayAnnotationStepCheck } from '@/hooks/common';
|
||||
import { UploadFooter } from '@/components';
|
||||
|
||||
import { ImageFileAddStep } from './types';
|
||||
import { createImageFileAddStore, type ImageFileAddStore } from './store';
|
||||
import { ImageUpload } from './steps/upload';
|
||||
import { ImageProcess } from './steps/process';
|
||||
import { ImageAnnotation } from './steps/annotation';
|
||||
|
||||
export const ImageFileAddConfig: UploadConfig<
|
||||
ImageFileAddStep,
|
||||
ImageFileAddStore
|
||||
> = {
|
||||
steps: [
|
||||
{
|
||||
title: I18n.t('knowledge_photo_006'),
|
||||
step: ImageFileAddStep.Upload,
|
||||
content: props => (
|
||||
<ImageUpload
|
||||
{...props}
|
||||
footer={(controls: FooterControlsProps) => (
|
||||
<UploadFooter controls={controls} />
|
||||
)}
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: I18n.t('knowledge_photo_007'),
|
||||
step: ImageFileAddStep.Annotation,
|
||||
content: props => (
|
||||
<ImageAnnotation
|
||||
{...props}
|
||||
footer={(controls: FooterControlsProps) => (
|
||||
<UploadFooter controls={controls} />
|
||||
)}
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: I18n.t('db_table_0126_015'),
|
||||
step: ImageFileAddStep.Process,
|
||||
content: props => (
|
||||
<ImageProcess
|
||||
{...props}
|
||||
footer={(controls: FooterControlsProps) => (
|
||||
<UploadFooter controls={controls} />
|
||||
)}
|
||||
/>
|
||||
),
|
||||
},
|
||||
],
|
||||
createStore: createImageFileAddStore,
|
||||
useUploadMount: store => useImageDisplayAnnotationStepCheck(),
|
||||
};
|
||||
@@ -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 { ImageFileAddConfig } from './config';
|
||||
@@ -0,0 +1,125 @@
|
||||
/* stylelint-disable max-nesting-depth */
|
||||
/* stylelint-disable selector-class-pattern */
|
||||
.segment-radio-wrapper {
|
||||
.displayNone {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.custom-wrapper {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
|
||||
.form-segment {
|
||||
margin-top: 33px;
|
||||
margin-bottom: 15px;
|
||||
|
||||
.item {
|
||||
margin-bottom: 20px;
|
||||
|
||||
.label {
|
||||
display: block;
|
||||
|
||||
margin-bottom: 8px;
|
||||
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
line-height: 22px;
|
||||
color: var(--coz-fg-primary);
|
||||
}
|
||||
|
||||
.label-red::after {
|
||||
content: "*";
|
||||
margin-left: 4px;
|
||||
font-weight: 600;
|
||||
color: var(--coz-fg-hglt-red);
|
||||
}
|
||||
|
||||
.custom-input {
|
||||
margin-top: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.line {
|
||||
&::before {
|
||||
content: '';
|
||||
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
|
||||
display: inline-block;
|
||||
|
||||
width: 100%;
|
||||
height: 1px;
|
||||
margin-top: 26px;
|
||||
|
||||
background: var(--light-usage-border-color-border,
|
||||
rgb(28 31 35 / 8%));
|
||||
}
|
||||
}
|
||||
|
||||
:global {
|
||||
.semi-radioGroup.semi-radioGroup-vertical {
|
||||
row-gap: 16px;
|
||||
}
|
||||
|
||||
.semi-radioGroup {
|
||||
.semi-radio-content {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.custom-wrapper {
|
||||
padding-bottom: 0;
|
||||
|
||||
.semi-input-default,
|
||||
.semi-input-wrapper-focus {
|
||||
border-radius: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.semi-radio-cardRadioGroup {
|
||||
padding: 16px 16px 16px 19px;
|
||||
border: 1px solid var(--coz-stroke-plus);
|
||||
border-radius: 8px;
|
||||
|
||||
&:hover {
|
||||
background: var(--coz-mg-secondary-hovered);
|
||||
}
|
||||
|
||||
&:active {
|
||||
background: var(--coz-mg-secondary-pressed);
|
||||
}
|
||||
|
||||
.semi-radio-extra {
|
||||
margin-top: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
.semi-radio-cardRadioGroup_checked {
|
||||
background: var(--coz-mg-hglt);
|
||||
border: 1px solid var(--coz-stroke-hglt);
|
||||
|
||||
&:hover {
|
||||
background: var(--coz-mg-hglt-hovered);
|
||||
}
|
||||
|
||||
&:active {
|
||||
background: var(--coz-mg-hglt-pressed);
|
||||
}
|
||||
}
|
||||
|
||||
.semi-radio-addon {
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
|
||||
.semi-form-field-label {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.semi-checkboxGroup-vertical {
|
||||
row-gap: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 { useMemo, type FC } from 'react';
|
||||
|
||||
import {
|
||||
type ContentProps,
|
||||
FooterBtnStatus,
|
||||
} from '@coze-data/knowledge-resource-processor-core';
|
||||
import { KnowledgeE2e } from '@coze-data/e2e';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import { Radio, RadioGroup } from '@coze-arch/coze-design';
|
||||
|
||||
import { ImageAnnotationType, ImageFileAddStep } from '../../types';
|
||||
import { type ImageFileAddStore } from '../../store';
|
||||
|
||||
import styles from './index.module.less';
|
||||
|
||||
export const ImageAnnotation: FC<ContentProps<ImageFileAddStore>> = props => {
|
||||
const { useStore, footer } = props;
|
||||
const setCurrentStep = useStore(state => state.setCurrentStep);
|
||||
const annotationType = useStore(state => state.annotationType);
|
||||
const setAnnotationType = useStore(state => state.setAnnotationType);
|
||||
|
||||
const buttonStatus = useMemo(() => {
|
||||
if (!annotationType) {
|
||||
return FooterBtnStatus.DISABLE;
|
||||
}
|
||||
return FooterBtnStatus.ENABLE;
|
||||
}, [annotationType]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className={styles['segment-radio-wrapper']}>
|
||||
<RadioGroup
|
||||
type="pureCard"
|
||||
onChange={e => {
|
||||
setAnnotationType(e.target.value as ImageAnnotationType);
|
||||
}}
|
||||
direction="vertical"
|
||||
value={annotationType}
|
||||
>
|
||||
<Radio
|
||||
data-testid={KnowledgeE2e.ImageAnnotationAiRadio}
|
||||
value={ImageAnnotationType.Auto}
|
||||
extra={I18n.t('knowledge_photo_009')}
|
||||
>
|
||||
{I18n.t('knowledge_photo_008')}
|
||||
</Radio>
|
||||
<Radio
|
||||
data-testid={KnowledgeE2e.ImageAnnotationManualRadio}
|
||||
value={ImageAnnotationType.Manual}
|
||||
extra={I18n.t('knowledge_photo_011')}
|
||||
>
|
||||
{I18n.t('knowledge_photo_010')}
|
||||
</Radio>
|
||||
</RadioGroup>
|
||||
</div>
|
||||
|
||||
{footer?.([
|
||||
{
|
||||
e2e: KnowledgeE2e.UploadUnitUpBtn,
|
||||
type: 'primary',
|
||||
theme: 'light',
|
||||
text: I18n.t('datasets_createFileModel_previousBtn'),
|
||||
onClick: () => setCurrentStep(ImageFileAddStep.Upload),
|
||||
},
|
||||
{
|
||||
e2e: KnowledgeE2e.UploadUnitNextBtn,
|
||||
type: 'hgltplus',
|
||||
theme: 'solid',
|
||||
text: I18n.t('datasets_createFileModel_NextBtn'),
|
||||
status: buttonStatus,
|
||||
onClick: () => {
|
||||
setCurrentStep(ImageFileAddStep.Process);
|
||||
},
|
||||
},
|
||||
])}
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,4 @@
|
||||
.footer-sub-tip {
|
||||
font-size: 12px;
|
||||
color: var(--light-usage-text-color-text-2, rgb(28 31 35 / 60%));
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* 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, type FC } from 'react';
|
||||
|
||||
import { useDataNavigate, useKnowledgeParams } from '@coze-data/knowledge-stores';
|
||||
import { type ContentProps } from '@coze-data/knowledge-resource-processor-core';
|
||||
import { getKnowledgeIDEQuery } from '@coze-data/knowledge-common-services';
|
||||
import { KnowledgeE2e } from '@coze-data/e2e';
|
||||
import { REPORT_EVENTS } from '@coze-arch/report-events';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import {
|
||||
CaptionType,
|
||||
DocumentSource,
|
||||
FormatType,
|
||||
} from '@coze-arch/bot-api/knowledge';
|
||||
|
||||
import { reportProcessDocumentFail } from '@/utils/common';
|
||||
import { getProcessingDescMsg } from '@/utils';
|
||||
import { useCreateDocument } from '@/hooks';
|
||||
import { UnitProgress } from '@/components';
|
||||
|
||||
import { ImageAnnotationType } from '../../types';
|
||||
import { type ImageFileAddStore } from '../../store';
|
||||
|
||||
import styles from './index.module.less';
|
||||
|
||||
export const ImageProcess: FC<ContentProps<ImageFileAddStore>> = props => {
|
||||
const { useStore, footer } = props;
|
||||
|
||||
const resourceNavigate = useDataNavigate();
|
||||
|
||||
const params = useKnowledgeParams();
|
||||
|
||||
const unitList = useStore(state => state.unitList);
|
||||
const annotationType = useStore(state => state.annotationType);
|
||||
const progressList = useStore(state => state.progressList);
|
||||
const createStatus = useStore(state => state.createStatus);
|
||||
|
||||
const createDocument = useCreateDocument(useStore, {
|
||||
onSuccess: docRes => {
|
||||
const documentInfos = docRes.document_infos ?? [];
|
||||
reportProcessDocumentFail(
|
||||
documentInfos,
|
||||
REPORT_EVENTS.KnowledgeProcessDocument,
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
createDocument({
|
||||
format_type: FormatType.Image,
|
||||
chunk_strategy: {
|
||||
caption_type:
|
||||
annotationType === ImageAnnotationType.Manual
|
||||
? CaptionType.Manual
|
||||
: CaptionType.Auto,
|
||||
},
|
||||
document_bases: unitList.map(item => ({
|
||||
name: item.name,
|
||||
source_info: {
|
||||
tos_uri: item.uri,
|
||||
document_source: DocumentSource.Document,
|
||||
},
|
||||
})),
|
||||
});
|
||||
}, []);
|
||||
return (
|
||||
<>
|
||||
<UnitProgress progressList={progressList} createStatus={createStatus} />
|
||||
{footer?.({
|
||||
btns: [
|
||||
{
|
||||
e2e: KnowledgeE2e.CreateUnitConfirmBtn,
|
||||
type: 'hgltplus',
|
||||
theme: 'solid',
|
||||
text: I18n.t('variable_reset_yes'),
|
||||
onClick: () => {
|
||||
const query = getKnowledgeIDEQuery() as Record<string, string>;
|
||||
resourceNavigate.toResource?.(
|
||||
'knowledge',
|
||||
params.datasetID,
|
||||
query,
|
||||
);
|
||||
},
|
||||
},
|
||||
],
|
||||
prefix: (
|
||||
<span className={styles['footer-sub-tip']}>
|
||||
{getProcessingDescMsg(createStatus)}
|
||||
</span>
|
||||
),
|
||||
})}
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* 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, type FC } from 'react';
|
||||
|
||||
import {
|
||||
type ContentProps,
|
||||
FooterBtnStatus,
|
||||
UploadStatus,
|
||||
type UnitItem,
|
||||
UnitType,
|
||||
} from '@coze-data/knowledge-resource-processor-core';
|
||||
import { KnowledgeE2e } from '@coze-data/e2e';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import { Toast } from '@coze-arch/coze-design';
|
||||
|
||||
import { UploadUnitFile, UploadUnitTable } from '@/components';
|
||||
|
||||
import { ImageFileAddStep } from '../../types';
|
||||
import { type ImageFileAddStore } from '../../store';
|
||||
import { useRetry } from './use-retry';
|
||||
|
||||
export const ImageUpload: FC<ContentProps<ImageFileAddStore>> = props => {
|
||||
const { useStore, footer } = props;
|
||||
const setCurrentStep = useStore(state => state.setCurrentStep);
|
||||
const unitList = useStore(state => state.unitList);
|
||||
const setUnitList = useStore(state => state.setUnitList);
|
||||
|
||||
const onRetry = useRetry({ unitList, setUnitList });
|
||||
|
||||
const buttonStatus = useMemo(() => {
|
||||
if (
|
||||
unitList.length === 0 ||
|
||||
unitList.some(
|
||||
unitItem =>
|
||||
unitItem.name.length === 0 ||
|
||||
unitItem.status !== UploadStatus.SUCCESS,
|
||||
)
|
||||
) {
|
||||
return FooterBtnStatus.DISABLE;
|
||||
}
|
||||
return FooterBtnStatus.ENABLE;
|
||||
}, [unitList]);
|
||||
|
||||
const hideUploadFile = false;
|
||||
const AddUnitMaxLimit = 300;
|
||||
|
||||
const handleClickNext = () => {
|
||||
setCurrentStep(ImageFileAddStep.Annotation);
|
||||
};
|
||||
|
||||
const handleUnitListUpdate = (data: UnitItem[]) => {
|
||||
const result = data;
|
||||
setUnitList(result);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<UploadUnitFile
|
||||
action=""
|
||||
accept={'.png,.jpg,.jpeg,.webp'}
|
||||
dragMainText={I18n.t('knowledge_photo_004')}
|
||||
dragSubText={I18n.t('knowledge_photo_005')}
|
||||
limit={AddUnitMaxLimit}
|
||||
unitList={unitList}
|
||||
multiple={AddUnitMaxLimit > 1}
|
||||
style={hideUploadFile ? { visibility: 'hidden', height: 0 } : undefined}
|
||||
setUnitList={handleUnitListUpdate}
|
||||
onFinish={handleUnitListUpdate}
|
||||
maxSizeMB={20}
|
||||
onSizeError={file =>
|
||||
Toast.error(
|
||||
I18n.t('photo-size-limit', {
|
||||
fileName: file.name,
|
||||
}),
|
||||
)
|
||||
}
|
||||
/>
|
||||
{unitList.length > 0 ? (
|
||||
<div className="mt-[25px] mb-[25px] overflow-y-auto">
|
||||
<UploadUnitTable
|
||||
type={UnitType.IMAGE_FILE}
|
||||
edit={true}
|
||||
unitList={unitList}
|
||||
onChange={setUnitList}
|
||||
onRetry={onRetry}
|
||||
/>
|
||||
</div>
|
||||
) : null}
|
||||
{footer?.([
|
||||
{
|
||||
e2e: KnowledgeE2e.UploadUnitNextBtn,
|
||||
type: 'hgltplus',
|
||||
theme: 'solid',
|
||||
text: I18n.t('datasets_createFileModel_NextBtn'),
|
||||
status: buttonStatus,
|
||||
onClick: handleClickNext,
|
||||
},
|
||||
])}
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -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 { DataNamespace, dataReporter } from '@coze-data/reporter';
|
||||
import { type UnitItem } from '@coze-data/knowledge-resource-processor-core';
|
||||
import { REPORT_EVENTS } from '@coze-arch/report-events';
|
||||
import { FileBizType } from '@coze-arch/bot-api/developer_api';
|
||||
import { DeveloperApi } from '@coze-arch/bot-api';
|
||||
|
||||
import { transformUnitList, getFileExtension, getBase64 } from '@/utils';
|
||||
|
||||
export const useRetry = (params: {
|
||||
unitList: UnitItem[];
|
||||
setUnitList: (unitList: UnitItem[]) => void;
|
||||
}) => {
|
||||
const { unitList, setUnitList } = params;
|
||||
|
||||
const onRetry = async (record: UnitItem, index: number) => {
|
||||
try {
|
||||
const { fileInstance } = record;
|
||||
if (fileInstance) {
|
||||
const { name } = fileInstance;
|
||||
const extension = getFileExtension(name);
|
||||
const base64 = await getBase64(fileInstance);
|
||||
const result = await DeveloperApi.UploadFile({
|
||||
file_head: {
|
||||
file_type: extension,
|
||||
biz_type: FileBizType.BIZ_BOT_DATASET,
|
||||
},
|
||||
data: base64,
|
||||
});
|
||||
|
||||
setUnitList(
|
||||
transformUnitList({
|
||||
unitList,
|
||||
data: result?.data,
|
||||
fileInstance,
|
||||
index,
|
||||
}),
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
const error = e as Error;
|
||||
dataReporter.errorEvent(DataNamespace.KNOWLEDGE, {
|
||||
eventName: REPORT_EVENTS.KnowledgeUploadFile,
|
||||
error,
|
||||
});
|
||||
}
|
||||
};
|
||||
return onRetry;
|
||||
};
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* 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 { devtools } from 'zustand/middleware';
|
||||
import { create } from 'zustand';
|
||||
import {
|
||||
CreateUnitStatus,
|
||||
type UploadBaseAction,
|
||||
type UploadBaseState,
|
||||
type ProgressItem,
|
||||
type UnitItem,
|
||||
} from '@coze-data/knowledge-resource-processor-core';
|
||||
|
||||
import { ImageAnnotationType, ImageFileAddStep } from '../types';
|
||||
|
||||
export type ImageFileAddStore = UploadBaseState<ImageFileAddStep> &
|
||||
UploadBaseAction<ImageFileAddStep> & {
|
||||
annotationType: ImageAnnotationType;
|
||||
setAnnotationType: (annotationType: ImageAnnotationType) => void;
|
||||
};
|
||||
|
||||
const storeStaticValues: Pick<
|
||||
ImageFileAddStore,
|
||||
| 'unitList'
|
||||
| 'currentStep'
|
||||
| 'annotationType'
|
||||
| 'createStatus'
|
||||
| 'progressList'
|
||||
> = {
|
||||
currentStep: ImageFileAddStep.Upload,
|
||||
unitList: [],
|
||||
annotationType: ImageAnnotationType.Auto,
|
||||
createStatus: CreateUnitStatus.UPLOAD_UNIT,
|
||||
progressList: [],
|
||||
};
|
||||
|
||||
export const createImageFileAddStore = () =>
|
||||
create<ImageFileAddStore>()(
|
||||
devtools((set, get, store) => ({
|
||||
...storeStaticValues,
|
||||
setCurrentStep: (currentStep: ImageFileAddStep) => {
|
||||
set({ currentStep });
|
||||
},
|
||||
setUnitList: (unitList: UnitItem[]) => {
|
||||
set({ unitList });
|
||||
},
|
||||
setAnnotationType: (annotationType: ImageAnnotationType) => {
|
||||
set({ annotationType });
|
||||
},
|
||||
setCreateStatus: (createStatus: CreateUnitStatus) => {
|
||||
set({ createStatus });
|
||||
},
|
||||
setProgressList: (progressList: ProgressItem[]) => {
|
||||
set({ progressList });
|
||||
},
|
||||
reset: () => {
|
||||
set(storeStaticValues);
|
||||
},
|
||||
})),
|
||||
);
|
||||
@@ -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 enum ImageFileAddStep {
|
||||
Upload = 0,
|
||||
Annotation,
|
||||
Process,
|
||||
}
|
||||
|
||||
export enum ImageAnnotationType {
|
||||
Auto = 'auto',
|
||||
Manual = 'manual',
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* 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 UploadConfig,
|
||||
type FooterControlsProps,
|
||||
} from '@coze-data/knowledge-resource-processor-core';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
|
||||
import { UploadFooter } from '@/components';
|
||||
|
||||
import { useTableCheck } from '../../hooks';
|
||||
import {
|
||||
type UploadTableAction,
|
||||
type UploadTableState,
|
||||
} from '../../../interface';
|
||||
import { type TableLocalContentProps } from './types';
|
||||
import { createTableCustomAddStore } from './store';
|
||||
import { TableCustomCreate } from './steps';
|
||||
import { TableCustomStep, TABLE_CUSTOM_WRAPPER_CLASS_NAME } from './constant';
|
||||
|
||||
export const TableCustomAddConfig: UploadConfig<
|
||||
TableCustomStep,
|
||||
UploadTableAction<TableCustomStep> & UploadTableState<TableCustomStep>
|
||||
> = {
|
||||
steps: [
|
||||
{
|
||||
content: (props: TableLocalContentProps) => (
|
||||
<TableCustomCreate
|
||||
useStore={props.useStore}
|
||||
footer={(controls: FooterControlsProps) => (
|
||||
<UploadFooter controls={controls} />
|
||||
)}
|
||||
checkStatus={undefined}
|
||||
/>
|
||||
),
|
||||
title: I18n.t('datasets_createFileModel_step2'),
|
||||
step: TableCustomStep.CREATE,
|
||||
},
|
||||
],
|
||||
createStore: createTableCustomAddStore,
|
||||
showStep: false,
|
||||
className: TABLE_CUSTOM_WRAPPER_CLASS_NAME,
|
||||
useUploadMount: store => useTableCheck(store),
|
||||
};
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/** table-custom add steps */
|
||||
export enum TableCustomStep {
|
||||
CREATE,
|
||||
}
|
||||
|
||||
export const TABLE_CUSTOM_WRAPPER_CLASS_NAME = 'table-custom-wrapper';
|
||||
@@ -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 { TableCustomAddConfig } from './config';
|
||||
@@ -0,0 +1,12 @@
|
||||
.create-table-wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
|
||||
.add-column-button {
|
||||
width: 114px;
|
||||
margin-top: 16px;
|
||||
}
|
||||
@@ -0,0 +1,168 @@
|
||||
/*
|
||||
* 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 React, { useEffect, useState } from 'react';
|
||||
|
||||
import { nanoid } from 'nanoid';
|
||||
import { useDataNavigate, useKnowledgeParams } from '@coze-data/knowledge-stores';
|
||||
import {
|
||||
FooterBtnStatus,
|
||||
type ContentProps,
|
||||
} from '@coze-data/knowledge-resource-processor-core';
|
||||
import { KnowledgeE2e } from '@coze-data/e2e';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import { Tooltip } from '@coze-arch/bot-semi';
|
||||
import { type DocTableColumn } from '@coze-arch/bot-api/memory';
|
||||
import { DocumentSource, FormatType } from '@coze-arch/bot-api/knowledge';
|
||||
import { IconCozPlus } from '@coze-arch/coze-design/icons';
|
||||
import { Button } from '@coze-arch/coze-design';
|
||||
|
||||
import { type AddCustomTableMeta } from '@/types';
|
||||
import { useCreateDocumentReq } from '@/services';
|
||||
import { getCustomStatus } from '@/features/knowledge-type/table/utils';
|
||||
import type {
|
||||
UploadTableState,
|
||||
UploadTableAction,
|
||||
} from '@/features/knowledge-type/table/interface';
|
||||
import { MAX_TABLE_META_COLUMN_LEN } from '@/constants';
|
||||
import { TableStructure, TableStructureTitle } from '@/components';
|
||||
|
||||
import styles from './create-v2.module.less';
|
||||
|
||||
function getCreateDocumentParams(
|
||||
metaData: AddCustomTableMeta & { key?: string; id?: string },
|
||||
isAppend: boolean,
|
||||
) {
|
||||
return {
|
||||
document_bases: [
|
||||
{
|
||||
name: '', // table custom传控
|
||||
source_info: {
|
||||
document_source: DocumentSource.Custom,
|
||||
},
|
||||
table_meta: metaData.map((meta, index) => ({
|
||||
column_name: meta.column_name,
|
||||
is_semantic: meta.is_semantic,
|
||||
column_type: meta.column_type,
|
||||
desc: meta.desc,
|
||||
sequence: index.toString(),
|
||||
})),
|
||||
},
|
||||
],
|
||||
format_type: FormatType.Table,
|
||||
is_append: isAppend,
|
||||
};
|
||||
}
|
||||
export const TableCustomCreate = <
|
||||
T extends UploadTableState<number> & UploadTableAction<number>,
|
||||
>(
|
||||
props: ContentProps<T>,
|
||||
) => {
|
||||
const { footer, useStore } = props;
|
||||
const params = useKnowledgeParams();
|
||||
|
||||
const resourceNavigate = useDataNavigate();
|
||||
|
||||
const { datasetID: knowledgeId } = params;
|
||||
const [footerStatus, setFooterStatus] = useState(FooterBtnStatus.ENABLE);
|
||||
const currentUuid = nanoid();
|
||||
const [metaData, setMetaData] = useState<AddCustomTableMeta>([
|
||||
{
|
||||
id: currentUuid,
|
||||
key: currentUuid,
|
||||
column_name: '',
|
||||
is_semantic: false,
|
||||
},
|
||||
]);
|
||||
const documentList = useStore(state => state.documentList) ?? [];
|
||||
const isAppend = documentList.length !== 0;
|
||||
|
||||
const createDocument = useCreateDocumentReq({
|
||||
onSuccess: () => {
|
||||
setFooterStatus(FooterBtnStatus.ENABLE);
|
||||
resourceNavigate.toResource?.('knowledge', knowledgeId);
|
||||
},
|
||||
onFail: () => {
|
||||
setFooterStatus(FooterBtnStatus.DISABLE);
|
||||
},
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (footerStatus !== FooterBtnStatus.LOADING) {
|
||||
setFooterStatus(getCustomStatus(metaData, 'toBeDelete')); // toBeDelete 待删
|
||||
}
|
||||
}, [metaData]);
|
||||
|
||||
const TooltipWrapper = ({ children }: { children: JSX.Element }) => {
|
||||
if (metaData.length >= MAX_TABLE_META_COLUMN_LEN) {
|
||||
return (
|
||||
<Tooltip trigger="hover" content={I18n.t('knowledge_1222_01')}>
|
||||
{children}
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
return <>{children}</>;
|
||||
};
|
||||
return (
|
||||
<div className={styles['create-table-wrapper']}>
|
||||
<TableStructureTitle />
|
||||
<TableStructure
|
||||
initValid
|
||||
isDragTable
|
||||
data={metaData}
|
||||
setData={setMetaData as (v: Array<DocTableColumn>) => void}
|
||||
/>
|
||||
<TooltipWrapper>
|
||||
<Button
|
||||
data-testid={KnowledgeE2e.TableCustomUAddFieldBtn}
|
||||
className={styles['add-column-button']}
|
||||
type="tertiary"
|
||||
disabled={metaData.length >= MAX_TABLE_META_COLUMN_LEN}
|
||||
onClick={() => {
|
||||
const curUuid = nanoid();
|
||||
setMetaData(
|
||||
metaData.concat({
|
||||
id: curUuid,
|
||||
key: curUuid,
|
||||
column_name: '',
|
||||
is_semantic: false,
|
||||
}),
|
||||
);
|
||||
}}
|
||||
block={false}
|
||||
icon={<IconCozPlus />}
|
||||
>
|
||||
{I18n.t('datasets_segment_tableStructure_add_field')}
|
||||
</Button>
|
||||
</TooltipWrapper>
|
||||
{footer
|
||||
? footer([
|
||||
{
|
||||
e2e: KnowledgeE2e.CreateUnitConfirmBtn,
|
||||
type: 'hgltplus',
|
||||
theme: 'solid',
|
||||
text: I18n.t('variable_reset_yes'),
|
||||
onClick: () => {
|
||||
setFooterStatus(FooterBtnStatus.LOADING);
|
||||
createDocument(getCreateDocumentParams(metaData, isAppend));
|
||||
},
|
||||
status: footerStatus,
|
||||
},
|
||||
])
|
||||
: null}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* 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 TableLocalContentProps } from '../../types';
|
||||
import { TableCustomCreate as TableCustomCreateV2 } from './create-v2';
|
||||
|
||||
/** 到时候要删掉 TableCustomCreateV1*/
|
||||
export const TableCustomCreate = (props: TableLocalContentProps) => (
|
||||
<TableCustomCreateV2 {...props} />
|
||||
);
|
||||
@@ -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 { TableCustomCreate } from './create';
|
||||
@@ -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 { TableCustomCreate } from './create';
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user