feat: manually mirror opencoze's code from bytedance

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

View File

@@ -0,0 +1,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;

View File

@@ -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;

View File

@@ -0,0 +1,5 @@
const { defineConfig } = require('@coze-arch/stylelint-config');
module.exports = defineConfig({
extends: [],
});

View File

@@ -0,0 +1,16 @@
# @coze-data/knowledge-resource-processor-core
> 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`

View File

@@ -0,0 +1,248 @@
/*
* 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, { useState } from 'react';
import { type StoreApi, type UseBoundStore, create } from 'zustand';
import { expect, describe, test } from 'vitest';
import { fireEvent, render, screen } from '@testing-library/react';
import { Button } from '@coze-arch/bot-semi';
import { type ProgressItem, type UnitItem } from '../src/types/common';
import {
type UploadBaseState,
type UploadBaseAction,
type UploadConfig,
} from '../src/protocol/base';
import { Upload } from '../src/main';
import { CheckedStatus, CreateUnitStatus } from '../src/constants/common';
import { type ContentProps } from '../src';
import { KnowledgeUploadStoreProvider } from '../src';
enum UploadStep {
UPLOAD = 0,
MANAGE = 1,
PROCESS = 2,
}
describe('test upload struct', () => {
const testConfig: UploadConfig<
UploadStep,
UploadBaseState<UploadStep> & UploadBaseAction<UploadStep>
> = {
steps: [
{
content: (
props: ContentProps<
UploadBaseState<UploadStep> & UploadBaseAction<UploadStep>
>,
) => {
const { useStore } = props;
// eslint-disable-next-line react-hooks/rules-of-hooks -- linter-disable-autofix
const { setCurrentStep, currentStep } = useStore();
return (
<>
Upload
<Button
onClick={() => {
console.log('debug there setCurrentStep');
setCurrentStep(currentStep + 1);
}}
>
next Step
</Button>
</>
);
},
title: 'test',
step: UploadStep.UPLOAD,
showThisStep: checkStatus => checkStatus === CheckedStatus.NO_FILE,
},
{
content: (
props: ContentProps<
UploadBaseState<UploadStep> & UploadBaseAction<UploadStep>
>,
) => {
const { useStore } = props;
// eslint-disable-next-line react-hooks/rules-of-hooks -- linter-disable-autofix
const { setCurrentStep, currentStep } = useStore();
return (
<>
MANAGE
<Button
onClick={() => {
setCurrentStep(currentStep - 1);
}}
>
prev Step
</Button>
<Button
onClick={() => {
setCurrentStep(currentStep + 1);
}}
>
next Step
</Button>
</>
);
},
title: 'test',
step: UploadStep.MANAGE,
},
{
content: (
props: ContentProps<
UploadBaseState<UploadStep> & UploadBaseAction<UploadStep>
>,
) => {
const { useStore } = props;
// eslint-disable-next-line react-hooks/rules-of-hooks -- linter-disable-autofix
const { setCurrentStep, currentStep } = useStore();
return (
<>
PROCESS
<Button
onClick={() => {
setCurrentStep(currentStep - 1);
}}
>
prev Step
</Button>
</>
);
},
title: 'test',
step: UploadStep.PROCESS,
},
],
createStore: () =>
create<UploadBaseState<UploadStep> & UploadBaseAction<UploadStep>>()(
set => ({
currentStep: UploadStep.MANAGE,
createStatus: CreateUnitStatus.UPLOAD_UNIT,
progressList: [],
unitList: [],
setCurrentStep: (step: UploadStep) =>
set({
currentStep: step,
}),
setCreateStatus: (createStatus: CreateUnitStatus) =>
set({
createStatus,
}),
setProgressList: (progressList: ProgressItem[]) =>
set({
progressList,
}),
setUnitList: (unitList: UnitItem[]) =>
set({
unitList,
}),
reset: () =>
set({
currentStep: UploadStep.MANAGE,
createStatus: CreateUnitStatus.UPLOAD_UNIT,
progressList: [],
unitList: [],
}),
}),
),
};
test('step render', async () => {
await render(
<KnowledgeUploadStoreProvider createStore={testConfig.createStore}>
<Upload config={testConfig} />
</KnowledgeUploadStoreProvider>,
);
const currentStepComp = await screen.queryByText('MANAGE');
expect(currentStepComp).toBeDefined();
});
test('no step comp', async () => {
testConfig.showStep = false;
await render(
<KnowledgeUploadStoreProvider createStore={testConfig.createStore}>
<Upload config={testConfig} />
</KnowledgeUploadStoreProvider>,
);
const currentStepComp = await screen.queryByText('MANAGE');
const stepComp = await screen.queryByText('1');
expect(stepComp).toBeNull();
expect(currentStepComp).toBeDefined();
});
test('next step', async () => {
testConfig.showStep = true;
await render(
<KnowledgeUploadStoreProvider createStore={testConfig.createStore}>
<Upload config={testConfig} />
</KnowledgeUploadStoreProvider>,
);
const nextButton = await screen.queryByText('next Step');
expect(nextButton).toBeDefined();
await fireEvent.click(nextButton as unknown as any);
const manageComp = await screen.queryByText('PROCESS');
expect(manageComp).toBeDefined();
});
test('skip step', async () => {
await render(
<KnowledgeUploadStoreProvider createStore={testConfig.createStore}>
<Upload config={testConfig} />
</KnowledgeUploadStoreProvider>,
);
const uploadStep = await screen.queryByText('Upload');
expect(uploadStep).toBeNull();
});
test('enter placeHolder & no skip', async () => {
testConfig.useUploadMount = (
store: UseBoundStore<
StoreApi<UploadBaseState<UploadStep> & UploadBaseAction<UploadStep>>
>,
) => {
// eslint-disable-next-line react-hooks/rules-of-hooks -- linter-disable-autofix
const [showPlaceHolder, setShowPlaceHolder] = useState(true);
const setCurrentStep = store(s => s.setCurrentStep);
setCurrentStep(UploadStep.UPLOAD);
if (!showPlaceHolder) {
return [undefined, CheckedStatus.NO_FILE];
}
return [
<Button
onClick={() => {
setShowPlaceHolder(false);
}}
>
skip
</Button>,
CheckedStatus.NO_FILE,
];
};
await render(
<KnowledgeUploadStoreProvider createStore={testConfig.createStore}>
<Upload config={testConfig} />
</KnowledgeUploadStoreProvider>,
);
const skipButton = await screen.queryByText('skip');
await fireEvent.click(skipButton as unknown as any);
const uploadStep = await screen.queryByText('Upload');
expect(uploadStep).not.toBeNull();
});
});

View File

@@ -0,0 +1,12 @@
{
"operationSettings": [
{
"operationName": "test:cov",
"outputFolderNames": ["coverage"]
},
{
"operationName": "ts-check",
"outputFolderNames": ["./dist"]
}
]
}

View File

@@ -0,0 +1,6 @@
{
"codecov": {
"coverage": 0,
"incrementCoverage": 0
}
}

View File

@@ -0,0 +1,9 @@
const { defineConfig } = require('@coze-arch/eslint-config');
module.exports = defineConfig({
packageRoot: __dirname,
preset: 'web',
rules: {
'@coze-arch/no-deep-relative-import': 'off',
},
});

View File

@@ -0,0 +1,49 @@
{
"name": "@coze-data/knowledge-resource-processor-core",
"version": "0.1.0",
"description": "knowledge resource processor core framework",
"license": "Apache-2.0",
"author": "rosefang.123@bytedance.com",
"maintainers": [],
"main": "src/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-semi": "workspace:*",
"@coze-arch/coze-design": "0.0.6-alpha.346d77",
"@coze-arch/pdfjs-shadow": "workspace:*",
"@coze-arch/report-events": "workspace:*",
"classnames": "^2.3.2",
"immer": "^10.0.3",
"zustand": "^4.4.7"
},
"devDependencies": {
"@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/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"
},
"// deps": "immer@^10.0.3 为脚本自动补齐,请勿改动"
}

View File

@@ -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.
*/
/** upload页面url上的type取值 */
export enum UnitType {
/** 文本格式:本地文档,上传 PDF, TXT, DOCX 格式的本地文件 */
TEXT_DOC = 'text_doc',
/** 文本格式:在线数据,自动获取在线网页内容 */
TEXT_URL = 'text_url',
/** 文本格式:在线数据,手动获取在线网页内容 */
TEXT_EXTENSION = 'text_extension',
/** 文本格式:自定义内容,支持创建&编辑 */
TEXT_CUSTOM = 'text_custom',
/** 文本格式:将 Notion 页面和数据库导入到知识库中 */
TEXT_NOTION = 'text_notion',
/** 文本格式 将 Google Docs 导入到知识库中 */
TEXT_GOOGLE_DRIVE = 'text_google_drive',
/** 文本格式:飞书文档 导入到知识库中 */
TEXT_FEISHU = 'text_feishu',
/** 文本格式:公众号 */
TEXT_WECHAT = 'text_wechat',
/** 文本格式Lark文档 导入到知识库中 */
TEXT_LARK = 'text_lark',
/** 表格格式本地文档上传Excel或者CSV格式的文档 */
TABLE_DOC = 'table_doc',
/** 表格格式API 获取JSON格式API内容 */
TABLE_API = 'table_api',
/** 表格格式:自定义 自定义内容,支持创建&编辑 */
TABLE_CUSTOM = 'table_custom',
/** 表格格式:将 Google Sheets 导入到知识库中 */
TABLE_GOOGLE_DRIVE = 'table_google_drive',
/** 表格格式:将 飞书表格 导入到知识库中 */
TABLE_FEISHU = 'table_feishu',
/** 表格格式:将 Lark表格 导入到知识库中 */
TABLE_LARK = 'table_lark',
/** 图片格式本地图片上传PNGJPGJPEG等格式图片 */
IMAGE_FILE = 'image_file',
/** 表格格式 */
TABLE = 'table',
/** 文本格式 */
TEXT = 'text',
/** 图片格式 */
IMAGE = 'image',
}
/**
* unit 操作类型
* upload页面支持以下几种方式
* - ADD 首次创建
* - UPDATE 更新数据
* - INCREMENTAL 增量数据
* - RESEGMENT 重新切片
*/
export enum OptType {
RESEGMENT = 'resegment',
ADD = 'add',
UPDATE = 'update',
INCREMENTAL = 'incremental',
}
/** footer 按钮状态 */
export enum FooterBtnStatus {
DISABLE = 'disable',
LOADING = 'loading',
ENABLE = 'enable',
}
/** create unit 全局过程状态。注意与UploadStatus的区别*/
export enum CreateUnitStatus {
UPLOAD_UNIT = 'uploadUnit',
GET_TASK_PROGRESS = 'getTaskProGress',
TASK_FINISH = 'taskFinish',
}
/**
* UploadStatus 是 upload-unit-file、upload-unit-table组件 上传文件过程的状态
* 原型来自 import { type FileItemStatus } from '@douyinfe/semi-foundation/lib/es/upload/foundation';
* FileItemStatus的写法有问题
*/
export enum UploadStatus {
SUCCESS = 'success',
UPLOAD_FAIL = 'uploadFail',
VALIDATE_FAIL = 'validateFail',
VALIDATING = 'validating',
UPLOADING = 'uploading',
WAIT = 'wait',
}
export enum FileNodeType {
FileNodeTypeFolder = 'folder',
FileNodeTypeDocument = 'document',
FileNodeTypeSheet = 'sheet',
}
export enum EntityStatus {
EntityStatusProcess = 'process',
EntityStatusSuccess = 'success',
EntityStatusFail = 'failure',
}
export enum CheckedStatus {
LOADING = 0,
NO_AUTH = 1,
NO_FILE = 2,
SIMPLE = 3,
HAD_SEGMENT_RULES = 4,
}

View File

@@ -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 {
UnitType,
OptType,
FooterBtnStatus,
CreateUnitStatus,
FileNodeType,
UploadStatus,
EntityStatus,
CheckedStatus,
} from './common';

View File

@@ -0,0 +1,50 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { createContext, type PropsWithChildren, type FC, useRef } from 'react';
import { type StoreApi, type UseBoundStore } from 'zustand';
interface StoreRef {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
knowledge?: UseBoundStore<StoreApi<any>> | undefined;
}
export const KnowledgeUploadStoreContext = createContext<{
storeRef: StoreRef;
}>({
storeRef: {
knowledge: undefined,
},
});
export const KnowledgeUploadStoreProvider: FC<
PropsWithChildren<{
createStore: () => StoreRef['knowledge'];
}>
> = ({ createStore, children }) => {
const store = useRef<StoreRef>({});
if (!store.current?.knowledge) {
store.current.knowledge = createStore();
}
return (
<KnowledgeUploadStoreContext.Provider value={{ storeRef: store.current }}>
{children}
</KnowledgeUploadStoreContext.Provider>
);
};

View File

@@ -0,0 +1,79 @@
/* stylelint-disable max-nesting-depth */
/* stylelint-disable no-descending-specificity */
.knowledge-steps {
display: flex;
flex-direction: column;
width: 100%;
height: 100%;
:global {
.semi-steps-horizontal {
display: flex;
justify-content: center;
width: 100%;
.semi-steps-item {
flex: none;
// padding-left: 12px;
.semi-steps-item-container {
align-items: center;
}
&.semi-steps-item-active {
.semi-steps-item-title {
color: var(--coz-fg-hglt);
}
.semi-steps-item-number-icon {
color: var(--coz-fg-hglt-plus);
}
}
.semi-steps-item-title {
max-width: 100%;
padding-right: 4px;
padding-bottom: 0;
font-weight: 500;
color: var(--coz-fg-secondary);
}
.semi-steps-item-icon {
height: 28px;
.semi-steps-item-number-icon {
width: 28px;
height: 28px;
}
}
}
.semi-steps-item-left .semi-steps-item-icon .semi-steps-item-number-icon{
font-size: 20px;
font-weight: 500;
}
.semi-steps-item-wait {
.semi-steps-item-left .semi-steps-item-icon .semi-steps-item-number-icon {
font-size: 20px;
font-weight: 500;
color: var(--coz-fg-secondary);
}
}
}
}
/** 成功后的icon */
.finish-icon {
display: flex;
align-items: center;
justify-content: center;
width: 28px;
height: 28px;
background-color: var(--coz-mg-hglt);
border-radius: 50%;
}
}

View File

@@ -0,0 +1,42 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export { Upload } from './main';
export type {
UploadBaseState,
UploadBaseAction,
GetUploadConfig,
UploadConfig,
} from './protocol';
export type {
ContentProps,
FooterControlsProps,
FooterControlProp,
FooterBtnProps,
ProgressItem,
UnitItem,
FooterPrefixType,
} from './types';
export {
UnitType,
OptType,
CreateUnitStatus,
FooterBtnStatus,
UploadStatus,
EntityStatus,
CheckedStatus,
} from './constants';
export { KnowledgeUploadStoreProvider } from './context';

View File

@@ -0,0 +1,116 @@
/*
* 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, { useContext, useEffect } from 'react';
import classNames from 'classnames';
import { REPORT_EVENTS } from '@coze-arch/report-events';
import { Steps } from '@coze-arch/bot-semi';
import { CustomError } from '@coze-arch/bot-error';
import { IconCozCheckMarkFill } from '@coze-arch/coze-design/icons';
import type {
UploadBaseState,
UploadBaseAction,
UploadConfig,
} from './protocol/base';
import { KnowledgeUploadStoreContext } from './context';
import styles from './index.module.less';
const BOT_DATA_REFACTOR_CLASS_NAME = 'data-refactor';
export const Upload = <
T extends number,
R extends UploadBaseState<T> & UploadBaseAction<T>,
>(props: {
config: UploadConfig<T, R>;
}) => {
useEffect(
() => () => {
// It is necessary, otherwise it will be wrong to re-enter the page status
reset();
},
[],
);
/** get store */
const storeContext = useContext(KnowledgeUploadStoreContext);
if (!storeContext.storeRef.knowledge) {
throw new CustomError(
REPORT_EVENTS.normalError,
'no knowledge store context',
);
}
const store = storeContext.storeRef.knowledge;
/** get steps */
const { config } = props;
if (!config) {
return null;
}
const { className, useUploadMount, showStep = true } = config;
const currentStep = store(state => state.currentStep);
const reset = store(state => state.reset);
// eslint-disable-next-line react-hooks/rules-of-hooks -- linter-disable-autofix
const [placeHolder, checkStatus] = useUploadMount?.(store) ?? [];
const showStepFlags = config.steps.map(
step => step.showThisStep?.(checkStatus) ?? true,
);
const steps = config.steps.filter((_v, index) => showStepFlags[index]);
// 数组过滤后steps通过索引取值有问题改为取对应step值关联item数据
const ContentComp = steps.find(item => item.step === currentStep)?.content;
if (placeHolder) {
return placeHolder;
}
return (
<div
className={classNames(
`${className} ${BOT_DATA_REFACTOR_CLASS_NAME}`,
styles['knowledge-steps'],
)}
>
{showStep ? (
<Steps
type="basic"
hasLine={false}
current={currentStep}
className="mb-[32px]"
>
{steps.map(step =>
currentStep > step.step ? (
<Steps.Step
key={step.title}
title={step.title}
icon={
<div className={styles['finish-icon']}>
<IconCozCheckMarkFill />
</div>
}
/>
) : (
<Steps.Step key={step.title} title={step.title} />
),
)}
</Steps>
) : null}
{ContentComp ? (
<ContentComp useStore={store} checkStatus={checkStatus} />
) : null}
</div>
);
};

View File

@@ -0,0 +1,68 @@
/*
* 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 StoreApi, type UseBoundStore } from 'zustand';
import type { ProgressItem, UnitItem, ContentProps } from '../types';
import {
type OptType,
type CreateUnitStatus,
type UnitType,
type CheckedStatus,
} from '../constants';
export interface UploadBaseState<T extends number | string> {
currentStep: T;
createStatus: CreateUnitStatus;
progressList: ProgressItem[];
unitList: UnitItem[];
}
export interface UploadBaseAction<T extends number | string> {
setCurrentStep: (step: T) => void;
setCreateStatus: (createStatus: CreateUnitStatus) => void;
setProgressList: (progressList: ProgressItem[]) => void;
setUnitList: (unitList: UnitItem[]) => void;
reset: () => void;
}
/** need to implement this function. */
export type GetUploadConfig<T, R> = (
type: UnitType,
opt: OptType,
) => UploadConfig<T, R> | null;
/** upload unified configuration */
export interface UploadConfig<T, R> {
steps: UploadConfigSteps<T, R>;
createStore: () => UseBoundStore<StoreApi<R>>;
className?: string;
/** Whether to show the top step, default true */
showStep?: boolean;
useUploadMount?: (
store: UseBoundStore<StoreApi<R>>,
) => [React.ReactElement | undefined, CheckedStatus | undefined] | null;
}
export type UploadConfigSteps<T, R> = Array<UploadConfigStep<T, R>>;
export interface UploadConfigStep<T, R> {
content?: (props: ContentProps<R>) => React.ReactElement;
showThisStep?: (checkStatus?: CheckedStatus) => boolean;
title: string;
step: T;
e2e?: string;
}

View File

@@ -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.
*/
export type {
UploadBaseState,
UploadBaseAction,
GetUploadConfig,
UploadConfig,
} from './base';

View File

@@ -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 {
type UpdateType,
type DocumentStatus,
type Int64,
type WebStatus,
type DocumentProgress,
} from '@coze-arch/bot-api/knowledge';
import type { FileNodeType, EntityStatus, UploadStatus } from '../constants';
interface CommonUnitItem {
key?: string;
percent: number | undefined;
status: UploadStatus | WebStatus | EntityStatus;
type: string; // unit类型url、doc、pdf等
uri: string; // 文件在tos上的的相对路径urlweb_url
url: string; // 文件的绝对url
name: string; // unit namewebpage title
validateMessage?: string;
// 外部传入的动态 errorMessage
dynamicErrorMessage?: string;
}
interface DocUnitItem {
size?: string; // 文件大小
docId?: string; // 文档IDupdate content时用到
fileInstance?: File | undefined;
uid?: string;
}
interface URLUnitItem {
updateInterval?: number; // URL使用更新频率
subpagesCount?: number;
updateType?: UpdateType;
webID?: string;
statusDescript?: string;
manualCrawlingConfig?: {
response: {
title: string;
url: string;
recordType: 'text' | 'list';
result: {
key: string;
name: string;
data: string | string[];
xPath: string;
type: 'text' | 'image' | 'link';
/**
* FIXME: 为了兼容性无法修改 data 结构,所以深度采集时会带上以下三个参数
*/
parentKey?: string;
titles?: string[];
urls?: string[];
}[];
};
/**
* 如果是深度采集得到的文档,则存在值,对应父文档 column 的key
*/
fromParentUnitColumnKey?: string;
};
manualCrawlingTableContent?: Record<string, string>[];
}
/**
* 三方数据连接器任务
*/
interface EntityUnitItem {
file_name?: string;
file_id?: string;
entity_id?: string;
tos_url?: string;
error_msg?: string;
file_node_type?: FileNodeType;
has_children_nodes?: boolean;
error_code?: Int64;
file_size?: string;
instance_id?: string;
tos_key?: string;
}
// TODO 这个 UnitItem 实现有问题,待优化
/** 除了 UnitItem其他外部都没有用到暂不导出*/
export type UnitItem = CommonUnitItem &
DocUnitItem &
URLUnitItem &
EntityUnitItem;
export interface ProgressItem extends DocumentProgress {
documentId: string | undefined;
progress: number;
uri: string;
name: string;
status: DocumentStatus;
statusDesc: string;
remainingTime: number;
}

View File

@@ -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.
*/
/**
* types由于多个位置都会使用避免循环依赖故提到最上层
*/
export type { UnitItem, ProgressItem } from './common';
export type {
ContentProps,
FooterControlsProps,
FooterControlProp,
FooterBtnProps,
FooterPrefixType,
} from './upload';

View File

@@ -0,0 +1,56 @@
/*
* 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';
/**
* types for upload
*/
import { type StoreApi, type UseBoundStore } from 'zustand';
import {
type OptType,
type FooterBtnStatus,
type CheckedStatus,
} from '../constants';
export interface ContentProps<T> {
useStore: UseBoundStore<StoreApi<T>>;
footer?: (
controls: FooterControlsProps | FooterBtnProps[],
) => React.ReactElement;
opt?: OptType;
checkStatus: CheckedStatus | undefined;
}
export type FooterControlsProps = FooterControlProp | FooterBtnProps[];
export type FooterPrefixType = React.ReactElement | string | undefined;
export interface FooterControlProp {
prefix: FooterPrefixType;
btns: FooterBtnProps[];
}
export interface FooterBtnProps {
e2e?: string;
onClick: () => void;
text: string;
status?: FooterBtnStatus;
theme?: 'solid' | 'borderless' | 'light';
type?: 'hgltplus' | 'primary' | 'secondary' | 'yellow' | 'red' | 'green';
disableHoverContent?: ReactNode;
}

View File

@@ -0,0 +1,20 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
declare module '*.less' {
const resource: { [key: string]: string };
export = resource;
}

View File

@@ -0,0 +1,34 @@
import { Meta } from "@storybook/blocks";
<Meta title="Hello world" />
<div className="sb-container">
<div className='sb-section-title'>
# Hello world
Hello world
</div>
</div>
<style>
{`
.sb-container {
margin-bottom: 48px;
}
.sb-section {
width: 100%;
display: flex;
flex-direction: row;
gap: 20px;
}
img {
object-fit: cover;
}
.sb-section-title {
margin-bottom: 32px;
}
`}
</style>

View File

@@ -0,0 +1,42 @@
{
"$schema": "https://json.schemastore.org/tsconfig",
"extends": "@coze-arch/ts-config/tsconfig.web.json",
"compilerOptions": {
"types": [],
"strictNullChecks": true,
"noImplicitAny": true,
"rootDir": "./src",
"outDir": "./dist",
"tsBuildInfoFile": "dist/tsconfig.build.tsbuildinfo"
},
"include": ["src"],
"references": [
{
"path": "../../../arch/bot-api/tsconfig.build.json"
},
{
"path": "../../../arch/bot-error/tsconfig.build.json"
},
{
"path": "../../../arch/pdfjs-shadow/tsconfig.build.json"
},
{
"path": "../../../arch/report-events/tsconfig.build.json"
},
{
"path": "../../../components/bot-semi/tsconfig.build.json"
},
{
"path": "../../../../config/eslint-config/tsconfig.build.json"
},
{
"path": "../../../../config/stylelint-config/tsconfig.build.json"
},
{
"path": "../../../../config/ts-config/tsconfig.build.json"
},
{
"path": "../../../../config/vitest-config/tsconfig.build.json"
}
]
}

View File

@@ -0,0 +1,15 @@
{
"$schema": "https://json.schemastore.org/tsconfig",
"compilerOptions": {
"composite": true
},
"references": [
{
"path": "./tsconfig.build.json"
},
{
"path": "./tsconfig.misc.json"
}
],
"exclude": ["**/*"]
}

View File

@@ -0,0 +1,18 @@
{
"extends": "@coze-arch/ts-config/tsconfig.web.json",
"$schema": "https://json.schemastore.org/tsconfig",
"include": ["__tests__", "stories", "vitest.config.ts", "tailwind.config.ts"],
"exclude": ["./dist"],
"references": [
{
"path": "./tsconfig.build.json"
}
],
"compilerOptions": {
"rootDir": "./",
"outDir": "./dist",
"types": ["vitest/globals"],
"strictNullChecks": true,
"noImplicitAny": true
}
}

View File

@@ -0,0 +1,33 @@
/*
* 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 { defineConfig } from '@coze-arch/vitest-config';
export default defineConfig(
{
dirname: __dirname,
preset: 'web',
test: {
coverage: {
all: true,
exclude: ['src/types', 'src/index.tsx'],
},
},
},
{
fixSemi: true,
},
);