feat: manually mirror opencoze's code from bytedance
Change-Id: I09a73aadda978ad9511264a756b2ce51f5761adf
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
const { defineConfig } = require('@coze-arch/stylelint-config');
|
||||
|
||||
module.exports = defineConfig({
|
||||
extends: [],
|
||||
});
|
||||
16
frontend/packages/studio/workspace/entry-adapter/README.md
Normal file
16
frontend/packages/studio/workspace/entry-adapter/README.md
Normal file
@@ -0,0 +1,16 @@
|
||||
# @coze-studio/workspace-adapter
|
||||
|
||||
> 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,64 @@
|
||||
{
|
||||
"name": "@coze-studio/workspace-adapter",
|
||||
"version": "0.0.1",
|
||||
"description": "工作空间菜单栏入口页面",
|
||||
"license": "Apache-2.0",
|
||||
"author": "duwenhan@bytedance.com",
|
||||
"maintainers": [],
|
||||
"exports": {
|
||||
"./develop": "./src/pages/develop/index.tsx",
|
||||
"./library": "./src/pages/library/index.tsx"
|
||||
},
|
||||
"main": "src/index.ts",
|
||||
"typesVersions": {
|
||||
"*": {
|
||||
"develop": [
|
||||
"./src/pages/develop/index.tsx"
|
||||
],
|
||||
"library": [
|
||||
"./src/pages/library/index.tsx"
|
||||
]
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"build": "exit 0",
|
||||
"dev": "exit 0",
|
||||
"lint": "eslint ./ --cache",
|
||||
"test": "vitest --run --passWithNoTests",
|
||||
"test:cov": "npm run test -- --coverage"
|
||||
},
|
||||
"dependencies": {
|
||||
"@coze-arch/bot-api": "workspace:*",
|
||||
"@coze-arch/bot-tea": "workspace:*",
|
||||
"@coze-arch/coze-design": "0.0.6-alpha.346d77",
|
||||
"@coze-arch/i18n": "workspace:*",
|
||||
"@coze-arch/idl": "workspace:*",
|
||||
"@coze-foundation/space-store-adapter": "workspace:*",
|
||||
"@coze-studio/workspace-base": "workspace:*",
|
||||
"classnames": "^2.3.2"
|
||||
},
|
||||
"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,401 @@
|
||||
/*
|
||||
* 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-per-function */
|
||||
/* eslint @coze-arch/max-line-per-function: ["error", {"max": 500}] */
|
||||
/* eslint-disable complexity */
|
||||
import { type FC, useEffect } from 'react';
|
||||
|
||||
import classNames from 'classnames';
|
||||
import {
|
||||
highlightFilterStyle,
|
||||
WorkspaceEmpty,
|
||||
DevelopCustomPublishStatus,
|
||||
isPublishStatus,
|
||||
isRecentOpen,
|
||||
isSearchScopeEnum,
|
||||
getPublishRequestParam,
|
||||
getTypeRequestParams,
|
||||
isEqualDefaultFilterParams,
|
||||
isFilterHighlight,
|
||||
CREATOR_FILTER_OPTIONS,
|
||||
FILTER_PARAMS_DEFAULT,
|
||||
STATUS_FILTER_OPTIONS,
|
||||
TYPE_FILTER_OPTIONS,
|
||||
BotCard,
|
||||
Content,
|
||||
Header,
|
||||
HeaderActions,
|
||||
HeaderTitle,
|
||||
Layout,
|
||||
SubHeader,
|
||||
SubHeaderFilters,
|
||||
SubHeaderSearch,
|
||||
useIntelligenceList,
|
||||
useIntelligenceActions,
|
||||
useCachedQueryParams,
|
||||
useGlobalEventListeners,
|
||||
type DevelopProps,
|
||||
useProjectCopyPolling,
|
||||
useCardActions,
|
||||
} from '@coze-studio/workspace-base/develop';
|
||||
import { useSpaceStore } from '@coze-foundation/space-store-adapter';
|
||||
import {
|
||||
IntelligenceType,
|
||||
search,
|
||||
SearchScope,
|
||||
} from '@coze-arch/idl/intelligence_api';
|
||||
import { I18n, type I18nKeysNoOptionsType } from '@coze-arch/i18n';
|
||||
import { IconCozLoading, IconCozPlus } from '@coze-arch/coze-design/icons';
|
||||
import {
|
||||
Button,
|
||||
IconButton,
|
||||
Search,
|
||||
Select,
|
||||
Spin,
|
||||
} from '@coze-arch/coze-design';
|
||||
import { EVENT_NAMES, sendTeaEvent } from '@coze-arch/bot-tea';
|
||||
import { SpaceType } from '@coze-arch/bot-api/developer_api';
|
||||
|
||||
export const Develop: FC<DevelopProps> = ({ spaceId }) => {
|
||||
const isPersonal = useSpaceStore(
|
||||
state => state.space.space_type === SpaceType.Personal,
|
||||
);
|
||||
|
||||
// 关键字检索 & 筛选
|
||||
const [filterParams, setFilterParams, debouncedSetSearchValue] =
|
||||
useCachedQueryParams();
|
||||
|
||||
const {
|
||||
isIntelligenceTypeFilterHighlight,
|
||||
isOwnerFilterHighlight,
|
||||
isPublishAndOpenFilterHighlight,
|
||||
} = isFilterHighlight(filterParams);
|
||||
|
||||
const {
|
||||
listResp: { loading, data, loadingMore, mutate, noMore, reload },
|
||||
containerRef,
|
||||
} = useIntelligenceList({
|
||||
params: {
|
||||
spaceId,
|
||||
searchValue: filterParams.searchValue,
|
||||
types: getTypeRequestParams({
|
||||
type: filterParams.searchType,
|
||||
}),
|
||||
hasPublished: getPublishRequestParam(filterParams.isPublish),
|
||||
recentlyOpen: filterParams.recentlyOpen,
|
||||
searchScope: filterParams.searchScope,
|
||||
// 固定值,来自历史代码
|
||||
orderBy: filterParams.isPublish
|
||||
? search.OrderBy.PublishTime
|
||||
: search.OrderBy.UpdateTime,
|
||||
},
|
||||
});
|
||||
|
||||
useGlobalEventListeners({ reload, spaceId });
|
||||
|
||||
useEffect(() => {
|
||||
setFilterParams(prev => ({
|
||||
...prev,
|
||||
searchValue: '',
|
||||
}));
|
||||
}, [spaceId]);
|
||||
|
||||
/**
|
||||
* report tea event
|
||||
*/
|
||||
useEffect(() => {
|
||||
sendTeaEvent(EVENT_NAMES.view_bot, { tab: 'my_bots' });
|
||||
}, []);
|
||||
|
||||
useProjectCopyPolling({
|
||||
listData: data?.list,
|
||||
spaceId,
|
||||
mutate,
|
||||
});
|
||||
|
||||
const { contextHolder: cardActionsContextHolder, actions: cardActions } =
|
||||
useCardActions({
|
||||
isPersonalSpace: isPersonal,
|
||||
mutate,
|
||||
});
|
||||
|
||||
/**
|
||||
* 创建 project
|
||||
*/
|
||||
const { contextHolder, actions } = useIntelligenceActions({
|
||||
spaceId,
|
||||
mutateList: mutate,
|
||||
reloadList: reload,
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
{contextHolder}
|
||||
{cardActionsContextHolder}
|
||||
<Layout>
|
||||
<Header>
|
||||
<HeaderTitle>
|
||||
<span>{I18n.t('workspace_develop')}</span>
|
||||
</HeaderTitle>
|
||||
<HeaderActions>
|
||||
<Button icon={<IconCozPlus />} onClick={actions.createIntelligence}>
|
||||
{I18n.t('workspace_create')}
|
||||
</Button>
|
||||
</HeaderActions>
|
||||
</Header>
|
||||
<SubHeader>
|
||||
<SubHeaderFilters>
|
||||
<Select
|
||||
className="min-w-[128px]"
|
||||
style={
|
||||
isIntelligenceTypeFilterHighlight ? highlightFilterStyle : {}
|
||||
}
|
||||
value={filterParams.searchType}
|
||||
onChange={val => {
|
||||
setFilterParams(prev => ({
|
||||
...prev,
|
||||
searchType:
|
||||
val as (typeof TYPE_FILTER_OPTIONS)[number]['value'],
|
||||
}));
|
||||
|
||||
// tea 埋点
|
||||
sendTeaEvent(EVENT_NAMES.workspace_action_front, {
|
||||
space_id: spaceId,
|
||||
space_type: isPersonal ? 'personal' : 'teamspace',
|
||||
tab_name: 'develop',
|
||||
action: 'filter',
|
||||
filter_type: 'types',
|
||||
filter_name: I18n.t(
|
||||
TYPE_FILTER_OPTIONS.find(opt => opt.value === val)
|
||||
?.labelI18NKey as I18nKeysNoOptionsType,
|
||||
),
|
||||
});
|
||||
}}
|
||||
>
|
||||
{TYPE_FILTER_OPTIONS.map(opt => (
|
||||
<Select.Option key={opt.value} value={opt.value}>
|
||||
{I18n.t(opt.labelI18NKey)}
|
||||
</Select.Option>
|
||||
))}
|
||||
</Select>
|
||||
{!isPersonal ? (
|
||||
/**
|
||||
* Search Scope
|
||||
* 所有人
|
||||
* 由我创建
|
||||
*/
|
||||
<Select
|
||||
className="min-w-[128px]"
|
||||
style={isOwnerFilterHighlight ? highlightFilterStyle : {}}
|
||||
value={filterParams.searchScope}
|
||||
onChange={val => {
|
||||
if (!isSearchScopeEnum(val)) {
|
||||
return;
|
||||
}
|
||||
setFilterParams(p => {
|
||||
if (val === SearchScope.CreateByMe && p.recentlyOpen) {
|
||||
return {
|
||||
...p,
|
||||
recentlyOpen: false,
|
||||
isPublish: DevelopCustomPublishStatus.All,
|
||||
searchScope: val,
|
||||
};
|
||||
}
|
||||
return {
|
||||
...p,
|
||||
searchScope: val,
|
||||
};
|
||||
});
|
||||
// tea 埋点
|
||||
sendTeaEvent(EVENT_NAMES.workspace_action_front, {
|
||||
space_id: spaceId,
|
||||
space_type: isPersonal ? 'personal' : 'teamspace',
|
||||
tab_name: 'develop',
|
||||
action: 'filter',
|
||||
filter_type: 'creators',
|
||||
filter_name: I18n.t(
|
||||
CREATOR_FILTER_OPTIONS.find(opt => opt.value === val)
|
||||
?.labelI18NKey as I18nKeysNoOptionsType,
|
||||
),
|
||||
});
|
||||
}}
|
||||
>
|
||||
{CREATOR_FILTER_OPTIONS.map(opt => (
|
||||
<Select.Option key={opt.value} value={opt.value}>
|
||||
{I18n.t(opt.labelI18NKey)}
|
||||
</Select.Option>
|
||||
))}
|
||||
</Select>
|
||||
) : null}
|
||||
{/*
|
||||
全部
|
||||
已发布
|
||||
最近打开
|
||||
*/}
|
||||
<Select
|
||||
className="min-w-[128px]"
|
||||
style={
|
||||
isPublishAndOpenFilterHighlight ? highlightFilterStyle : {}
|
||||
}
|
||||
value={
|
||||
filterParams.recentlyOpen
|
||||
? 'recentOpened'
|
||||
: filterParams.isPublish
|
||||
}
|
||||
onChange={val => {
|
||||
setFilterParams(p => ({
|
||||
...p,
|
||||
searchScope: SearchScope.All,
|
||||
recentlyOpen: isRecentOpen(val),
|
||||
isPublish: isPublishStatus(val)
|
||||
? val
|
||||
: DevelopCustomPublishStatus.All,
|
||||
}));
|
||||
// tea 埋点
|
||||
sendTeaEvent(EVENT_NAMES.workspace_action_front, {
|
||||
space_id: spaceId,
|
||||
space_type: isPersonal ? 'personal' : 'teamspace',
|
||||
tab_name: 'develop',
|
||||
action: 'filter',
|
||||
filter_type: 'status',
|
||||
filter_name: I18n.t(
|
||||
STATUS_FILTER_OPTIONS.find(opt => opt.value === val)
|
||||
?.labelI18NKey as I18nKeysNoOptionsType,
|
||||
),
|
||||
});
|
||||
}}
|
||||
>
|
||||
{STATUS_FILTER_OPTIONS.map(opt => (
|
||||
<Select.Option key={opt.value} value={opt.value}>
|
||||
{I18n.t(opt.labelI18NKey)}
|
||||
</Select.Option>
|
||||
))}
|
||||
</Select>
|
||||
</SubHeaderFilters>
|
||||
<SubHeaderSearch>
|
||||
<Search
|
||||
disabled={filterParams.recentlyOpen}
|
||||
showClear={true}
|
||||
className="w-[200px]"
|
||||
style={filterParams.searchValue ? highlightFilterStyle : {}}
|
||||
placeholder={I18n.t('workspace_develop_search_project')}
|
||||
value={filterParams.searchValue}
|
||||
onChange={val => {
|
||||
debouncedSetSearchValue(val);
|
||||
}}
|
||||
/>
|
||||
</SubHeaderSearch>
|
||||
</SubHeader>
|
||||
<Content ref={containerRef}>
|
||||
<Spin spinning={loading} wrapperClassName="w-full !h-[80vh]">
|
||||
{/* 有数据时 */}
|
||||
{data?.list.length ? (
|
||||
<div
|
||||
className={classNames(
|
||||
'grid grid-cols-3 auto-rows-min gap-[20px]',
|
||||
'[@media(min-width:1600px)]:grid-cols-4',
|
||||
)}
|
||||
>
|
||||
{data.list.map((project, index) => (
|
||||
<BotCard
|
||||
key={`${project.basic_info?.id}-${index}`}
|
||||
intelligenceInfo={project}
|
||||
onRetryCopy={cardActions.onRetryCopy}
|
||||
onCancelCopyAfterFailed={
|
||||
cardActions.onCancelCopyAfterFailed
|
||||
}
|
||||
onClick={() => {
|
||||
cardActions.onClick(project);
|
||||
}}
|
||||
onUpdateIntelligenceInfo={cardActions.onUpdate}
|
||||
onDelete={({ name, id, type }) => {
|
||||
if (type === IntelligenceType.Bot) {
|
||||
actions.deleteIntelligence({
|
||||
name,
|
||||
spaceId,
|
||||
agentId: id,
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (type === IntelligenceType.Project) {
|
||||
actions.deleteIntelligence({ name, projectId: id });
|
||||
return;
|
||||
}
|
||||
}}
|
||||
onCopyAgent={cardActions.onCopyAgent}
|
||||
onCopyProject={params => {
|
||||
cardActions.onCopyProject({
|
||||
initialValue: {
|
||||
project_id: params.id ?? '',
|
||||
to_space_id: spaceId,
|
||||
name: params.name ?? '',
|
||||
description: params.description,
|
||||
icon_uri: [
|
||||
{
|
||||
uid: params.icon_uri,
|
||||
url: params.icon_url ?? '',
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
}}
|
||||
timePrefixType={
|
||||
filterParams.recentlyOpen
|
||||
? 'recentOpen'
|
||||
: filterParams.isPublish
|
||||
? 'publish'
|
||||
: 'edit'
|
||||
}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
{!data?.list?.length && !loading ? (
|
||||
<WorkspaceEmpty
|
||||
onClear={() => {
|
||||
setFilterParams(FILTER_PARAMS_DEFAULT);
|
||||
}}
|
||||
hasFilter={
|
||||
!isEqualDefaultFilterParams({
|
||||
filterParams,
|
||||
})
|
||||
}
|
||||
/>
|
||||
) : null}
|
||||
|
||||
{/* 展示底部的 loading */}
|
||||
{data?.list.length && loadingMore ? (
|
||||
<div className="flex items-center justify-center w-full h-[38px] my-[20px] coz-fg-secondary text-[12px]">
|
||||
<IconButton
|
||||
icon={<IconCozLoading />}
|
||||
loading
|
||||
color="secondary"
|
||||
/>
|
||||
<div>{I18n.t('Loading')}...</div>
|
||||
</div>
|
||||
) : null}
|
||||
{/* 没有更多数据的时候要展示个占位 */}
|
||||
{noMore && data?.list.length ? (
|
||||
<div className="h-[38px] my-[20px]"></div>
|
||||
) : null}
|
||||
</Spin>
|
||||
</Content>
|
||||
</Layout>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* 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, useRef } from 'react';
|
||||
|
||||
import {
|
||||
BaseLibraryPage,
|
||||
useDatabaseConfig,
|
||||
usePluginConfig,
|
||||
useWorkflowConfig,
|
||||
usePromptConfig,
|
||||
useKnowledgeConfig,
|
||||
} from '@coze-studio/workspace-base/library';
|
||||
|
||||
export const LibraryPage: FC<{ spaceId: string }> = ({ spaceId }) => {
|
||||
const basePageRef = useRef<{ reloadList: () => void }>(null);
|
||||
const configCommonParams = {
|
||||
spaceId,
|
||||
reloadList: () => {
|
||||
basePageRef.current?.reloadList();
|
||||
},
|
||||
};
|
||||
const { config: pluginConfig, modals: pluginModals } =
|
||||
usePluginConfig(configCommonParams);
|
||||
const { config: workflowConfig, modals: workflowModals } =
|
||||
useWorkflowConfig(configCommonParams);
|
||||
const { config: knowledgeConfig, modals: knowledgeModals } =
|
||||
useKnowledgeConfig(configCommonParams);
|
||||
const { config: promptConfig, modals: promptModals } =
|
||||
usePromptConfig(configCommonParams);
|
||||
const { config: databaseConfig, modals: databaseModals } =
|
||||
useDatabaseConfig(configCommonParams);
|
||||
|
||||
return (
|
||||
<>
|
||||
<BaseLibraryPage
|
||||
spaceId={spaceId}
|
||||
ref={basePageRef}
|
||||
entityConfigs={[
|
||||
pluginConfig,
|
||||
workflowConfig,
|
||||
knowledgeConfig,
|
||||
promptConfig,
|
||||
databaseConfig,
|
||||
]}
|
||||
/>
|
||||
{pluginModals}
|
||||
{workflowModals}
|
||||
{promptModals}
|
||||
{databaseModals}
|
||||
{knowledgeModals}
|
||||
</>
|
||||
);
|
||||
};
|
||||
17
frontend/packages/studio/workspace/entry-adapter/src/typings.d.ts
vendored
Normal file
17
frontend/packages/studio/workspace/entry-adapter/src/typings.d.ts
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/// <reference types='@coze-arch/bot-typings' />
|
||||
@@ -0,0 +1,51 @@
|
||||
{
|
||||
"extends": "@coze-arch/ts-config/tsconfig.web.json",
|
||||
"$schema": "https://json.schemastore.org/tsconfig",
|
||||
"compilerOptions": {
|
||||
"outDir": "dist",
|
||||
"rootDir": "src",
|
||||
"jsx": "react-jsx",
|
||||
"lib": ["DOM", "ESNext"],
|
||||
"module": "ESNext",
|
||||
"target": "ES2020",
|
||||
"moduleResolution": "bundler",
|
||||
"tsBuildInfoFile": "dist/tsconfig.build.tsbuildinfo"
|
||||
},
|
||||
"include": ["src"],
|
||||
"exclude": ["node_modules", "dist"],
|
||||
"references": [
|
||||
{
|
||||
"path": "../../../arch/bot-api/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../../../arch/bot-tea/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../../../arch/bot-typings/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../../../arch/i18n/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../../../arch/idl/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"
|
||||
},
|
||||
{
|
||||
"path": "../entry-base/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../../../foundation/space-store-adapter/tsconfig.build.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/tsconfig",
|
||||
"exclude": ["**/*"],
|
||||
"compilerOptions": {
|
||||
"composite": true
|
||||
},
|
||||
"references": [
|
||||
{
|
||||
"path": "./tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "./tsconfig.misc.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"extends": "@coze-arch/ts-config/tsconfig.web.json",
|
||||
"$schema": "https://json.schemastore.org/tsconfig",
|
||||
"compilerOptions": {
|
||||
"rootDir": "./",
|
||||
"outDir": "./dist",
|
||||
"jsx": "react-jsx",
|
||||
"lib": ["DOM", "ESNext"],
|
||||
"module": "ESNext",
|
||||
"target": "ES2020",
|
||||
"moduleResolution": "bundler"
|
||||
},
|
||||
"include": ["__tests__", "vitest.config.ts", "stories"],
|
||||
"exclude": ["./dist"],
|
||||
"references": [
|
||||
{
|
||||
"path": "./tsconfig.build.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
import { defineConfig } from '@coze-arch/vitest-config';
|
||||
|
||||
export default defineConfig({
|
||||
dirname: __dirname,
|
||||
preset: 'web',
|
||||
});
|
||||
@@ -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: [],
|
||||
});
|
||||
16
frontend/packages/studio/workspace/entry-base/README.md
Normal file
16
frontend/packages/studio/workspace/entry-base/README.md
Normal file
@@ -0,0 +1,16 @@
|
||||
# @flow-studio/workspace
|
||||
|
||||
workspace 入口package
|
||||
|
||||
## 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: {},
|
||||
});
|
||||
126
frontend/packages/studio/workspace/entry-base/package.json
Normal file
126
frontend/packages/studio/workspace/entry-base/package.json
Normal file
@@ -0,0 +1,126 @@
|
||||
{
|
||||
"name": "@coze-studio/workspace-base",
|
||||
"version": "0.0.1",
|
||||
"description": "Coze 2.0 workspace业务能力入口",
|
||||
"license": "Apache-2.0",
|
||||
"author": "sunzhiyuan.evan@bytedance.com",
|
||||
"maintainers": [],
|
||||
"exports": {
|
||||
".": "./src/index.tsx",
|
||||
"./knowledge-upload": "./src/pages/knowledge-upload/index.tsx",
|
||||
"./knowledge-preview": "./src/pages/knowledge-preview/index.tsx",
|
||||
"./develop": "./src/pages/develop/index.tsx",
|
||||
"./library": "./src/pages/library/index.tsx"
|
||||
},
|
||||
"main": "src/index.tsx",
|
||||
"typesVersions": {
|
||||
"*": {
|
||||
".": [
|
||||
"./src/index.tsx"
|
||||
],
|
||||
"knowledge-upload": [
|
||||
"./src/pages/knowledge-upload/index.tsx"
|
||||
],
|
||||
"knowledge-preview": [
|
||||
"./src/pages/knowledge-preview/index.tsx"
|
||||
],
|
||||
"develop": [
|
||||
"./src/pages/develop/index.tsx"
|
||||
],
|
||||
"library": [
|
||||
"./src/pages/library/index.tsx"
|
||||
]
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"build": "exit 0",
|
||||
"lint": "eslint ./ --cache",
|
||||
"test": "vitest --run --passWithNoTests",
|
||||
"test:cov": "npm run test -- --coverage"
|
||||
},
|
||||
"dependencies": {
|
||||
"@coze-agent-ide/bot-plugin": "workspace:*",
|
||||
"@coze-agent-ide/space-bot": "workspace:*",
|
||||
"@coze-arch/bot-api": "workspace:*",
|
||||
"@coze-arch/bot-error": "workspace:*",
|
||||
"@coze-arch/bot-flags": "workspace:*",
|
||||
"@coze-arch/bot-semi": "workspace:*",
|
||||
"@coze-arch/bot-space-api": "workspace:*",
|
||||
"@coze-arch/bot-studio-store": "workspace:*",
|
||||
"@coze-arch/bot-tea": "workspace:*",
|
||||
"@coze-arch/bot-utils": "workspace:*",
|
||||
"@coze-arch/coze-design": "0.0.6-alpha.346d77",
|
||||
"@coze-arch/i18n": "workspace:*",
|
||||
"@coze-arch/idl": "workspace:*",
|
||||
"@coze-arch/logger": "workspace:*",
|
||||
"@coze-arch/report-events": "workspace:*",
|
||||
"@coze-common/biz-components": "workspace:*",
|
||||
"@coze-common/chat-area-utils": "workspace:*",
|
||||
"@coze-common/coze-mitt": "workspace:*",
|
||||
"@coze-common/prompt-kit": "workspace:*",
|
||||
"@coze-common/prompt-kit-adapter": "workspace:*",
|
||||
"@coze-community/components": "workspace:*",
|
||||
"@coze-data/database-v2": "workspace:*",
|
||||
"@coze-data/knowledge-ide-adapter": "workspace:*",
|
||||
"@coze-data/knowledge-ide-base": "workspace:*",
|
||||
"@coze-data/knowledge-modal-adapter": "workspace:*",
|
||||
"@coze-data/knowledge-resource-processor-adapter": "workspace:*",
|
||||
"@coze-data/knowledge-resource-processor-base": "workspace:*",
|
||||
"@coze-data/knowledge-resource-processor-core": "workspace:*",
|
||||
"@coze-data/knowledge-stores": "workspace:*",
|
||||
"@coze-data/utils": "workspace:*",
|
||||
"@coze-foundation/account-adapter": "workspace:*",
|
||||
"@coze-foundation/enterprise-store-adapter": "workspace:*",
|
||||
"@coze-foundation/layout": "workspace:*",
|
||||
"@coze-foundation/local-storage": "workspace:*",
|
||||
"@coze-studio/bot-plugin-store": "workspace:*",
|
||||
"@coze-studio/bot-utils": "workspace:*",
|
||||
"@coze-studio/components": "workspace:*",
|
||||
"@coze-studio/premium-components-adapter": "workspace:*",
|
||||
"@coze-studio/premium-store-adapter": "workspace:*",
|
||||
"@coze-studio/project-entity-adapter": "workspace:*",
|
||||
"@coze-studio/user-store": "workspace:*",
|
||||
"@coze-workflow/base": "workspace:*",
|
||||
"@coze-workflow/components": "workspace:*",
|
||||
"ahooks": "^3.7.8",
|
||||
"axios": "^1.4.0",
|
||||
"classnames": "^2.3.2",
|
||||
"immer": "^10.0.3",
|
||||
"lodash-es": "^4.17.21",
|
||||
"mitt": "^3.0.1",
|
||||
"qs": "^6.11.2"
|
||||
},
|
||||
"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:*",
|
||||
"@rsbuild/core": "1.1.13",
|
||||
"@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/node": "18.18.9",
|
||||
"@types/qs": "^6.9.7",
|
||||
"@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",
|
||||
"react-is": ">= 16.8.0",
|
||||
"react-router-dom": "^6.22.0",
|
||||
"styled-components": ">= 2",
|
||||
"stylelint": "^15.11.0",
|
||||
"typescript": "~5.8.2",
|
||||
"vite": "^4.3.9",
|
||||
"vite-plugin-svgr": "~3.3.0",
|
||||
"vitest": "~3.0.5",
|
||||
"webpack": "~5.91.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=18.2.0",
|
||||
"react-dom": ">=18.2.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { type FC } from 'react';
|
||||
|
||||
import { Avatar } from '@coze-arch/coze-design';
|
||||
|
||||
export interface CreatorProps {
|
||||
avatar?: string;
|
||||
name?: string;
|
||||
extra?: string;
|
||||
}
|
||||
|
||||
export const Creator: FC<CreatorProps> = ({ avatar, name, extra }) => (
|
||||
<div className="flex items-center gap-x-[4px] h-[16px] coz-fg-secondary text-[12px] leading-16px">
|
||||
{/* 社区版无多人协作功能,不展示资源所有者信息 */}
|
||||
{IS_OPEN_SOURCE ? null : (
|
||||
<>
|
||||
<Avatar className="w-[16px] h-[16px] flex-shrink-0" src={avatar} />
|
||||
<div className="text-nowrap">{name}</div>
|
||||
<div className="w-3px h-3px rounded-full bg-[var(--coz-fg-secondary)]" />
|
||||
</>
|
||||
)}
|
||||
<div className="text-ellipsis whitespace-nowrap overflow-hidden">
|
||||
{extra}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
* 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 HTMLAttributes, forwardRef } from 'react';
|
||||
|
||||
import classNames from 'classnames';
|
||||
|
||||
export type LayoutBaseProps = HTMLAttributes<HTMLDivElement>;
|
||||
|
||||
export const Layout = forwardRef<HTMLDivElement, LayoutBaseProps>(
|
||||
({ children, ...restProps }, ref) => (
|
||||
<div
|
||||
{...restProps}
|
||||
ref={ref}
|
||||
className={classNames(
|
||||
restProps.className,
|
||||
'min-h-[100%]',
|
||||
'flex flex-col gap-[16px]',
|
||||
'overflow-hidden',
|
||||
'px-[24px] pt-[24px]',
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
),
|
||||
);
|
||||
|
||||
export const Header = forwardRef<HTMLDivElement, LayoutBaseProps>(
|
||||
({ children, ...restProps }, ref) => (
|
||||
<div
|
||||
{...restProps}
|
||||
ref={ref}
|
||||
className={classNames(
|
||||
restProps.className,
|
||||
'flex-shrink-0',
|
||||
'w-full h-[32px]',
|
||||
'flex items-center justify-between',
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
),
|
||||
);
|
||||
|
||||
export const HeaderTitle = forwardRef<HTMLDivElement, LayoutBaseProps>(
|
||||
({ children, ...restProps }, ref) => (
|
||||
<div
|
||||
{...restProps}
|
||||
ref={ref}
|
||||
className={classNames(
|
||||
restProps.className,
|
||||
'text-[20px] font-[500]',
|
||||
'flex items-center gap-[8px]',
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
),
|
||||
);
|
||||
|
||||
export const HeaderActions = forwardRef<HTMLDivElement, LayoutBaseProps>(
|
||||
({ children, ...restProps }, ref) => (
|
||||
<div
|
||||
{...restProps}
|
||||
ref={ref}
|
||||
className={classNames(
|
||||
restProps.className,
|
||||
'flex items-center gap-[8px] ml-[32px]',
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
),
|
||||
);
|
||||
|
||||
export const SubHeader = forwardRef<HTMLDivElement, LayoutBaseProps>(
|
||||
({ children, ...restProps }, ref) => (
|
||||
<div
|
||||
{...restProps}
|
||||
ref={ref}
|
||||
className={classNames(
|
||||
restProps.className,
|
||||
'flex-shrink-0',
|
||||
'w-full h-[32px]',
|
||||
'flex items-center justify-between',
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
),
|
||||
);
|
||||
|
||||
export const SubHeaderFilters = forwardRef<HTMLDivElement, LayoutBaseProps>(
|
||||
({ children, ...restProps }, ref) => (
|
||||
<div
|
||||
{...restProps}
|
||||
ref={ref}
|
||||
className={classNames(restProps.className, 'flex items-center gap-[8px]')}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
),
|
||||
);
|
||||
|
||||
export const SubHeaderSearch = forwardRef<HTMLDivElement, LayoutBaseProps>(
|
||||
({ children, ...restProps }, ref) => (
|
||||
<div {...restProps} ref={ref} className={classNames(restProps.className)}>
|
||||
{children}
|
||||
</div>
|
||||
),
|
||||
);
|
||||
|
||||
export const Content = forwardRef<HTMLDivElement, LayoutBaseProps>(
|
||||
({ children, ...restProps }, ref) => (
|
||||
<div
|
||||
{...restProps}
|
||||
ref={ref}
|
||||
className={classNames(
|
||||
restProps.className,
|
||||
'flex-grow',
|
||||
'overflow-x-hidden overflow-y-auto',
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
),
|
||||
);
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* 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 { I18n } from '@coze-arch/i18n';
|
||||
import { IconCozEmpty, IconCozBroom } from '@coze-arch/coze-design/icons';
|
||||
import { Button } from '@coze-arch/coze-design';
|
||||
|
||||
interface WorkspaceEmptyProps {
|
||||
onClear?: () => void; // 清空按钮点击事件
|
||||
hasFilter?: boolean; // 是否有筛选项
|
||||
}
|
||||
|
||||
export const WorkspaceEmpty: FC<WorkspaceEmptyProps> = ({
|
||||
onClear,
|
||||
hasFilter = false,
|
||||
}) => (
|
||||
<div className="w-full h-full flex flex-col items-center pt-[120px]">
|
||||
<IconCozEmpty className="w-[48px] h-[48px] coz-fg-dim" />
|
||||
<div className="text-[16px] font-[500] leading-[22px] mt-[8px] mb-[16px] coz-fg-primary">
|
||||
{I18n.t(
|
||||
hasFilter ? 'library_empty_no_results_found_under' : 'search_not_found',
|
||||
)}
|
||||
</div>
|
||||
{hasFilter ? (
|
||||
<Button
|
||||
color="primary"
|
||||
icon={<IconCozBroom />}
|
||||
onClick={() => {
|
||||
onClear?.();
|
||||
}}
|
||||
>
|
||||
{I18n.t('library_empty_clear_filters')}
|
||||
</Button>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
@@ -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 const highlightFilterStyle = {
|
||||
border: '1px solid var(--semi-color-focus-border)',
|
||||
};
|
||||
46
frontend/packages/studio/workspace/entry-base/src/index.tsx
Normal file
46
frontend/packages/studio/workspace/entry-base/src/index.tsx
Normal file
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export { default as Plugin } from './pages/plugin';
|
||||
export { default as Tool } from './pages/tool';
|
||||
export { default as MocksetDetail } from './pages/mockset';
|
||||
export { default as MocksetList } from './pages/mockset-list';
|
||||
|
||||
// !Notice 禁止直接导出 knowledge 相关代码,避免首屏加载
|
||||
// export { default as KnowledgePreviewPage } from './pages/knowledge-preview';
|
||||
// export { default as KnowledgeUploadPage } from './pages/knowledge-upload';
|
||||
export { default as DatabaseDetailPage } from './pages/database';
|
||||
|
||||
export {
|
||||
resourceNavigate as pluginResourceNavigate,
|
||||
compareObjects,
|
||||
} from './utils';
|
||||
|
||||
// 公共组件
|
||||
export { Creator } from './components/creator';
|
||||
export {
|
||||
Content,
|
||||
Header,
|
||||
HeaderActions,
|
||||
HeaderTitle,
|
||||
Layout,
|
||||
SubHeader,
|
||||
SubHeaderFilters,
|
||||
} from './components/layout/list';
|
||||
export { WorkspaceEmpty } from './components/workspace-empty';
|
||||
|
||||
// constants
|
||||
export { highlightFilterStyle } from './constants/filter-style';
|
||||
@@ -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 { useNavigate, useParams } from 'react-router-dom';
|
||||
import React from 'react';
|
||||
|
||||
import qs from 'qs';
|
||||
import {
|
||||
KnowledgeParamsStoreProvider,
|
||||
type IKnowledgeParams,
|
||||
} from '@coze-data/knowledge-stores';
|
||||
import { DatabaseDetail } from '@coze-data/database-v2';
|
||||
|
||||
const DatabaseDetailPage = () => {
|
||||
const urlParams = useParams();
|
||||
const queryParams = new URLSearchParams(location.search);
|
||||
const navigate = useNavigate();
|
||||
const params: IKnowledgeParams = {
|
||||
botID: queryParams.get('bot_id') || '',
|
||||
pageMode: (queryParams.get('page_mode') ||
|
||||
'normal') as IKnowledgeParams['pageMode'],
|
||||
biz: (queryParams.get('biz') || 'library') as IKnowledgeParams['biz'],
|
||||
workflowID: queryParams.get('workflow_id') || '',
|
||||
agentID: queryParams.get('agent_id') || '',
|
||||
tableID: urlParams.table_id || '',
|
||||
initialTab: (queryParams.get('initial_tab') ||
|
||||
'structure') as IKnowledgeParams['initialTab'],
|
||||
};
|
||||
|
||||
return (
|
||||
<KnowledgeParamsStoreProvider
|
||||
params={params}
|
||||
resourceNavigate={{
|
||||
// eslint-disable-next-line max-params
|
||||
toResource: (resource, resourceID, query, opts) =>
|
||||
navigate(
|
||||
`/space/${params.spaceID}/${resource}/${resourceID}?${qs.stringify(query)}`,
|
||||
opts,
|
||||
),
|
||||
}}
|
||||
>
|
||||
<DatabaseDetail />
|
||||
</KnowledgeParamsStoreProvider>
|
||||
);
|
||||
};
|
||||
|
||||
export default DatabaseDetailPage;
|
||||
@@ -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 { useRequest } from 'ahooks';
|
||||
import {
|
||||
type IntelligenceBasicInfo,
|
||||
IntelligenceStatus,
|
||||
TaskAction,
|
||||
} from '@coze-arch/idl/intelligence_api';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import {
|
||||
IconCozLoading,
|
||||
IconCozWarningCircleFillPalette,
|
||||
} from '@coze-arch/coze-design/icons';
|
||||
import { Button, Space } from '@coze-arch/coze-design';
|
||||
import { intelligenceApi } from '@coze-arch/bot-api';
|
||||
|
||||
export interface CopyProcessMaskProps {
|
||||
intelligenceBasicInfo: IntelligenceBasicInfo;
|
||||
onRetry?: (status: IntelligenceStatus | undefined) => void;
|
||||
onCancelCopyAfterFailed?: (status: IntelligenceStatus | undefined) => void;
|
||||
}
|
||||
|
||||
export const CopyProcessMask: React.FC<CopyProcessMaskProps> = ({
|
||||
intelligenceBasicInfo,
|
||||
onRetry,
|
||||
onCancelCopyAfterFailed,
|
||||
}) => {
|
||||
const { status } = intelligenceBasicInfo;
|
||||
|
||||
const { run } = useRequest(
|
||||
async (action: TaskAction) => {
|
||||
const response = await intelligenceApi.ProcessEntityTask({
|
||||
entity_id: intelligenceBasicInfo.id,
|
||||
action,
|
||||
});
|
||||
return response.data?.entity_task?.entity_status;
|
||||
},
|
||||
{
|
||||
manual: true,
|
||||
onSuccess: (res, [action]) => {
|
||||
if (action === TaskAction.ProjectCopyCancel) {
|
||||
onCancelCopyAfterFailed?.(res);
|
||||
}
|
||||
if (action === TaskAction.ProjectCopyRetry) {
|
||||
onRetry?.(res);
|
||||
}
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
if (
|
||||
status !== IntelligenceStatus.CopyFailed &&
|
||||
status !== IntelligenceStatus.Copying
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="absolute w-full h-full flex items-center justify-center backdrop-blur-[6px] bg-[rgba(255,255,255,0.8)] left-0 top-0">
|
||||
<div className="coz-fg-secondary flex flex-col items-center gap-y-[12px]">
|
||||
{status === IntelligenceStatus.Copying ? (
|
||||
<>
|
||||
<IconCozLoading className="animate-spin" />
|
||||
<div>{I18n.t('project_ide_duplicate_loading')}</div>
|
||||
</>
|
||||
) : null}
|
||||
{status === IntelligenceStatus.CopyFailed ? (
|
||||
<>
|
||||
<IconCozWarningCircleFillPalette className="coz-fg-hglt-red" />
|
||||
<div>{I18n.t('develop_list_card_copy_fail')}</div>
|
||||
<Space spacing={8}>
|
||||
<Button
|
||||
color="primary"
|
||||
onClick={() => {
|
||||
run(TaskAction.ProjectCopyCancel);
|
||||
}}
|
||||
>
|
||||
{I18n.t('Cancel')}
|
||||
</Button>
|
||||
<Button
|
||||
color="hgltplus"
|
||||
onClick={() => {
|
||||
run(TaskAction.ProjectCopyRetry);
|
||||
}}
|
||||
>
|
||||
{I18n.t('project_ide_toast_duplicate_fail_retry')}
|
||||
</Button>
|
||||
</Space>
|
||||
</>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* 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 { Typography } from '@coze-arch/coze-design';
|
||||
|
||||
export interface DescriptionProps {
|
||||
description?: string;
|
||||
}
|
||||
|
||||
const Description: FC<DescriptionProps> = ({ description }) => (
|
||||
<Typography.Text
|
||||
className="coz-fg-secondary text-[14px] leading-[20px] break-words"
|
||||
ellipsis={{
|
||||
showTooltip: {
|
||||
opts: {
|
||||
theme: 'dark',
|
||||
content: (
|
||||
<Typography.Text
|
||||
className="break-words break-all coz-fg-white"
|
||||
onClick={e => e.stopPropagation()}
|
||||
ellipsis={{ showTooltip: false, rows: 16 }}
|
||||
>
|
||||
{description}
|
||||
</Typography.Text>
|
||||
),
|
||||
},
|
||||
type: 'tooltip',
|
||||
},
|
||||
rows: 2,
|
||||
}}
|
||||
>
|
||||
{description}
|
||||
</Typography.Text>
|
||||
);
|
||||
|
||||
export default Description;
|
||||
@@ -0,0 +1,399 @@
|
||||
/*
|
||||
* 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 @coze-arch/max-line-per-function: ["error", {"max": 500}] */
|
||||
/* eslint-disable complexity */
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { useMemo, useState, type ReactNode } from 'react';
|
||||
|
||||
import { cloneDeep } from 'lodash-es';
|
||||
import classNames from 'classnames';
|
||||
import { FavoriteIconBtn } from '@coze-community/components';
|
||||
import { ProductEntityType } from '@coze-arch/idl/product_api';
|
||||
import {
|
||||
type IntelligenceBasicInfo,
|
||||
type IntelligenceData,
|
||||
IntelligenceStatus,
|
||||
IntelligenceType,
|
||||
} from '@coze-arch/idl/intelligence_api';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import {
|
||||
IconCozCheckMarkCircleFillPalette,
|
||||
IconCozMore,
|
||||
IconCozStarFill,
|
||||
IconCozWarningCircleFill,
|
||||
} from '@coze-arch/coze-design/icons';
|
||||
import { Avatar, IconButton, Menu, Tooltip } from '@coze-arch/coze-design';
|
||||
import { formatDate, getFormatDateType } from '@coze-arch/bot-utils';
|
||||
import { useSpaceStore } from '@coze-arch/bot-studio-store';
|
||||
import { ConnectorDynamicStatus } from '@coze-arch/bot-api/developer_api';
|
||||
|
||||
import { Creator } from '@/components/creator';
|
||||
|
||||
import Name from './name';
|
||||
import { type AgentCopySuccessCallback, MenuCopyBot } from './menu-actions';
|
||||
import { IntelligenceTag } from './intelligence-tag';
|
||||
import Description from './description';
|
||||
import { CopyProcessMask } from './copy-process-mask';
|
||||
|
||||
export interface BotCardProps {
|
||||
intelligenceInfo: IntelligenceData;
|
||||
timePrefixType?: 'recentOpen' | 'publish' | 'edit';
|
||||
/**
|
||||
* 返回 true 时会打断默认的跳转行为
|
||||
*/
|
||||
onClick?: (() => true) | (() => void);
|
||||
onDelete?: (param: {
|
||||
name: string;
|
||||
id: string;
|
||||
type: IntelligenceType;
|
||||
}) => void;
|
||||
onCopyProject?: (basicInfo: IntelligenceBasicInfo) => void;
|
||||
onCopyAgent?: AgentCopySuccessCallback;
|
||||
onUpdateIntelligenceInfo: (info: IntelligenceData) => void;
|
||||
onRetryCopy: (basicInfo: IntelligenceBasicInfo) => void;
|
||||
onCancelCopyAfterFailed: (basicInfo: IntelligenceBasicInfo) => void;
|
||||
extraMenu?: ReactNode;
|
||||
headerExtra?: ReactNode;
|
||||
statusExtra?: ReactNode;
|
||||
actionsMenuVisible?: boolean;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line max-lines-per-function
|
||||
export const BotCard: React.FC<BotCardProps> = ({
|
||||
intelligenceInfo,
|
||||
timePrefixType,
|
||||
onClick,
|
||||
onDelete,
|
||||
onCopyProject,
|
||||
onCopyAgent,
|
||||
onUpdateIntelligenceInfo,
|
||||
onCancelCopyAfterFailed,
|
||||
onRetryCopy,
|
||||
extraMenu,
|
||||
actionsMenuVisible = true,
|
||||
headerExtra,
|
||||
statusExtra,
|
||||
}) => {
|
||||
const navigate = useNavigate();
|
||||
|
||||
const {
|
||||
basic_info,
|
||||
type,
|
||||
permission_info: { in_collaboration, can_delete } = {},
|
||||
publish_info: { publish_time, connectors, has_published } = {},
|
||||
other_info: { recently_open_time } = {},
|
||||
owner_info,
|
||||
favorite_info: { is_fav } = {},
|
||||
} = intelligenceInfo;
|
||||
|
||||
const { id, name, icon_url, space_id, description, update_time, status } =
|
||||
basic_info ?? {};
|
||||
|
||||
const hideOperation = useSpaceStore(store => store.space.hide_operation);
|
||||
|
||||
const renderPublishStatusIcon = () => {
|
||||
if (!has_published) {
|
||||
return null;
|
||||
}
|
||||
if (!connectors?.length) {
|
||||
return (
|
||||
<IconCozCheckMarkCircleFillPalette className="text-xxl coz-fg-hglt-green flex-shrink-0" />
|
||||
);
|
||||
}
|
||||
const isSomeConnectorsFailed = connectors.some(
|
||||
item => item?.connector_status !== ConnectorDynamicStatus.Normal,
|
||||
);
|
||||
if (isSomeConnectorsFailed) {
|
||||
return (
|
||||
<IconCozWarningCircleFill className="text-xxl coz-fg-hglt-yellow flex-shrink-0" />
|
||||
);
|
||||
}
|
||||
return (
|
||||
<IconCozCheckMarkCircleFillPalette className="text-xxl coz-fg-hglt-green flex-shrink-0" />
|
||||
);
|
||||
};
|
||||
|
||||
if (!id || !space_id) {
|
||||
// id 和 space id 对 bot 卡片来说是必须的,这里约束一下 ts 类型
|
||||
throw Error('No botID or no spaceID which are necessary');
|
||||
}
|
||||
|
||||
const isBanned = status === IntelligenceStatus.Banned;
|
||||
const isAgent = type === IntelligenceType.Bot;
|
||||
const isProject = type === IntelligenceType.Project;
|
||||
|
||||
const timePrefix = useMemo(() => {
|
||||
switch (timePrefixType) {
|
||||
case 'recentOpen':
|
||||
return I18n.t('develop_list_rank_tag_opened');
|
||||
case 'publish':
|
||||
return I18n.t('bot_list_rank_tag_published');
|
||||
case 'edit':
|
||||
return in_collaboration
|
||||
? I18n.t('devops_publish_multibranch_RecentSubmit')
|
||||
: I18n.t('bot_list_rank_tag_edited');
|
||||
default:
|
||||
}
|
||||
}, [timePrefixType, in_collaboration]);
|
||||
|
||||
const time = useMemo(() => {
|
||||
let timestamp: string | undefined;
|
||||
|
||||
switch (timePrefixType) {
|
||||
case 'recentOpen':
|
||||
timestamp = recently_open_time;
|
||||
break;
|
||||
case 'publish':
|
||||
timestamp = publish_time;
|
||||
break;
|
||||
case 'edit':
|
||||
timestamp = update_time;
|
||||
break;
|
||||
default:
|
||||
}
|
||||
|
||||
return formatDate(Number(timestamp), getFormatDateType(Number(timestamp)));
|
||||
}, [timePrefixType, publish_time, update_time, recently_open_time]);
|
||||
|
||||
// 是否展示 card 复层操作按钮
|
||||
const [showActions, setShowActions] = useState(false);
|
||||
// 是否展示 menu 菜单,这里有其他组件主动调用,需要受控
|
||||
const [showMenu, setShowMenu] = useState(false);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
className={classNames([
|
||||
'flex-grow h-[158px] min-w-[280px]',
|
||||
'rounded-[6px] border-solid border-[1px] ',
|
||||
'relative',
|
||||
'overflow-hidden transition duration-150 ease-out hover:shadow-[0_6px_8px_0_rgba(28,31,35,6%)]',
|
||||
'coz-stroke-primary coz-mg-card',
|
||||
])}
|
||||
>
|
||||
<div
|
||||
className="h-full w-full cursor-pointer flex flex-col gap-[12px] px-[16px] py-[16px]"
|
||||
onClick={() => {
|
||||
if (onClick?.()) {
|
||||
return;
|
||||
}
|
||||
if (isBanned) {
|
||||
return;
|
||||
}
|
||||
if (isAgent) {
|
||||
navigate(`/space/${space_id}/bot/${id}`);
|
||||
return;
|
||||
}
|
||||
if (isProject) {
|
||||
navigate(`/space/${space_id}/project-ide/${id}`);
|
||||
return;
|
||||
}
|
||||
}}
|
||||
onMouseEnter={() => {
|
||||
setShowActions(true);
|
||||
}}
|
||||
onMouseLeave={() => {
|
||||
setShowActions(false);
|
||||
}}
|
||||
data-testid="bot-list-page.bot-card"
|
||||
>
|
||||
{/* 展示迁移失败状态 icon */}
|
||||
{statusExtra}
|
||||
|
||||
{/* bot 基本信息 */}
|
||||
<div className="flex justify-between">
|
||||
<div className="flex flex-col gap-[4px] w-[calc(100%-76px)]">
|
||||
<div className="flex items-center gap-[4px]">
|
||||
<Name name={name} />
|
||||
{isBanned ? (
|
||||
// 如果失效了,高优展示失效 icon
|
||||
<IconCozWarningCircleFill className="text-xxl coz-fg-hglt-red flex-shrink-0" />
|
||||
) : (
|
||||
<>
|
||||
{/* 发布状态 icon */}
|
||||
{renderPublishStatusIcon()}
|
||||
{headerExtra}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<Description description={description} />
|
||||
</div>
|
||||
<Avatar
|
||||
className="w-[64px] h-[64px] rounded-[10px] flex-shrink-0 ml-[12px]"
|
||||
shape="square"
|
||||
src={icon_url}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* 项目/智能体 */}
|
||||
<IntelligenceTag intelligenceType={type} />
|
||||
|
||||
{/* bot 作者信息 */}
|
||||
{!!owner_info && (
|
||||
<Creator
|
||||
avatar={owner_info.avatar_url}
|
||||
name={owner_info.nickname}
|
||||
extra={`${timePrefix} ${time}`}
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* actions 浮层 action 浮层出现的时候下方有一个白色遮罩 */}
|
||||
{!hideOperation ? (
|
||||
<>
|
||||
{showActions && actionsMenuVisible ? (
|
||||
<div
|
||||
className="absolute bottom-[16px] right-[16px] w-[100px] h-[16px] "
|
||||
style={{
|
||||
background:
|
||||
'linear-gradient(90deg, rgba(255,255,255,0) 0%, rgba(255,255,255,1) 21.38%)',
|
||||
}}
|
||||
></div>
|
||||
) : null}
|
||||
<div
|
||||
className="absolute bottom-[16px] right-[16px] flex gap-[4px]"
|
||||
onClick={e => {
|
||||
// 阻止 click 事件冒泡到 card 最外层
|
||||
e.stopPropagation();
|
||||
}}
|
||||
>
|
||||
{showActions && actionsMenuVisible ? (
|
||||
<>
|
||||
{!isBanned ? (
|
||||
// 收藏 bot
|
||||
<FavoriteIconBtn
|
||||
useButton
|
||||
isVisible
|
||||
entityId={id}
|
||||
entityType={
|
||||
type === IntelligenceType.Bot
|
||||
? ProductEntityType.Bot
|
||||
: ProductEntityType.Project
|
||||
}
|
||||
isFavorite={is_fav}
|
||||
onFavoriteStateChange={isFav => {
|
||||
const clonedInfo = cloneDeep(intelligenceInfo);
|
||||
clonedInfo.favorite_info = {
|
||||
...(clonedInfo.favorite_info ?? {}),
|
||||
is_fav: isFav,
|
||||
};
|
||||
onUpdateIntelligenceInfo(clonedInfo);
|
||||
}}
|
||||
/>
|
||||
) : null}
|
||||
{/* 下拉菜单 */}
|
||||
<Menu
|
||||
keepDOM
|
||||
className="w-fit mt-4px mb-4px"
|
||||
position="bottomRight"
|
||||
trigger="custom"
|
||||
visible={showMenu}
|
||||
render={
|
||||
<Menu.SubMenu mode="menu">
|
||||
{/* 复制 bot */}
|
||||
{isAgent ? (
|
||||
<MenuCopyBot
|
||||
id={id}
|
||||
spaceID={space_id}
|
||||
disabled={isBanned}
|
||||
onCopySuccess={onCopyAgent}
|
||||
onClose={() => setShowActions(false)}
|
||||
/>
|
||||
) : null}
|
||||
{isProject ? (
|
||||
<Tooltip content={I18n.t('coze_copy_to_tips_1')}>
|
||||
<Menu.Item
|
||||
onClick={() => {
|
||||
if (!basic_info) {
|
||||
return;
|
||||
}
|
||||
onCopyProject?.(basic_info);
|
||||
}}
|
||||
data-testid="bot-card.copy"
|
||||
>
|
||||
{I18n.t('project_ide_create_duplicate')}
|
||||
</Menu.Item>
|
||||
</Tooltip>
|
||||
) : null}
|
||||
{extraMenu}
|
||||
{/* 删除 bot */}
|
||||
<Tooltip
|
||||
position="left"
|
||||
trigger={can_delete ? 'custom' : 'hover'}
|
||||
content={I18n.t(
|
||||
'project_delete_permission_tooltips',
|
||||
)}
|
||||
>
|
||||
<Menu.Item
|
||||
type="danger"
|
||||
disabled={!can_delete}
|
||||
onClick={() => {
|
||||
if (!name || !type) {
|
||||
return;
|
||||
}
|
||||
onDelete?.({ name, id, type });
|
||||
}}
|
||||
>
|
||||
<span>{I18n.t('Delete')}</span>
|
||||
</Menu.Item>
|
||||
</Tooltip>
|
||||
</Menu.SubMenu>
|
||||
}
|
||||
>
|
||||
<IconButton
|
||||
className="rotate-90"
|
||||
data-testid="bot-card.icon-more-button"
|
||||
color="primary"
|
||||
size="default"
|
||||
icon={<IconCozMore />}
|
||||
onClick={() => setShowMenu(true)}
|
||||
/>
|
||||
</Menu>
|
||||
</>
|
||||
) : is_fav && !isBanned ? (
|
||||
// 如果 bot 已经收藏了,非 hover 时展示 icon
|
||||
<IconButton
|
||||
className="!pt-[20px]"
|
||||
color="secondary"
|
||||
icon={<IconCozStarFill className="coz-fg-color-yellow" />}
|
||||
></IconButton>
|
||||
) : null}
|
||||
</div>
|
||||
</>
|
||||
) : null}
|
||||
</div>
|
||||
{basic_info ? (
|
||||
<CopyProcessMask
|
||||
intelligenceBasicInfo={basic_info}
|
||||
onRetry={changedStatus => {
|
||||
onRetryCopy({
|
||||
...basic_info,
|
||||
status: changedStatus,
|
||||
});
|
||||
}}
|
||||
onCancelCopyAfterFailed={changedStatus => {
|
||||
onCancelCopyAfterFailed({
|
||||
...basic_info,
|
||||
status: changedStatus,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
) : null}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* 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 { IntelligenceType } from '@coze-arch/idl/intelligence_api';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import { Tag } from '@coze-arch/coze-design';
|
||||
export interface IntelligenceTagProps {
|
||||
intelligenceType: IntelligenceType | undefined;
|
||||
}
|
||||
|
||||
export const IntelligenceTag: React.FC<IntelligenceTagProps> = ({
|
||||
intelligenceType,
|
||||
}) => {
|
||||
if (intelligenceType === IntelligenceType.Project) {
|
||||
return (
|
||||
<Tag color="brand" size="small" className="w-fit">
|
||||
{I18n.t('develop_list_card_tag_project')}
|
||||
</Tag>
|
||||
);
|
||||
}
|
||||
if (intelligenceType === IntelligenceType.Bot) {
|
||||
return (
|
||||
<Tag color="primary" size="small" className="w-fit">
|
||||
{I18n.t('develop_list_card_tag_agent')}
|
||||
</Tag>
|
||||
);
|
||||
}
|
||||
// 社区版暂不支持该功能
|
||||
if (intelligenceType === IntelligenceType.DouyinAvatarBot) {
|
||||
return (
|
||||
<Tag color="red" size="small" className="w-fit">
|
||||
{/* TODO: i18n 文案 */}
|
||||
抖音分身
|
||||
</Tag>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
@@ -0,0 +1,232 @@
|
||||
/*
|
||||
* 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 { useNavigate } from 'react-router-dom';
|
||||
import { useRef, type FC } from 'react';
|
||||
|
||||
import { cozeMitt } from '@coze-common/coze-mitt';
|
||||
import { logger } from '@coze-arch/logger';
|
||||
import { type User } from '@coze-arch/idl/intelligence_api';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import { IconCozWarningCircleFill } from '@coze-arch/coze-design/icons';
|
||||
import { Menu, Toast, Tooltip } from '@coze-arch/coze-design';
|
||||
import { EVENT_NAMES, sendTeaEvent } from '@coze-arch/bot-tea';
|
||||
import { useUIModal } from '@coze-arch/bot-semi';
|
||||
import { CustomError } from '@coze-arch/bot-error';
|
||||
import { DeveloperApi } from '@coze-arch/bot-api';
|
||||
|
||||
export interface MenuCommonProps {
|
||||
id: string;
|
||||
spaceID: string;
|
||||
}
|
||||
|
||||
export interface MenuAnalysisProps extends MenuCommonProps {
|
||||
disabled?: boolean;
|
||||
}
|
||||
|
||||
export type AgentCopySuccessCallback = (param: {
|
||||
templateId: string;
|
||||
id: string;
|
||||
name: string;
|
||||
ownerInfo: Required<User>;
|
||||
}) => void;
|
||||
|
||||
export const MenuAnalysis: FC<MenuAnalysisProps> = ({
|
||||
disabled,
|
||||
spaceID,
|
||||
id,
|
||||
}) => {
|
||||
const navigate = useNavigate();
|
||||
|
||||
return (
|
||||
<Menu.Item
|
||||
disabled={disabled}
|
||||
onClick={() => {
|
||||
navigate(`/space/${spaceID}/bot/${id}/analysis`);
|
||||
}}
|
||||
>
|
||||
{I18n.t('analytics_page_title')}
|
||||
</Menu.Item>
|
||||
);
|
||||
};
|
||||
|
||||
export interface MenuCopyBotProps extends MenuCommonProps {
|
||||
disabled?: boolean;
|
||||
name?: string;
|
||||
|
||||
onCopySuccess?: AgentCopySuccessCallback;
|
||||
onClose?: () => void;
|
||||
}
|
||||
|
||||
export const MenuCopyBot: FC<MenuCopyBotProps> = ({
|
||||
disabled,
|
||||
id,
|
||||
name,
|
||||
spaceID,
|
||||
onCopySuccess,
|
||||
onClose,
|
||||
}) => {
|
||||
const lock = useRef(false);
|
||||
|
||||
const copyBot = async () => {
|
||||
try {
|
||||
lock.current = true;
|
||||
const response = await DeveloperApi.DuplicateDraftBot({
|
||||
space_id: spaceID,
|
||||
bot_id: id,
|
||||
});
|
||||
Toast.success({
|
||||
content: I18n.t('bot_duplicateded_toast'),
|
||||
showClose: false,
|
||||
});
|
||||
const {
|
||||
bot_id = '',
|
||||
name: newBotName = '',
|
||||
user_info = {},
|
||||
} = response.data;
|
||||
const {
|
||||
id: userId = '',
|
||||
name: userName = '',
|
||||
avatar_url = '',
|
||||
user_unique_name = '',
|
||||
user_label = {},
|
||||
} = user_info;
|
||||
onCopySuccess?.({
|
||||
templateId: id,
|
||||
id: bot_id,
|
||||
name: newBotName,
|
||||
ownerInfo: {
|
||||
user_id: userId,
|
||||
nickname: userName,
|
||||
avatar_url,
|
||||
user_unique_name,
|
||||
user_label,
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
logger.error({
|
||||
error: new CustomError('copy bot', 'copy bot error'),
|
||||
});
|
||||
} finally {
|
||||
onClose?.();
|
||||
lock.current = false;
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Tooltip
|
||||
trigger={disabled ? 'custom' : 'hover'}
|
||||
content={I18n.t('coze_copy_to_tips_1')}
|
||||
>
|
||||
<Menu.Item
|
||||
data-testid="bot-card.copy"
|
||||
disabled={disabled}
|
||||
onClick={() => {
|
||||
if (lock.current) {
|
||||
return;
|
||||
}
|
||||
sendTeaEvent(EVENT_NAMES.bot_duplicate_click, {
|
||||
bot_type: 'team_bot',
|
||||
});
|
||||
// team bot header
|
||||
sendTeaEvent(EVENT_NAMES.bot_duplicate_click_front, {
|
||||
bot_type: 'team_bot',
|
||||
bot_id: id,
|
||||
bot_name: name,
|
||||
from: 'bots_card',
|
||||
source: 'bots_card',
|
||||
});
|
||||
copyBot();
|
||||
}}
|
||||
>
|
||||
{I18n.t('duplicate')}
|
||||
</Menu.Item>
|
||||
</Tooltip>
|
||||
);
|
||||
};
|
||||
|
||||
export interface MenuDeleteBotProps extends MenuCommonProps {
|
||||
onDeleteSuccess?: () => void;
|
||||
onClick?: () => void;
|
||||
onClose?: () => void;
|
||||
}
|
||||
|
||||
export const MenuDeleteBot: FC<MenuDeleteBotProps> = ({
|
||||
spaceID,
|
||||
id,
|
||||
onDeleteSuccess,
|
||||
onClick,
|
||||
onClose,
|
||||
}) => {
|
||||
const deleteBot = async () => {
|
||||
try {
|
||||
await DeveloperApi.DeleteDraftBot({
|
||||
space_id: spaceID,
|
||||
bot_id: id,
|
||||
});
|
||||
Toast.success({
|
||||
content: I18n.t('bot_deleted_toast'),
|
||||
showClose: false,
|
||||
});
|
||||
onDeleteSuccess?.();
|
||||
cozeMitt.emit('refreshFavList', {
|
||||
id,
|
||||
numDelta: -1,
|
||||
});
|
||||
} catch (error) {
|
||||
logger.error({
|
||||
error: new CustomError('delete bot', 'delete bot error'),
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const { open, close, modal } = useUIModal({
|
||||
type: 'info',
|
||||
title: I18n.t('bot_delete_confirm_title'),
|
||||
onOk: async () => await deleteBot(),
|
||||
okText: I18n.t('Delete'),
|
||||
cancelText: I18n.t('Cancel'),
|
||||
icon: <IconCozWarningCircleFill className="text-24px coz-fg-hglt-red" />,
|
||||
onCancel: () => {
|
||||
close();
|
||||
onClose?.();
|
||||
},
|
||||
okButtonProps: {
|
||||
type: 'danger',
|
||||
},
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
<Menu.Item
|
||||
type="danger"
|
||||
onClick={() => {
|
||||
open();
|
||||
onClick?.();
|
||||
}}
|
||||
>
|
||||
<span className="coz-fg-hglt-red">{I18n.t('Delete')}</span>
|
||||
</Menu.Item>
|
||||
{modal(
|
||||
<>
|
||||
{I18n.t('bot_list_delete_bot', {
|
||||
platform: FLOW_BRAND_NAME,
|
||||
})}
|
||||
</>,
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { type FC } from 'react';
|
||||
|
||||
import { I18n, type I18nKeysNoOptionsType } from '@coze-arch/i18n';
|
||||
import { IconCozWorkflow } from '@coze-arch/coze-design/icons';
|
||||
import { Typography } from '@coze-arch/coze-design';
|
||||
|
||||
export interface ModelInfoProps {
|
||||
showWorkflowMode?: boolean;
|
||||
name?: string;
|
||||
}
|
||||
|
||||
const ModelInfo: FC<ModelInfoProps> = ({ showWorkflowMode, name }) => (
|
||||
<Typography.Text
|
||||
className="text-[12px] leading-[16px] coz-fg-dim"
|
||||
ellipsis={{ showTooltip: { opts: { theme: 'dark' } }, rows: 1 }}
|
||||
>
|
||||
{showWorkflowMode ? (
|
||||
<div className="flex items-center">
|
||||
<IconCozWorkflow className="mr-[2px]" />
|
||||
{I18n.t('Workflow Mode' as I18nKeysNoOptionsType)}
|
||||
</div>
|
||||
) : (
|
||||
name
|
||||
)}
|
||||
</Typography.Text>
|
||||
);
|
||||
|
||||
export default ModelInfo;
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { type FC } from 'react';
|
||||
|
||||
import { Typography } from '@coze-arch/coze-design';
|
||||
|
||||
export interface NameProps {
|
||||
name?: string;
|
||||
}
|
||||
|
||||
const Name: FC<NameProps> = ({ name }) => (
|
||||
<Typography.Text
|
||||
className="text-[16px] font-[500] leading-[22px]"
|
||||
ellipsis={{
|
||||
showTooltip: {
|
||||
opts: {
|
||||
content: <span onClick={e => e.stopPropagation()}>{name}</span>,
|
||||
style: { wordBreak: 'break-word' },
|
||||
theme: 'dark',
|
||||
},
|
||||
type: 'tooltip',
|
||||
},
|
||||
rows: 1,
|
||||
}}
|
||||
>
|
||||
{name}
|
||||
</Typography.Text>
|
||||
);
|
||||
|
||||
export default Name;
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* 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 { SearchScope } from '@coze-arch/idl/intelligence_api';
|
||||
|
||||
import {
|
||||
DevelopCustomPublishStatus,
|
||||
DevelopCustomTypeStatus,
|
||||
type FilterParamsType,
|
||||
} from './type';
|
||||
export const CREATOR_FILTER_OPTIONS = [
|
||||
{
|
||||
value: SearchScope.All,
|
||||
labelI18NKey: 'bot_list_team',
|
||||
},
|
||||
{
|
||||
value: SearchScope.CreateByMe,
|
||||
labelI18NKey: 'bot_list_mine',
|
||||
},
|
||||
] as const;
|
||||
|
||||
export const STATUS_FILTER_OPTIONS = [
|
||||
{
|
||||
value: DevelopCustomPublishStatus.All,
|
||||
labelI18NKey: 'filter_all',
|
||||
},
|
||||
{
|
||||
value: DevelopCustomPublishStatus.Publish,
|
||||
labelI18NKey: 'Published_1',
|
||||
},
|
||||
{
|
||||
value: 'recentOpened',
|
||||
labelI18NKey: 'filter_develop_recent_opened',
|
||||
},
|
||||
] as const;
|
||||
|
||||
export const TYPE_FILTER_OPTIONS = [
|
||||
{
|
||||
value: DevelopCustomTypeStatus.All,
|
||||
labelI18NKey: 'filter_develop_all_types',
|
||||
},
|
||||
{
|
||||
value: DevelopCustomTypeStatus.Project,
|
||||
labelI18NKey: 'filter_develop_project',
|
||||
},
|
||||
{
|
||||
value: DevelopCustomTypeStatus.Agent,
|
||||
labelI18NKey: 'filter_develop_agent',
|
||||
},
|
||||
] as const;
|
||||
|
||||
export const FILTER_PARAMS_DEFAULT: FilterParamsType = {
|
||||
searchScope: SearchScope.All,
|
||||
searchValue: '',
|
||||
isPublish: DevelopCustomPublishStatus.All,
|
||||
searchType: DevelopCustomTypeStatus.All,
|
||||
recentlyOpen: undefined,
|
||||
};
|
||||
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
import { isObject, merge } from 'lodash-es';
|
||||
import { useDebounceFn, useUpdateEffect } from 'ahooks';
|
||||
import { safeJSONParse } from '@coze-agent-ide/space-bot/util';
|
||||
import { EVENT_NAMES, sendTeaEvent } from '@coze-arch/bot-tea';
|
||||
import { localStorageService } from '@coze-foundation/local-storage';
|
||||
|
||||
import { type FilterParamsType } from '../type';
|
||||
import { FILTER_PARAMS_DEFAULT } from '../develop-filter-options';
|
||||
|
||||
const isPersistentFilterParamsType = (
|
||||
params: unknown,
|
||||
): params is Partial<FilterParamsType> => isObject(params);
|
||||
|
||||
const getDefaultFilterParams = async () => {
|
||||
const localFilterParams = await localStorageService.getValueSync(
|
||||
'workspace-develop-filters',
|
||||
);
|
||||
if (!localFilterParams) {
|
||||
return FILTER_PARAMS_DEFAULT;
|
||||
}
|
||||
const parsedFilterParams = safeJSONParse(localFilterParams) as unknown;
|
||||
if (isPersistentFilterParamsType(parsedFilterParams)) {
|
||||
return merge({}, FILTER_PARAMS_DEFAULT, parsedFilterParams);
|
||||
}
|
||||
return FILTER_PARAMS_DEFAULT;
|
||||
};
|
||||
|
||||
export const useCachedQueryParams = () => {
|
||||
const [filterParams, setFilterParams] = useState<FilterParamsType>(
|
||||
FILTER_PARAMS_DEFAULT,
|
||||
);
|
||||
|
||||
useUpdateEffect(() => {
|
||||
/** 当筛选条件变化时,取合适的 key 存入本地 */
|
||||
const { searchScope, isPublish, recentlyOpen, searchType } = filterParams;
|
||||
localStorageService.setValue(
|
||||
'workspace-develop-filters',
|
||||
JSON.stringify({
|
||||
searchScope,
|
||||
isPublish,
|
||||
searchType,
|
||||
recentlyOpen,
|
||||
}),
|
||||
);
|
||||
}, [filterParams]);
|
||||
|
||||
useEffect(() => {
|
||||
/** 异步读取本地存储的筛选条件 */
|
||||
getDefaultFilterParams().then(filters => {
|
||||
setFilterParams(prev => merge({}, prev, filters));
|
||||
});
|
||||
}, []);
|
||||
|
||||
const debouncedSetSearchValue = useDebounceFn(
|
||||
(searchValue = '') => {
|
||||
setFilterParams(params => ({
|
||||
...params,
|
||||
searchValue,
|
||||
}));
|
||||
// tea 埋点
|
||||
sendTeaEvent(EVENT_NAMES.search_front, {
|
||||
full_url: location.href,
|
||||
source: 'develop',
|
||||
search_word: searchValue,
|
||||
});
|
||||
},
|
||||
{
|
||||
wait: 300,
|
||||
},
|
||||
);
|
||||
|
||||
return [filterParams, setFilterParams, debouncedSetSearchValue.run] as const;
|
||||
};
|
||||
@@ -0,0 +1,156 @@
|
||||
/*
|
||||
* 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 Dispatch, type SetStateAction } from 'react';
|
||||
|
||||
import { cloneDeep, merge } from 'lodash-es';
|
||||
import { produce } from 'immer';
|
||||
import { EVENT_NAMES, sendTeaEvent } from '@coze-arch/bot-tea';
|
||||
import {
|
||||
type IntelligenceBasicInfo,
|
||||
type IntelligenceData,
|
||||
} from '@coze-arch/bot-api/intelligence_api';
|
||||
import { useCopyProjectModal } from '@coze-studio/project-entity-adapter';
|
||||
|
||||
import { type DraftIntelligenceList } from '../type';
|
||||
import { produceCopyIntelligenceData } from '../page-utils/copy';
|
||||
import { type AgentCopySuccessCallback } from '../components/bot-card/menu-actions';
|
||||
|
||||
export const useCardActions = ({
|
||||
isPersonalSpace,
|
||||
mutate,
|
||||
}: {
|
||||
isPersonalSpace: boolean;
|
||||
mutate: Dispatch<SetStateAction<DraftIntelligenceList | undefined>>;
|
||||
}) => {
|
||||
const { modalContextHolder: copyModalHolder, openModal: onCopyProject } =
|
||||
useCopyProjectModal({
|
||||
onSuccess: ({ basicInfo, templateId, ownerInfo }) => {
|
||||
mutate(prev =>
|
||||
produce(prev, draft => {
|
||||
const target = draft?.list.find(
|
||||
intelligence => intelligence.basic_info?.id === templateId,
|
||||
);
|
||||
|
||||
if (!target) {
|
||||
return;
|
||||
}
|
||||
|
||||
const copyData = produceCopyIntelligenceData({
|
||||
originTemplateData: target,
|
||||
newCopyData: { basicInfo, ownerInfo },
|
||||
});
|
||||
draft?.list.unshift(copyData);
|
||||
}),
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
const mutateIntelligenceBasicInfo = (info: IntelligenceBasicInfo) => {
|
||||
mutate(prev =>
|
||||
produce(prev, draft => {
|
||||
const target = draft?.list.find(i => i.basic_info?.id === info.id);
|
||||
if (!target) {
|
||||
return;
|
||||
}
|
||||
target.basic_info = info;
|
||||
}),
|
||||
);
|
||||
};
|
||||
|
||||
const onCopyAgent: AgentCopySuccessCallback = param => {
|
||||
mutate(prev =>
|
||||
produce(prev, draft => {
|
||||
const target = draft?.list.find(
|
||||
intelligence => intelligence.basic_info?.id === param.templateId,
|
||||
);
|
||||
|
||||
if (!target) {
|
||||
return;
|
||||
}
|
||||
|
||||
const copyData = produceCopyIntelligenceData({
|
||||
originTemplateData: target,
|
||||
newCopyData: {
|
||||
ownerInfo: param.ownerInfo,
|
||||
basicInfo: merge({}, target.basic_info, {
|
||||
id: param.id,
|
||||
name: param.name,
|
||||
}),
|
||||
},
|
||||
});
|
||||
draft?.list.unshift(copyData);
|
||||
}),
|
||||
);
|
||||
};
|
||||
|
||||
const onDeleteMutate = ({ id }: { id: string }) => {
|
||||
mutate(prev =>
|
||||
produce(prev, draft => {
|
||||
if (!draft?.list) {
|
||||
return;
|
||||
}
|
||||
draft.list = draft.list.filter(item => item.basic_info?.id !== id);
|
||||
}),
|
||||
);
|
||||
};
|
||||
|
||||
const onUpdate = (intelligenceData: IntelligenceData) => {
|
||||
mutate(prev => {
|
||||
if (!prev) {
|
||||
return undefined;
|
||||
}
|
||||
const idx = prev.list.findIndex(
|
||||
item => item.basic_info?.id === intelligenceData.basic_info?.id,
|
||||
);
|
||||
|
||||
if (idx < 0) {
|
||||
return;
|
||||
}
|
||||
const clonedList = cloneDeep(prev?.list ?? []);
|
||||
clonedList.splice(idx, 1, intelligenceData);
|
||||
return {
|
||||
...prev,
|
||||
list: clonedList,
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
const onClick = (intelligenceData: IntelligenceData) => {
|
||||
sendTeaEvent(EVENT_NAMES.workspace_action_front, {
|
||||
space_id: intelligenceData.basic_info?.space_id ?? '',
|
||||
space_type: isPersonalSpace ? 'personal' : 'teamspace',
|
||||
tab_name: 'develop',
|
||||
action: 'click',
|
||||
id: intelligenceData.basic_info?.id,
|
||||
name: intelligenceData.basic_info?.name,
|
||||
type: 'agent',
|
||||
});
|
||||
};
|
||||
|
||||
return {
|
||||
contextHolder: <>{copyModalHolder}</>,
|
||||
actions: {
|
||||
onClick,
|
||||
onCopyProject,
|
||||
onCopyAgent,
|
||||
onUpdate,
|
||||
onRetryCopy: mutateIntelligenceBasicInfo,
|
||||
onCancelCopyAfterFailed: mutateIntelligenceBasicInfo,
|
||||
onDeleteMutate,
|
||||
},
|
||||
};
|
||||
};
|
||||
@@ -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 { useEffect } from 'react';
|
||||
|
||||
import {
|
||||
cozeMitt,
|
||||
type RefreshFavListParams,
|
||||
type CreateProjectByCopyTemplateFromSidebarParam,
|
||||
} from '@coze-common/coze-mitt';
|
||||
|
||||
export const useGlobalEventListeners = ({
|
||||
reload,
|
||||
spaceId,
|
||||
}: {
|
||||
reload: () => void;
|
||||
spaceId: string;
|
||||
}) => {
|
||||
useEffect(() => {
|
||||
const handlerRefreshFavList = (
|
||||
refreshFavListParams: RefreshFavListParams,
|
||||
) => {
|
||||
// 只在工作空间收藏取消收藏变化的时候刷新列表
|
||||
if (refreshFavListParams.emitPosition === 'favorites-list-item') {
|
||||
reload();
|
||||
}
|
||||
};
|
||||
const handleReloadConditionally = (
|
||||
eventParam: CreateProjectByCopyTemplateFromSidebarParam,
|
||||
) => {
|
||||
if (eventParam.toSpaceId !== spaceId) {
|
||||
return;
|
||||
}
|
||||
reload();
|
||||
};
|
||||
cozeMitt.on('refreshFavList', handlerRefreshFavList);
|
||||
cozeMitt.on(
|
||||
'createProjectByCopyTemplateFromSidebar',
|
||||
handleReloadConditionally,
|
||||
);
|
||||
return () => {
|
||||
cozeMitt.off('refreshFavList', handlerRefreshFavList);
|
||||
cozeMitt.off(
|
||||
'createProjectByCopyTemplateFromSidebar',
|
||||
handleReloadConditionally,
|
||||
);
|
||||
};
|
||||
}, []);
|
||||
};
|
||||
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
* 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 { useNavigate } from 'react-router-dom';
|
||||
import { type SetStateAction, type Dispatch, type ReactNode } from 'react';
|
||||
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import {
|
||||
type DeleteIntelligenceParam,
|
||||
useCreateProjectModal,
|
||||
useDeleteIntelligence,
|
||||
type CreateProjectHookProps,
|
||||
} from '@coze-studio/project-entity-adapter';
|
||||
import { cozeMitt } from '@coze-common/coze-mitt';
|
||||
import { Toast } from '@coze-arch/coze-design';
|
||||
|
||||
import { type DraftIntelligenceList } from '../type';
|
||||
|
||||
const showCreateSuccessToast = () => {
|
||||
Toast.success({
|
||||
content: I18n.t('creat_project_toast_success'),
|
||||
showClose: false,
|
||||
});
|
||||
};
|
||||
|
||||
export const useIntelligenceActions = ({
|
||||
spaceId,
|
||||
mutateList,
|
||||
reloadList,
|
||||
extraGuideButtonConfigs,
|
||||
}: {
|
||||
spaceId: string;
|
||||
reloadList: () => void;
|
||||
mutateList: Dispatch<SetStateAction<DraftIntelligenceList | undefined>>;
|
||||
extraGuideButtonConfigs?: CreateProjectHookProps['extraGuideButtonConfigs'];
|
||||
}): {
|
||||
contextHolder: ReactNode;
|
||||
actions: {
|
||||
createIntelligence: () => void;
|
||||
deleteIntelligence: (param: DeleteIntelligenceParam) => void;
|
||||
};
|
||||
} => {
|
||||
const navigate = useNavigate();
|
||||
|
||||
const navigateToProjectIDE = (inputProjectId: string) =>
|
||||
navigate(`/space/${spaceId}/project-ide/${inputProjectId}`);
|
||||
|
||||
const {
|
||||
modalContextHolder: createModalContextHolder,
|
||||
createProject: createIntelligence,
|
||||
} = useCreateProjectModal({
|
||||
selectSpace: false,
|
||||
bizCreateFrom: 'space',
|
||||
initialSpaceId: spaceId,
|
||||
extraGuideButtonConfigs,
|
||||
onCreateBotSuccess: botId => {
|
||||
if (botId) {
|
||||
navigate(`/space/${spaceId}/bot/${botId}`);
|
||||
}
|
||||
},
|
||||
onCreateProjectSuccess: ({ projectId }) => {
|
||||
showCreateSuccessToast();
|
||||
navigateToProjectIDE(projectId);
|
||||
},
|
||||
onCopyProjectTemplateSuccess: () => {
|
||||
reloadList();
|
||||
},
|
||||
});
|
||||
|
||||
const handleDeleteIntelligenceAndMutate = (mutateDeleteId: string) => {
|
||||
Toast.success({
|
||||
content: I18n.t('project_ide_toast_delete_success'),
|
||||
showClose: false,
|
||||
});
|
||||
cozeMitt.emit('refreshFavList', { id: mutateDeleteId, numDelta: -1 });
|
||||
mutateList(prev =>
|
||||
prev
|
||||
? {
|
||||
...prev,
|
||||
list: prev.list.filter(
|
||||
item => item.basic_info?.id !== mutateDeleteId,
|
||||
),
|
||||
}
|
||||
: undefined,
|
||||
);
|
||||
};
|
||||
|
||||
const { modalContextHolder: deleteModalContextHolder, deleteIntelligence } =
|
||||
useDeleteIntelligence({
|
||||
onDeleteAgentSuccess: agentParam => {
|
||||
handleDeleteIntelligenceAndMutate(agentParam.agentId);
|
||||
},
|
||||
onDeleteProjectSuccess: projectParam => {
|
||||
handleDeleteIntelligenceAndMutate(projectParam.projectId);
|
||||
},
|
||||
});
|
||||
|
||||
return {
|
||||
contextHolder: (
|
||||
<>
|
||||
{createModalContextHolder}
|
||||
{deleteModalContextHolder}
|
||||
</>
|
||||
),
|
||||
actions: {
|
||||
createIntelligence,
|
||||
deleteIntelligence,
|
||||
},
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,203 @@
|
||||
/*
|
||||
* 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, useRef } from 'react';
|
||||
|
||||
import axios, { type CancelTokenSource } from 'axios';
|
||||
import { type InfiniteScrollOptions } from 'ahooks/lib/useInfiniteScroll/types';
|
||||
import { useInfiniteScroll } from 'ahooks';
|
||||
import { withSlardarIdButton } from '@coze-studio/bot-utils';
|
||||
import {
|
||||
createReportEvent,
|
||||
REPORT_EVENTS as ReportEventNames,
|
||||
} from '@coze-arch/report-events';
|
||||
import { logger } from '@coze-arch/logger';
|
||||
import {
|
||||
IntelligenceStatus,
|
||||
type IntelligenceType,
|
||||
type search,
|
||||
type SearchScope,
|
||||
} from '@coze-arch/idl/intelligence_api';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import { Toast } from '@coze-arch/coze-design';
|
||||
import { intelligenceApi } from '@coze-arch/bot-api';
|
||||
|
||||
import { type DraftIntelligenceList } from '../type';
|
||||
|
||||
const pageSize = 24;
|
||||
|
||||
export interface FilterParamsType {
|
||||
types: IntelligenceType[];
|
||||
spaceId: string;
|
||||
hasPublished?: boolean;
|
||||
searchValue?: string;
|
||||
recentlyOpen?: boolean;
|
||||
searchScope?: SearchScope;
|
||||
orderBy: search.OrderBy;
|
||||
}
|
||||
|
||||
const getIntelligenceList = async (
|
||||
dataSource: DraftIntelligenceList | undefined,
|
||||
{
|
||||
spaceId,
|
||||
types,
|
||||
searchValue,
|
||||
hasPublished,
|
||||
recentlyOpen,
|
||||
searchScope,
|
||||
orderBy,
|
||||
}: FilterParamsType,
|
||||
cancelTokenRef: React.MutableRefObject<CancelTokenSource | null>,
|
||||
) => {
|
||||
// 每次新的请求,都重置一下 cancel token
|
||||
const source = axios.CancelToken.source();
|
||||
cancelTokenRef.current = source;
|
||||
const resp = await intelligenceApi
|
||||
.GetDraftIntelligenceList(
|
||||
{
|
||||
space_id: spaceId,
|
||||
name: searchValue,
|
||||
types,
|
||||
size: pageSize,
|
||||
has_published: hasPublished,
|
||||
recently_open: recentlyOpen,
|
||||
cursor_id: dataSource?.nextCursorId,
|
||||
search_scope: searchScope,
|
||||
// 固定值,来自历史代码
|
||||
order_by: orderBy,
|
||||
status: [
|
||||
IntelligenceStatus.Using,
|
||||
IntelligenceStatus.Banned,
|
||||
IntelligenceStatus.MoveFailed,
|
||||
],
|
||||
},
|
||||
{ cancelToken: source.token, __disableErrorToast: true },
|
||||
)
|
||||
.catch(e => {
|
||||
if (e.message !== 'canceled') {
|
||||
Toast.error({
|
||||
content: withSlardarIdButton(e.msg || e.message || I18n.t('error')),
|
||||
showClose: false,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
if (resp?.data) {
|
||||
return {
|
||||
list: resp.data.intelligences ?? [],
|
||||
hasMore: Boolean(resp.data.has_more),
|
||||
nextCursorId: resp.data.next_cursor_id,
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
list: [],
|
||||
hasMore: false,
|
||||
nextCursorId: undefined,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
const buildBotLogger = logger.createLoggerWith({
|
||||
ctx: {
|
||||
namespace: 'bot_list',
|
||||
},
|
||||
});
|
||||
|
||||
const getBotListReportEvent = createReportEvent({
|
||||
eventName: ReportEventNames.getBotList,
|
||||
logger: buildBotLogger,
|
||||
});
|
||||
|
||||
export const useIntelligenceList = ({
|
||||
params: {
|
||||
spaceId,
|
||||
types,
|
||||
searchValue,
|
||||
hasPublished,
|
||||
recentlyOpen,
|
||||
searchScope,
|
||||
orderBy,
|
||||
},
|
||||
onBefore,
|
||||
onSuccess,
|
||||
onError,
|
||||
}: {
|
||||
params: FilterParamsType;
|
||||
} & Pick<
|
||||
InfiniteScrollOptions<DraftIntelligenceList>,
|
||||
'onBefore' | 'onSuccess' | 'onError'
|
||||
>) => {
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
const cancelTokenRef = useRef<CancelTokenSource | null>(null);
|
||||
|
||||
const listResp = useInfiniteScroll<DraftIntelligenceList>(
|
||||
async dataSource =>
|
||||
await getIntelligenceList(
|
||||
dataSource,
|
||||
{
|
||||
spaceId,
|
||||
types,
|
||||
searchValue,
|
||||
hasPublished,
|
||||
recentlyOpen,
|
||||
searchScope,
|
||||
orderBy,
|
||||
},
|
||||
cancelTokenRef,
|
||||
),
|
||||
{
|
||||
target: containerRef,
|
||||
reloadDeps: [
|
||||
types.join(','),
|
||||
searchValue,
|
||||
hasPublished,
|
||||
recentlyOpen,
|
||||
searchScope,
|
||||
orderBy,
|
||||
spaceId,
|
||||
],
|
||||
isNoMore: dataSource => !dataSource?.hasMore,
|
||||
onBefore: () => {
|
||||
if (listResp.loadingMore || listResp.loading) {
|
||||
cancelTokenRef.current?.cancel();
|
||||
}
|
||||
getBotListReportEvent.start();
|
||||
onBefore?.();
|
||||
},
|
||||
onSuccess: (...res) => {
|
||||
getBotListReportEvent.success();
|
||||
onSuccess?.(...res);
|
||||
},
|
||||
onError: e => {
|
||||
getBotListReportEvent.error({
|
||||
error: e,
|
||||
reason: e.message,
|
||||
});
|
||||
onError?.(e);
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
useEffect(
|
||||
() => () => {
|
||||
// 取消正在请求的接口
|
||||
cancelTokenRef.current?.cancel();
|
||||
},
|
||||
[spaceId],
|
||||
);
|
||||
|
||||
return { listResp, containerRef, cancelTokenRef };
|
||||
};
|
||||
@@ -0,0 +1,162 @@
|
||||
/*
|
||||
* 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 { useNavigate } from 'react-router-dom';
|
||||
import { type Dispatch, type SetStateAction, useEffect } from 'react';
|
||||
|
||||
import { produce } from 'immer';
|
||||
import {
|
||||
type IntelligenceData,
|
||||
IntelligenceStatus,
|
||||
IntelligenceType,
|
||||
TaskAction,
|
||||
} from '@coze-arch/idl/intelligence_api';
|
||||
import { CopyTaskType } from '@coze-arch/idl';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import { Button, Toast } from '@coze-arch/coze-design';
|
||||
import { intelligenceApi } from '@coze-arch/bot-api';
|
||||
|
||||
import { type DraftIntelligenceList } from '../type';
|
||||
import {
|
||||
intelligenceCopyTaskPollingService,
|
||||
type PollCopyTaskEvent,
|
||||
} from '../service/intelligence-copy-task-polling-service';
|
||||
|
||||
const registerCopyTaskPolling = (data: IntelligenceData[]) => {
|
||||
intelligenceCopyTaskPollingService.registerPolling(
|
||||
data
|
||||
.filter(
|
||||
intelligence =>
|
||||
intelligence.type === IntelligenceType.Project &&
|
||||
intelligence.basic_info?.status === IntelligenceStatus.Copying,
|
||||
)
|
||||
.map(i => ({
|
||||
entity_id: i.basic_info?.id,
|
||||
task_type: CopyTaskType.ProjectCopy,
|
||||
})),
|
||||
);
|
||||
};
|
||||
|
||||
export const useProjectCopyPolling = ({
|
||||
spaceId,
|
||||
listData,
|
||||
mutate,
|
||||
}: {
|
||||
spaceId: string;
|
||||
mutate: Dispatch<SetStateAction<DraftIntelligenceList | undefined>>;
|
||||
listData?: IntelligenceData[];
|
||||
}) => {
|
||||
const navigate = useNavigate();
|
||||
const navigateToProjectIDE = (inputProjectId: string) =>
|
||||
navigate(`/space/${spaceId}/project-ide/${inputProjectId}`);
|
||||
|
||||
useEffect(() => {
|
||||
if (listData) {
|
||||
registerCopyTaskPolling(listData);
|
||||
}
|
||||
}, [listData]);
|
||||
|
||||
useEffect(() => {
|
||||
const onTaskUpdate = (list: PollCopyTaskEvent['onCopyTaskUpdate']) => {
|
||||
mutate(prev =>
|
||||
produce(prev, draft => {
|
||||
list.forEach(task => {
|
||||
const target = draft?.list.find(
|
||||
intelligence => intelligence.basic_info?.id === task.entity_id,
|
||||
);
|
||||
if (!target || !target.basic_info) {
|
||||
return;
|
||||
}
|
||||
target.basic_info.status = task.entity_status;
|
||||
});
|
||||
}),
|
||||
);
|
||||
// 需要重新封装下
|
||||
list.forEach(item => {
|
||||
if (item.entity_status === IntelligenceStatus.Using) {
|
||||
const successToastId = Toast.success({
|
||||
content: (
|
||||
<>
|
||||
{I18n.t('project_ide_toast_duplicate_success')}
|
||||
<Button
|
||||
className="ml-6px"
|
||||
color="primary"
|
||||
onClick={() => {
|
||||
Toast.close(successToastId);
|
||||
navigateToProjectIDE(item.entity_id ?? '');
|
||||
}}
|
||||
>
|
||||
{I18n.t('project_ide_toast_duplicate_view')}
|
||||
</Button>
|
||||
</>
|
||||
),
|
||||
showClose: false,
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (item.entity_status === IntelligenceStatus.CopyFailed) {
|
||||
const failedToastId = Toast.error({
|
||||
content: (
|
||||
<>
|
||||
{I18n.t('project_ide_toast_duplicate_fail')}
|
||||
<Button
|
||||
className="ml-6px"
|
||||
color="primary"
|
||||
onClick={async () => {
|
||||
Toast.close(failedToastId);
|
||||
const response = await intelligenceApi.ProcessEntityTask({
|
||||
entity_id: item.entity_id,
|
||||
action: TaskAction.ProjectCopyRetry,
|
||||
});
|
||||
mutate(prev =>
|
||||
produce(prev, draft => {
|
||||
const target = draft?.list.find(
|
||||
intelligence =>
|
||||
intelligence.basic_info?.id === item.entity_id,
|
||||
);
|
||||
|
||||
if (!target || !target.basic_info) {
|
||||
return;
|
||||
}
|
||||
target.basic_info.status =
|
||||
response.data?.entity_task?.entity_status;
|
||||
}),
|
||||
);
|
||||
}}
|
||||
>
|
||||
{I18n.t('project_ide_toast_duplicate_fail_retry')}
|
||||
</Button>
|
||||
</>
|
||||
),
|
||||
showClose: false,
|
||||
});
|
||||
return;
|
||||
}
|
||||
});
|
||||
};
|
||||
intelligenceCopyTaskPollingService.eventCenter.on(
|
||||
'onCopyTaskUpdate',
|
||||
onTaskUpdate,
|
||||
);
|
||||
return () => {
|
||||
intelligenceCopyTaskPollingService.clearAll();
|
||||
intelligenceCopyTaskPollingService.eventCenter.off(
|
||||
'onCopyTaskUpdate',
|
||||
onTaskUpdate,
|
||||
);
|
||||
};
|
||||
}, []);
|
||||
};
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* 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 {
|
||||
Content,
|
||||
Header,
|
||||
HeaderActions,
|
||||
HeaderTitle,
|
||||
Layout,
|
||||
SubHeader,
|
||||
SubHeaderFilters,
|
||||
SubHeaderSearch,
|
||||
} from '@/components/layout/list';
|
||||
|
||||
export { highlightFilterStyle } from '../../constants/filter-style';
|
||||
export { WorkspaceEmpty } from '../../components/workspace-empty';
|
||||
export { DevelopCustomPublishStatus, DevelopCustomTypeStatus } from './type';
|
||||
export {
|
||||
isPublishStatus,
|
||||
isSearchScopeEnum,
|
||||
isRecentOpen,
|
||||
} from './page-utils/predicate';
|
||||
export {
|
||||
getPublishRequestParam,
|
||||
getTypeRequestParams,
|
||||
} from './page-utils/parameters';
|
||||
export {
|
||||
isEqualDefaultFilterParams,
|
||||
isFilterHighlight,
|
||||
} from './page-utils/filters';
|
||||
export {
|
||||
CREATOR_FILTER_OPTIONS,
|
||||
FILTER_PARAMS_DEFAULT,
|
||||
STATUS_FILTER_OPTIONS,
|
||||
TYPE_FILTER_OPTIONS,
|
||||
} from './develop-filter-options';
|
||||
|
||||
export { useCardActions } from './hooks/use-card-actions';
|
||||
export { useIntelligenceList } from './hooks/use-intelligence-list';
|
||||
export { useIntelligenceActions } from './hooks/use-intelligence-actions';
|
||||
export { useGlobalEventListeners } from './hooks/use-global-event-listeners';
|
||||
export { useProjectCopyPolling } from './hooks/use-project-copy-polling';
|
||||
export { useCachedQueryParams } from './hooks/use-cached-query-params';
|
||||
export { BotCard } from './components/bot-card';
|
||||
|
||||
export interface DevelopProps {
|
||||
spaceId: string;
|
||||
}
|
||||
@@ -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 { produce } from 'immer';
|
||||
import {
|
||||
type IntelligenceBasicInfo,
|
||||
type IntelligenceData,
|
||||
type User,
|
||||
} from '@coze-arch/idl/intelligence_api';
|
||||
import { getUserInfo, getUserLabel } from '@coze-foundation/account-adapter';
|
||||
|
||||
export const produceCopyIntelligenceData = ({
|
||||
originTemplateData,
|
||||
newCopyData,
|
||||
}: {
|
||||
originTemplateData: IntelligenceData;
|
||||
newCopyData: {
|
||||
ownerInfo: User | undefined;
|
||||
basicInfo: IntelligenceBasicInfo;
|
||||
};
|
||||
}) => {
|
||||
// 这是 fallback
|
||||
const userInfo = getUserInfo();
|
||||
const userLabel = getUserLabel();
|
||||
return produce<IntelligenceData>(originTemplateData, draft => {
|
||||
const { type } = draft;
|
||||
const { ownerInfo, basicInfo } = newCopyData;
|
||||
return {
|
||||
type,
|
||||
owner_info: ownerInfo || {
|
||||
user_id: userInfo?.user_id_str,
|
||||
nickname: userInfo?.name,
|
||||
avatar_url: userInfo?.avatar_url,
|
||||
user_unique_name: userInfo?.app_user_info.user_unique_name,
|
||||
user_label: userLabel || undefined,
|
||||
},
|
||||
basic_info: basicInfo,
|
||||
permission_info: {
|
||||
in_collaboration: false,
|
||||
can_delete: true,
|
||||
can_view: true,
|
||||
},
|
||||
};
|
||||
});
|
||||
};
|
||||
@@ -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 { exhaustiveCheckForRecord } from '@coze-common/chat-area-utils';
|
||||
import { SearchScope } from '@coze-arch/idl/intelligence_api';
|
||||
|
||||
import { DevelopCustomTypeStatus, type FilterParamsType } from '../type';
|
||||
import { FILTER_PARAMS_DEFAULT } from '../develop-filter-options';
|
||||
|
||||
export const isEqualDefaultFilterParams = ({
|
||||
filterParams,
|
||||
}: {
|
||||
filterParams: FilterParamsType;
|
||||
}) => {
|
||||
const {
|
||||
searchScope,
|
||||
searchValue,
|
||||
searchType,
|
||||
isPublish,
|
||||
recentlyOpen,
|
||||
...rest
|
||||
} = filterParams;
|
||||
exhaustiveCheckForRecord(rest);
|
||||
return (
|
||||
searchScope === FILTER_PARAMS_DEFAULT.searchScope &&
|
||||
searchType === FILTER_PARAMS_DEFAULT.searchType &&
|
||||
isPublish === FILTER_PARAMS_DEFAULT.isPublish &&
|
||||
recentlyOpen === FILTER_PARAMS_DEFAULT.recentlyOpen &&
|
||||
!searchValue
|
||||
);
|
||||
};
|
||||
|
||||
export const isFilterHighlight = (currentFilterParams: FilterParamsType) => {
|
||||
const {
|
||||
searchValue,
|
||||
searchScope,
|
||||
isPublish,
|
||||
searchType,
|
||||
recentlyOpen,
|
||||
...rest
|
||||
} = currentFilterParams;
|
||||
exhaustiveCheckForRecord(rest);
|
||||
return {
|
||||
isIntelligenceTypeFilterHighlight:
|
||||
searchType !== DevelopCustomTypeStatus.All,
|
||||
isOwnerFilterHighlight: searchScope !== SearchScope.All,
|
||||
isPublishAndOpenFilterHighlight: isPublish || recentlyOpen,
|
||||
};
|
||||
};
|
||||
@@ -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 { IntelligenceType } from '@coze-arch/idl/intelligence_api';
|
||||
|
||||
import { DevelopCustomPublishStatus, DevelopCustomTypeStatus } from '../type';
|
||||
|
||||
export const getPublishRequestParam = (
|
||||
publishStatus: DevelopCustomPublishStatus | undefined,
|
||||
) => {
|
||||
if (typeof publishStatus === 'undefined') {
|
||||
return;
|
||||
}
|
||||
if (publishStatus === DevelopCustomPublishStatus.All) {
|
||||
return;
|
||||
}
|
||||
return publishStatus === DevelopCustomPublishStatus.Publish;
|
||||
};
|
||||
|
||||
/**
|
||||
* 项目类型请求前后端参数映射,将DevelopCustomTypeStatus映射为IntelligenceType[]
|
||||
* 需要根据是否可以展示抖音分身来决定是否处理 DouyinAvatarBot
|
||||
* @param type
|
||||
* @returns
|
||||
*/
|
||||
export const getTypeRequestParams = ({
|
||||
type,
|
||||
}: {
|
||||
type: DevelopCustomTypeStatus;
|
||||
}) => {
|
||||
const allIntelligenceTypeParams = [
|
||||
IntelligenceType.Bot,
|
||||
IntelligenceType.Project,
|
||||
];
|
||||
const typeMap: Record<DevelopCustomTypeStatus, IntelligenceType[]> = {
|
||||
[DevelopCustomTypeStatus.All]: allIntelligenceTypeParams,
|
||||
[DevelopCustomTypeStatus.Agent]: [IntelligenceType.Bot],
|
||||
[DevelopCustomTypeStatus.Project]: [IntelligenceType.Project],
|
||||
[DevelopCustomTypeStatus.DouyinAvatarBot]: [
|
||||
IntelligenceType.DouyinAvatarBot,
|
||||
],
|
||||
};
|
||||
|
||||
return typeMap[type] || [];
|
||||
};
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { SearchScope } from '@coze-arch/idl/intelligence_api';
|
||||
|
||||
import { DevelopCustomPublishStatus } from '../type';
|
||||
|
||||
export function isPublishStatus(
|
||||
val: unknown,
|
||||
): val is DevelopCustomPublishStatus {
|
||||
const statusList: unknown[] = [
|
||||
DevelopCustomPublishStatus.All,
|
||||
DevelopCustomPublishStatus.NoPublish,
|
||||
DevelopCustomPublishStatus.Publish,
|
||||
];
|
||||
|
||||
return statusList.includes(val);
|
||||
}
|
||||
|
||||
export const isRecentOpen = (val: unknown) => val === 'recentOpened';
|
||||
|
||||
export const isSearchScopeEnum = (val: unknown): val is SearchScope =>
|
||||
val === SearchScope.All || val === SearchScope.CreateByMe;
|
||||
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* 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 mitt, { type Emitter } from 'mitt';
|
||||
import { uniqBy } from 'lodash-es';
|
||||
import {
|
||||
type EntityTaskData,
|
||||
IntelligenceStatus,
|
||||
type TaskStruct,
|
||||
} from '@coze-arch/idl/intelligence_api';
|
||||
import { intelligenceApi } from '@coze-arch/bot-api';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/consistent-type-definitions
|
||||
export type PollCopyTaskEvent = {
|
||||
onCopyTaskUpdate: EntityTaskData[];
|
||||
};
|
||||
|
||||
export class IntelligenceCopyTaskPollingService {
|
||||
readonly defaultTimeout = 2000;
|
||||
readonly timeoutStep = 2000;
|
||||
taskPool: TaskStruct[] = [];
|
||||
timeout = this.defaultTimeout;
|
||||
timerId: ReturnType<typeof setTimeout> | null = null;
|
||||
eventCenter: Emitter<PollCopyTaskEvent>;
|
||||
|
||||
constructor() {
|
||||
this.eventCenter = mitt<PollCopyTaskEvent>();
|
||||
}
|
||||
|
||||
removeTaskPoll = (params: EntityTaskData[]) => {
|
||||
this.taskPool = this.taskPool.filter(
|
||||
task => !params.find(p => p.entity_id === task.entity_id),
|
||||
);
|
||||
};
|
||||
|
||||
poll = async () => {
|
||||
const response = await intelligenceApi.EntityTaskSearch({
|
||||
task_list: this.taskPool,
|
||||
});
|
||||
const taskMap = response.data?.entity_task_map ?? {};
|
||||
const taskList = Object.entries(taskMap).map(([_, task]) => task);
|
||||
|
||||
const finishPollList = taskList.filter(
|
||||
task => task.entity_status !== IntelligenceStatus.Copying,
|
||||
);
|
||||
|
||||
this.removeTaskPoll(finishPollList);
|
||||
|
||||
this.eventCenter.emit('onCopyTaskUpdate', taskList);
|
||||
};
|
||||
|
||||
resetTimeout = () => {
|
||||
this.timeout = this.defaultTimeout;
|
||||
};
|
||||
|
||||
increaseTimeout = () => {
|
||||
this.timeout += this.timeoutStep;
|
||||
};
|
||||
|
||||
checkIsContinuePoll = () => Boolean(this.taskPool.length);
|
||||
|
||||
clearTimer = () => {
|
||||
if (!this.timerId) {
|
||||
return;
|
||||
}
|
||||
clearTimeout(this.timerId);
|
||||
};
|
||||
|
||||
run = () => {
|
||||
this.timerId = setTimeout(async () => {
|
||||
await this.poll();
|
||||
if (!this.checkIsContinuePoll()) {
|
||||
return;
|
||||
}
|
||||
this.increaseTimeout();
|
||||
this.run();
|
||||
}, this.timeout);
|
||||
};
|
||||
|
||||
registerPolling = (params: TaskStruct[]) => {
|
||||
const prevLength = this.taskPool.length;
|
||||
|
||||
this.taskPool = uniqBy(
|
||||
this.taskPool.concat(params),
|
||||
task => task.entity_id,
|
||||
);
|
||||
|
||||
const currentLength = this.taskPool.length;
|
||||
|
||||
if (!prevLength && currentLength) {
|
||||
this.resetTimeout();
|
||||
this.run();
|
||||
}
|
||||
};
|
||||
|
||||
clearAll = () => {
|
||||
this.clearTimer();
|
||||
this.eventCenter.off('onCopyTaskUpdate');
|
||||
this.taskPool = [];
|
||||
this.timerId = null;
|
||||
};
|
||||
}
|
||||
|
||||
export const intelligenceCopyTaskPollingService =
|
||||
new IntelligenceCopyTaskPollingService();
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {
|
||||
type IntelligenceData,
|
||||
type SearchScope,
|
||||
} from '@coze-arch/idl/intelligence_api';
|
||||
|
||||
export enum DevelopCustomPublishStatus {
|
||||
All = 0,
|
||||
Publish = 1,
|
||||
NoPublish = 2,
|
||||
}
|
||||
|
||||
export enum DevelopCustomTypeStatus {
|
||||
All = 0,
|
||||
Project = 1,
|
||||
Agent = 2,
|
||||
DouyinAvatarBot = 3, // single agent 类型的抖音分身 社区版暂不支持该功能
|
||||
}
|
||||
|
||||
export interface DraftIntelligenceList {
|
||||
list: IntelligenceData[];
|
||||
hasMore: boolean;
|
||||
nextCursorId: string | undefined;
|
||||
}
|
||||
|
||||
export interface FilterParamsType {
|
||||
searchScope: SearchScope | undefined;
|
||||
searchValue: string;
|
||||
isPublish: DevelopCustomPublishStatus;
|
||||
searchType: DevelopCustomTypeStatus;
|
||||
recentlyOpen: boolean | undefined;
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { useNavigate, useParams } from 'react-router-dom';
|
||||
|
||||
import qs from 'qs';
|
||||
import { KnowledgeParamsStoreProvider } from '@coze-data/knowledge-stores';
|
||||
import {
|
||||
type UnitType,
|
||||
type OptType,
|
||||
} from '@coze-data/knowledge-resource-processor-core';
|
||||
import { type ActionType } from '@coze-data/knowledge-ide-base/types';
|
||||
import {
|
||||
BizAgentKnowledgeIDE,
|
||||
BizLibraryKnowledgeIDE,
|
||||
BizProjectKnowledgeIDE,
|
||||
BizWorkflowKnowledgeIDE,
|
||||
} from '@coze-data/knowledge-ide-adapter';
|
||||
import { useSpaceStore } from '@coze-arch/bot-studio-store';
|
||||
|
||||
export const KnowledgePreviewPage = () => {
|
||||
const { dataset_id, space_id } = useParams();
|
||||
const searchParams = new URLSearchParams(window.location.search);
|
||||
const params = {
|
||||
datasetID: dataset_id ?? '',
|
||||
spaceID: space_id ?? '',
|
||||
type: searchParams.get('type') as UnitType,
|
||||
opt: searchParams.get('opt') as OptType,
|
||||
docID: searchParams.get('doc_id') ?? '',
|
||||
pageMode: searchParams.get('page_mode') as 'modal' | 'normal',
|
||||
biz: searchParams.get('biz') as
|
||||
| 'agentIDE'
|
||||
| 'workflow'
|
||||
| 'project'
|
||||
| 'library',
|
||||
botID: searchParams.get('bot_id') ?? '',
|
||||
workflowID: searchParams.get('workflow_id') ?? '',
|
||||
agentID: searchParams.get('agent_id') ?? '',
|
||||
actionType: searchParams.get('action_type') as ActionType,
|
||||
first_auto_open_edit_document_id:
|
||||
searchParams.get('first_auto_open_edit_document_id') ?? '',
|
||||
create: searchParams.get('create') ?? '',
|
||||
};
|
||||
const navigate = useNavigate();
|
||||
const spaceID = useSpaceStore(store => store.space.id);
|
||||
return (
|
||||
<KnowledgeParamsStoreProvider
|
||||
params={{ ...params, spaceID }}
|
||||
resourceNavigate={{
|
||||
// eslint-disable-next-line max-params
|
||||
toResource: (resource, resourceID, query, opts) =>
|
||||
navigate(
|
||||
`/space/${params.spaceID}/${resource}/${resourceID}?${qs.stringify(query)}`,
|
||||
opts,
|
||||
),
|
||||
upload: (query, opts) =>
|
||||
navigate(
|
||||
`/space/${params.spaceID}/knowledge/${params.datasetID}/upload?${qs.stringify(query)}`,
|
||||
opts,
|
||||
),
|
||||
}}
|
||||
>
|
||||
{(() => {
|
||||
if (params.biz === 'agentIDE') {
|
||||
return <BizAgentKnowledgeIDE />;
|
||||
}
|
||||
if (params.biz === 'workflow') {
|
||||
return <BizWorkflowKnowledgeIDE />;
|
||||
}
|
||||
if (params.biz === 'project') {
|
||||
return <BizProjectKnowledgeIDE />;
|
||||
}
|
||||
// 默认'library'
|
||||
return <BizLibraryKnowledgeIDE />;
|
||||
})()}
|
||||
</KnowledgeParamsStoreProvider>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* 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 { useNavigate, useParams } from 'react-router-dom';
|
||||
|
||||
import qs from 'qs';
|
||||
import {
|
||||
KnowledgeParamsStoreProvider,
|
||||
type IKnowledgeParams,
|
||||
} from '@coze-data/knowledge-stores';
|
||||
import {
|
||||
OptType,
|
||||
UnitType,
|
||||
} from '@coze-data/knowledge-resource-processor-core';
|
||||
import {
|
||||
getUploadConfig,
|
||||
KnowledgeResourceProcessor,
|
||||
} from '@coze-data/knowledge-resource-processor-adapter';
|
||||
import { useSpaceStore } from '@coze-arch/bot-studio-store';
|
||||
|
||||
export const KnowledgeUploadPage = () => {
|
||||
const navigate = useNavigate();
|
||||
const spaceID = useSpaceStore(store => store.space.id);
|
||||
const locationSearchParams = new URLSearchParams(location.search);
|
||||
const type = (locationSearchParams.get('type') ||
|
||||
UnitType.TEXT_DOC) as UnitType;
|
||||
const opt = (locationSearchParams.get('opt') || OptType.ADD) as OptType;
|
||||
const docID = locationSearchParams.get('doc_id') || '';
|
||||
// 社区版暂不支持该功能
|
||||
const isDouyinBot =
|
||||
locationSearchParams.get('is_douyin') === 'true' ? true : false;
|
||||
const { dataset_id, space_id } = useParams();
|
||||
const params: IKnowledgeParams = {
|
||||
datasetID: dataset_id || '',
|
||||
spaceID: space_id || '',
|
||||
type,
|
||||
opt,
|
||||
docID,
|
||||
isDouyinBot,
|
||||
biz: 'library',
|
||||
};
|
||||
|
||||
const uploadConfig = getUploadConfig(
|
||||
type ?? UnitType.TEXT,
|
||||
opt ?? OptType.ADD,
|
||||
);
|
||||
if (!uploadConfig) {
|
||||
return <></>;
|
||||
}
|
||||
|
||||
return (
|
||||
<KnowledgeParamsStoreProvider
|
||||
params={{ ...params, spaceID }}
|
||||
resourceNavigate={{
|
||||
// eslint-disable-next-line max-params
|
||||
toResource: (resource, resourceID, query, opts) =>
|
||||
navigate(
|
||||
`/space/${params.spaceID}/${resource}/${resourceID}?${qs.stringify(query)}`,
|
||||
opts,
|
||||
),
|
||||
upload: (query, opts) =>
|
||||
navigate(
|
||||
`/space/${params.spaceID}/knowledge/${params.datasetID}/upload?${qs.stringify(query)}`,
|
||||
opts,
|
||||
),
|
||||
}}
|
||||
>
|
||||
<KnowledgeResourceProcessor uploadConfig={uploadConfig} />
|
||||
</KnowledgeParamsStoreProvider>
|
||||
);
|
||||
};
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 1.4 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 1.7 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 2.1 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 1.9 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 1.7 KiB |
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { type ReactNode } from 'react';
|
||||
|
||||
import { IconCozCheckMarkCircleFill } from '@coze-arch/coze-design/icons';
|
||||
import { Space, Typography, CozAvatar } from '@coze-arch/coze-design';
|
||||
import {
|
||||
PublishStatus,
|
||||
type ResourceInfo,
|
||||
} from '@coze-arch/bot-api/plugin_develop';
|
||||
|
||||
export const BaseLibraryItem: React.FC<{
|
||||
resourceInfo: ResourceInfo;
|
||||
defaultIcon?: string;
|
||||
customAvatar?: ReactNode;
|
||||
tag?: ReactNode;
|
||||
}> = ({ resourceInfo, defaultIcon, customAvatar, tag }) => (
|
||||
<div className="flex items-center w-full h-[48px]">
|
||||
{customAvatar ?? (
|
||||
<CozAvatar
|
||||
size="lg"
|
||||
className="overflow-hidden flex-shrink-0 mr-[12px] rounded-[12px]"
|
||||
data-testid="workspace.library.item.avatar"
|
||||
src={resourceInfo.icon || defaultIcon}
|
||||
type="bot"
|
||||
/>
|
||||
)}
|
||||
<div
|
||||
className="flex flex-col gap-[2px]"
|
||||
style={{ width: 'calc(100% - 60px)' }}
|
||||
>
|
||||
<div className="w-[95%] h-[20px] flex-shrink-0">
|
||||
<Space spacing={4} className="w-full">
|
||||
<Typography.Text
|
||||
data-testid="workspace.library.item.name"
|
||||
className="h-[20px] text-[14px] font-[500] coz-fg-primary leading-[20px]"
|
||||
style={{
|
||||
maxWidth: '246px',
|
||||
}}
|
||||
ellipsis={{ showTooltip: true }}
|
||||
>
|
||||
{resourceInfo.name}
|
||||
</Typography.Text>
|
||||
|
||||
{resourceInfo.publish_status === PublishStatus.Published ? (
|
||||
<IconCozCheckMarkCircleFill
|
||||
data-testid="workspace.library.item.publish.status"
|
||||
className="flex-shrink-0 w-[16px] h-[16px] coz-fg-hglt-green"
|
||||
/>
|
||||
) : null}
|
||||
</Space>
|
||||
</div>
|
||||
{tag || resourceInfo.desc ? (
|
||||
<div className="w-[95%] flex-shrink leading-[0]">
|
||||
<Space spacing={4} className="w-full">
|
||||
{tag}
|
||||
{resourceInfo.desc ? (
|
||||
<Typography.Text
|
||||
data-testid="workspace.library.item.desc"
|
||||
fontSize="12px"
|
||||
className="!h-[16px] !font-[400] !coz-fg-secondary !leading-[16px]"
|
||||
ellipsis={{ showTooltip: true }}
|
||||
>
|
||||
{resourceInfo.desc}
|
||||
</Typography.Text>
|
||||
) : null}
|
||||
</Space>
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* 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 from 'react';
|
||||
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import { IconCozPlus } from '@coze-arch/coze-design/icons';
|
||||
import { Button, Menu } from '@coze-arch/coze-design';
|
||||
|
||||
import { type LibraryEntityConfig } from '../types';
|
||||
|
||||
export const LibraryHeader: React.FC<{
|
||||
entityConfigs: LibraryEntityConfig[];
|
||||
}> = ({ entityConfigs }) => (
|
||||
<div className="flex items-center justify-between mb-[16px]">
|
||||
<div className="font-[500] text-[20px]">
|
||||
{I18n.t('navigation_workspace_library')}
|
||||
</div>
|
||||
<Menu
|
||||
position="bottomRight"
|
||||
className="w-120px mt-4px mb-4px"
|
||||
render={
|
||||
<Menu.SubMenu mode="menu">
|
||||
{entityConfigs.map(config => config.renderCreateMenu?.() ?? null)}
|
||||
</Menu.SubMenu>
|
||||
}
|
||||
>
|
||||
<Button
|
||||
theme="solid"
|
||||
type="primary"
|
||||
icon={<IconCozPlus />}
|
||||
data-testid="workspace.library.header.create"
|
||||
>
|
||||
{I18n.t('library_resource')}
|
||||
</Button>
|
||||
</Menu>
|
||||
</div>
|
||||
);
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* 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 {
|
||||
PublishStatus,
|
||||
ResType,
|
||||
type LibraryResourceListRequest,
|
||||
} from '@coze-arch/bot-api/plugin_develop';
|
||||
|
||||
export const LIBRARY_PAGE_SIZE = 15;
|
||||
|
||||
export type QueryParams = Omit<LibraryResourceListRequest, 'space_id' | 'size'>;
|
||||
|
||||
export const initialParam: QueryParams = {
|
||||
cursor: '',
|
||||
user_filter: 0,
|
||||
publish_status_filter: 0,
|
||||
res_type_filter: [-1],
|
||||
name: '',
|
||||
};
|
||||
|
||||
/** 是否由当前用户创建:
|
||||
* 0-不筛选
|
||||
* 1-当前用户 */
|
||||
export const getScopeOptions = () => [
|
||||
{
|
||||
label: I18n.t('library_filter_tags_all_creators'),
|
||||
value: 0,
|
||||
},
|
||||
{
|
||||
label: I18n.t('library_filter_tags_created_by_me'),
|
||||
value: 1,
|
||||
},
|
||||
];
|
||||
|
||||
/** 发布状态:
|
||||
* 0-不筛选
|
||||
* 1-未发布
|
||||
* 2-已发布 */
|
||||
export const getStatusOptions = () => [
|
||||
{
|
||||
label: I18n.t('library_filter_tags_all_status'),
|
||||
value: 0,
|
||||
},
|
||||
{
|
||||
label: I18n.t('library_filter_tags_published'),
|
||||
value: PublishStatus.Published,
|
||||
},
|
||||
{
|
||||
label: I18n.t('library_filter_tags_unpublished'),
|
||||
value: PublishStatus.UnPublished,
|
||||
},
|
||||
];
|
||||
|
||||
/** event type */
|
||||
export const eventLibraryType = {
|
||||
[ResType.Plugin]: 'plugin',
|
||||
[ResType.Workflow]: 'workflow',
|
||||
[ResType.Imageflow]: 'imageflow',
|
||||
[ResType.Knowledge]: 'knowledge',
|
||||
[ResType.UI]: 'ui',
|
||||
[ResType.Prompt]: 'prompt',
|
||||
[ResType.Database]: 'database',
|
||||
[ResType.Variable]: 'variable',
|
||||
[ResType.Voice]: 'voice',
|
||||
} as const;
|
||||
@@ -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 { useEffect, useState } from 'react';
|
||||
|
||||
import { parse } from 'qs';
|
||||
import { useUpdateEffect } from 'ahooks';
|
||||
import { localStorageService } from '@coze-foundation/local-storage';
|
||||
import { ResType } from '@coze-arch/idl/plugin_develop';
|
||||
import { safeJSONParse } from '@coze-agent-ide/space-bot/util';
|
||||
|
||||
import { compareObjects } from '@/utils';
|
||||
|
||||
import { initialParam, type QueryParams } from '../consts';
|
||||
|
||||
/**
|
||||
* 从url query中获取搜索参数 优先级最高,高于LS缓存
|
||||
* @returns {} | undefined
|
||||
*/
|
||||
const getSearchParamsFromUrl = () => {
|
||||
const urlQuery = parse(location.search.slice(1)) as {
|
||||
type?: string;
|
||||
name?: string;
|
||||
};
|
||||
const searchParams: QueryParams = {};
|
||||
if (urlQuery.type && Object.values(ResType).includes(Number(urlQuery.type))) {
|
||||
const resType = Number(urlQuery.type);
|
||||
searchParams.res_type_filter =
|
||||
resType === ResType.Knowledge ? [resType, -1] : [resType];
|
||||
}
|
||||
if (urlQuery.name) {
|
||||
searchParams.name = urlQuery.name;
|
||||
}
|
||||
return searchParams;
|
||||
};
|
||||
|
||||
// 异步初始化获取筛选参数, 分别从LS缓存获取和url query获取
|
||||
const getDefaultFilterParams = async () => {
|
||||
const searchParamsFromUrl = getSearchParamsFromUrl();
|
||||
const localFilterParams = await localStorageService.getValueSync(
|
||||
'workspace-library-filters',
|
||||
);
|
||||
let defaultFilterParams = initialParam;
|
||||
|
||||
if (localFilterParams) {
|
||||
const safeParams = safeJSONParse(localFilterParams) as QueryParams;
|
||||
defaultFilterParams = { ...defaultFilterParams, ...safeParams };
|
||||
}
|
||||
|
||||
// 图像流和工作流合并会删除资源中的图像流选项 这里转换成全部
|
||||
if (defaultFilterParams?.res_type_filter?.[0] === 3) {
|
||||
defaultFilterParams.res_type_filter[0] = -1;
|
||||
}
|
||||
|
||||
defaultFilterParams = { ...defaultFilterParams, ...searchParamsFromUrl };
|
||||
|
||||
return defaultFilterParams;
|
||||
};
|
||||
|
||||
export const useCachedQueryParams = ({ spaceId }: { spaceId: string }) => {
|
||||
const [ready, setReady] = useState(false);
|
||||
const [params, setParams] = useState<QueryParams>(initialParam);
|
||||
const hasFilter = !compareObjects(params, initialParam, [
|
||||
'res_type_filter',
|
||||
'user_filter',
|
||||
'publish_status_filter',
|
||||
'name',
|
||||
]);
|
||||
|
||||
/** 每次切换空间的时候,重新初始化筛选条件,并清空搜索框,重新请求资源列表 */
|
||||
useEffect(() => {
|
||||
setReady(false);
|
||||
getDefaultFilterParams().then(filters => {
|
||||
setParams(p => ({
|
||||
...p,
|
||||
...filters,
|
||||
cursor: '', // 筛选、刷新时重置为空
|
||||
}));
|
||||
setReady(true);
|
||||
});
|
||||
}, [spaceId]);
|
||||
|
||||
useUpdateEffect(() => {
|
||||
/** 当筛选条件变化时,取合适的 key 存入本地 */
|
||||
const tempParams = {
|
||||
res_type_filter: params.res_type_filter,
|
||||
user_filter: params.user_filter,
|
||||
publish_status_filter: params.publish_status_filter,
|
||||
};
|
||||
localStorageService.setValue(
|
||||
'workspace-library-filters',
|
||||
JSON.stringify(tempParams),
|
||||
);
|
||||
}, [params]);
|
||||
|
||||
const resetParams = () => {
|
||||
setParams(initialParam);
|
||||
};
|
||||
|
||||
return {
|
||||
params,
|
||||
setParams,
|
||||
resetParams,
|
||||
hasFilter,
|
||||
ready,
|
||||
} as const;
|
||||
};
|
||||
@@ -0,0 +1,197 @@
|
||||
/*
|
||||
* 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 MouseEvent } from 'react';
|
||||
|
||||
import { useSize } from 'ahooks';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import {
|
||||
type ColumnProps,
|
||||
Space,
|
||||
Avatar,
|
||||
Typography,
|
||||
} from '@coze-arch/coze-design';
|
||||
import { responsiveTableColumn, formatDate } from '@coze-arch/bot-utils';
|
||||
import {
|
||||
type ResourceInfo,
|
||||
type ResType,
|
||||
} from '@coze-arch/bot-api/plugin_develop';
|
||||
|
||||
import { type LibraryEntityConfig } from '../types';
|
||||
import { BaseLibraryItem } from '../components/base-library-item';
|
||||
|
||||
const { Text } = Typography;
|
||||
|
||||
// 预设表格cell最小宽度
|
||||
const NAME_COL_WIDTH = 260;
|
||||
const ACTIONS_COL_WIDTH = 60;
|
||||
const TYPE_COL_WIDTH = 100;
|
||||
const CREATOR_COL_WIDTH = 231;
|
||||
const EDITED_TIME_COL_WIDTH = 150;
|
||||
|
||||
const stopPro = (e: MouseEvent<HTMLDivElement>) => {
|
||||
e.stopPropagation(); //阻止冒泡
|
||||
};
|
||||
|
||||
const getResTypeLabelFromConfigMap = (
|
||||
item: ResourceInfo,
|
||||
entityConfigs: LibraryEntityConfig[],
|
||||
): string => {
|
||||
if (item.res_type === undefined) {
|
||||
return '-';
|
||||
}
|
||||
const target = entityConfigs.find(config =>
|
||||
config.target.includes(item.res_type as ResType),
|
||||
)?.typeFilter;
|
||||
return target?.filterName ?? target?.label ?? '-';
|
||||
};
|
||||
|
||||
export const useGetColumns = ({
|
||||
entityConfigs,
|
||||
reloadList,
|
||||
isPersonalSpace,
|
||||
}: {
|
||||
entityConfigs: LibraryEntityConfig[];
|
||||
reloadList: () => void;
|
||||
isPersonalSpace: boolean;
|
||||
}): ColumnProps<ResourceInfo>[] => {
|
||||
const size = useSize(document.body);
|
||||
const clientWidth = size?.width ?? document.body.clientWidth;
|
||||
|
||||
return [
|
||||
{
|
||||
title: I18n.t('library_name', {}, 'Resource'),
|
||||
dataIndex: 'name',
|
||||
width: responsiveTableColumn(clientWidth, NAME_COL_WIDTH),
|
||||
render: (_text, record) => {
|
||||
const config =
|
||||
record.res_type !== undefined
|
||||
? entityConfigs.find(c =>
|
||||
c.target.includes(record.res_type as ResType),
|
||||
)
|
||||
: undefined;
|
||||
if (config?.renderItem) {
|
||||
return config.renderItem(record);
|
||||
}
|
||||
return <BaseLibraryItem resourceInfo={record} />;
|
||||
},
|
||||
},
|
||||
{
|
||||
title: I18n.t('library_type', {}, 'Type'),
|
||||
dataIndex: 'res_type',
|
||||
width: responsiveTableColumn(TYPE_COL_WIDTH, TYPE_COL_WIDTH),
|
||||
render: (_v, record) => (
|
||||
<div
|
||||
data-testid="workspace.library.item.type"
|
||||
className="text-[14px] font-[400]"
|
||||
>
|
||||
{getResTypeLabelFromConfigMap(record, entityConfigs)}
|
||||
</div>
|
||||
),
|
||||
},
|
||||
...(isPersonalSpace
|
||||
? []
|
||||
: ([
|
||||
{
|
||||
title: I18n.t('Plugin_list_table_owner'),
|
||||
dataIndex: 'creator',
|
||||
width: responsiveTableColumn(CREATOR_COL_WIDTH, CREATOR_COL_WIDTH),
|
||||
render: (_v, record) => {
|
||||
if (!record.creator_name) {
|
||||
return '-';
|
||||
}
|
||||
return (
|
||||
<Space style={{ width: '100%' }} spacing={6}>
|
||||
<Avatar
|
||||
data-testid="workspace.library.item.creator.avatar"
|
||||
size="extra-small"
|
||||
src={record.creator_avatar}
|
||||
/>
|
||||
<Text
|
||||
data-testid="workspace.library.item.creator.name"
|
||||
style={{
|
||||
fontSize: 14,
|
||||
fontWeight: 500,
|
||||
color: 'var(--coz-fg-secondary)',
|
||||
}}
|
||||
ellipsis={{ showTooltip: true }}
|
||||
>
|
||||
{record.creator_name}
|
||||
</Text>
|
||||
<Text
|
||||
data-testid="workspace.library.item.creator.username"
|
||||
style={{
|
||||
flex: 1,
|
||||
fontSize: 14,
|
||||
fontWeight: 400,
|
||||
color: 'var(--coz-fg-secondary)',
|
||||
}}
|
||||
ellipsis={{ showTooltip: true }}
|
||||
>
|
||||
{`@${record.user_name}`}
|
||||
</Text>
|
||||
</Space>
|
||||
);
|
||||
},
|
||||
},
|
||||
] satisfies ColumnProps<ResourceInfo>[])),
|
||||
{
|
||||
title: I18n.t('library_edited_time', {}, 'Edited time'),
|
||||
dataIndex: 'edit_time',
|
||||
width: responsiveTableColumn(
|
||||
EDITED_TIME_COL_WIDTH,
|
||||
EDITED_TIME_COL_WIDTH,
|
||||
),
|
||||
render: (_v, record) => {
|
||||
if (!record.edit_time) {
|
||||
return '-';
|
||||
}
|
||||
return (
|
||||
<div
|
||||
data-testid="workspace.library.item.edit.time"
|
||||
className="text-[14px] font-[400]"
|
||||
>
|
||||
{formatDate(Number(record.edit_time), 'YYYY-MM-DD HH:mm')}
|
||||
</div>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: I18n.t('library_actions', {}, 'Actions'),
|
||||
dataIndex: 'action',
|
||||
width: responsiveTableColumn(ACTIONS_COL_WIDTH, ACTIONS_COL_WIDTH),
|
||||
render: (_v, record) => {
|
||||
const config =
|
||||
record.res_type !== undefined
|
||||
? entityConfigs.find(c =>
|
||||
c.target.includes(record.res_type as ResType),
|
||||
)
|
||||
: undefined;
|
||||
|
||||
return (
|
||||
<div
|
||||
data-testid="workspace.library.item.actions"
|
||||
onClick={e => {
|
||||
stopPro(e);
|
||||
}}
|
||||
>
|
||||
{config?.renderActions(record, reloadList) ?? null}
|
||||
</div>
|
||||
);
|
||||
},
|
||||
},
|
||||
];
|
||||
};
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { type ReactNode } from 'react';
|
||||
|
||||
import { type ResourceInfo } from '@coze-arch/idl/plugin_develop';
|
||||
import { type TableActionProps } from '@coze-arch/coze-design';
|
||||
|
||||
import { type LibraryEntityConfig } from '../../types';
|
||||
|
||||
export type UseEntityConfigHook = (params: {
|
||||
spaceId: string;
|
||||
isPersonalSpace?: boolean;
|
||||
reloadList: () => void;
|
||||
getCommonActions?: (
|
||||
item: ResourceInfo,
|
||||
) => NonNullable<TableActionProps['actionList']>;
|
||||
}) => { config: LibraryEntityConfig; modals: ReactNode };
|
||||
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
|
||||
import { useRequest } from 'ahooks';
|
||||
import {
|
||||
ActionKey,
|
||||
type ResourceInfo,
|
||||
ResType,
|
||||
} from '@coze-arch/idl/plugin_develop';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import { IconCozDatabase } from '@coze-arch/coze-design/icons';
|
||||
import { Menu, Table, Toast } from '@coze-arch/coze-design';
|
||||
import { MemoryApi } from '@coze-arch/bot-api';
|
||||
import { useLibraryCreateDatabaseModal } from '@coze-data/database-v2';
|
||||
|
||||
import { type UseEntityConfigHook } from './types';
|
||||
|
||||
const { TableAction } = Table;
|
||||
|
||||
export const useDatabaseConfig: UseEntityConfigHook = ({
|
||||
spaceId,
|
||||
reloadList,
|
||||
getCommonActions,
|
||||
}) => {
|
||||
const navigate = useNavigate();
|
||||
|
||||
const {
|
||||
modal: createDatabaseModal,
|
||||
open: openCreateDatabaseModal,
|
||||
close: closeCreateDatabaseModal,
|
||||
} = useLibraryCreateDatabaseModal({
|
||||
enterFrom: 'library',
|
||||
onFinish: databaseID => {
|
||||
navigate(
|
||||
`/space/${spaceId}/database/${databaseID}?page_modal=normal&biz=create`,
|
||||
);
|
||||
closeCreateDatabaseModal();
|
||||
},
|
||||
});
|
||||
// delete action
|
||||
const { run: deleteDatabase } = useRequest(
|
||||
(databaseId: string) =>
|
||||
MemoryApi.DeleteDatabase({
|
||||
id: databaseId,
|
||||
}),
|
||||
{
|
||||
manual: true,
|
||||
onSuccess: () => {
|
||||
reloadList();
|
||||
Toast.success(I18n.t('Delete_success'));
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
return {
|
||||
modals: <>{createDatabaseModal}</>,
|
||||
config: {
|
||||
typeFilter: {
|
||||
label: I18n.t('new_db_001'),
|
||||
value: ResType.Database,
|
||||
},
|
||||
renderCreateMenu: () => (
|
||||
<Menu.Item
|
||||
data-testid="workspace.library.header.create.card"
|
||||
icon={<IconCozDatabase />}
|
||||
onClick={openCreateDatabaseModal}
|
||||
>
|
||||
{I18n.t('new_db_001')}
|
||||
</Menu.Item>
|
||||
),
|
||||
target: [ResType.Database],
|
||||
onItemClick: (item: ResourceInfo) => {
|
||||
navigate(
|
||||
`/space/${spaceId}/database/${item.res_id}?page_mode=normal&from=library`,
|
||||
);
|
||||
},
|
||||
renderActions: (item: ResourceInfo) => {
|
||||
// 是否能删除
|
||||
const deleteDisabled = !item.actions?.find(
|
||||
action => action.key === ActionKey.Delete,
|
||||
)?.enable;
|
||||
// 是否启用
|
||||
|
||||
// delete operation
|
||||
const deleteProps = {
|
||||
disabled: deleteDisabled,
|
||||
deleteDesc: I18n.t('library_delete_desc'),
|
||||
handler: () => {
|
||||
deleteDatabase(item.res_id || '');
|
||||
},
|
||||
};
|
||||
|
||||
return (
|
||||
<TableAction
|
||||
deleteProps={deleteProps}
|
||||
actionList={getCommonActions?.(item)}
|
||||
/>
|
||||
);
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,272 @@
|
||||
/*
|
||||
* 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 { useNavigate } from 'react-router-dom';
|
||||
|
||||
import { useRequest } from 'ahooks';
|
||||
import { useCreateKnowledgeModalV2 } from '@coze-data/knowledge-modal-adapter';
|
||||
import {
|
||||
ActionKey,
|
||||
type ResourceInfo,
|
||||
ResType,
|
||||
} from '@coze-arch/idl/plugin_develop';
|
||||
import { DatasetStatus } from '@coze-arch/idl/knowledge';
|
||||
import { I18n, type I18nKeysNoOptionsType } from '@coze-arch/i18n';
|
||||
import { IconCozClock, IconCozKnowledge } from '@coze-arch/coze-design/icons';
|
||||
import { Menu, Switch, Tag, Toast, Table } from '@coze-arch/coze-design';
|
||||
import { KnowledgeApi } from '@coze-arch/bot-api';
|
||||
import { safeJSONParse } from '@coze-agent-ide/space-bot/util';
|
||||
|
||||
import { BaseLibraryItem } from '../../components/base-library-item';
|
||||
import DocDefaultIcon from '../../assets/doc_default_icon.png';
|
||||
import { type UseEntityConfigHook } from './types';
|
||||
|
||||
const { TableAction } = Table;
|
||||
/**
|
||||
* 知识库tag:
|
||||
* 0-text
|
||||
* 1-table
|
||||
* 2-image
|
||||
* */
|
||||
const knowledgeSubTypeTextMap: Record<number, I18nKeysNoOptionsType> = {
|
||||
0: 'library_filter_tags_text',
|
||||
1: 'library_filter_tags_table',
|
||||
2: 'library_filter_tags_image',
|
||||
};
|
||||
|
||||
/**
|
||||
* 禁用状态tag:
|
||||
* 3-disabled
|
||||
* */
|
||||
const knowledgeBizStatusTextMap: Record<number, I18nKeysNoOptionsType> = {
|
||||
3: 'library_filter_tags_disabled',
|
||||
};
|
||||
|
||||
enum KnowledgeBizStatus {
|
||||
Disabled = 3,
|
||||
}
|
||||
|
||||
const renderKnowledgeItem = (item: ResourceInfo) => {
|
||||
const knowledgeTag =
|
||||
item.res_sub_type !== undefined &&
|
||||
knowledgeSubTypeTextMap[item.res_sub_type];
|
||||
const knowledgeBizStatusTag =
|
||||
item.biz_res_status !== undefined &&
|
||||
knowledgeBizStatusTextMap[item.biz_res_status];
|
||||
return (
|
||||
<BaseLibraryItem
|
||||
resourceInfo={item}
|
||||
defaultIcon={DocDefaultIcon}
|
||||
tag={
|
||||
<>
|
||||
{safeJSONParse(item.biz_extend?.processing_file_id_list)?.length ? (
|
||||
<Tag
|
||||
data-testid="workspace.library.item.tag"
|
||||
color="brand"
|
||||
size="mini"
|
||||
className="flex-shrink-0 flex-grow-0"
|
||||
prefixIcon={<IconCozClock />}
|
||||
>
|
||||
{I18n.t('library_filter_tags_processing')}
|
||||
</Tag>
|
||||
) : null}
|
||||
{knowledgeTag ? (
|
||||
<Tag
|
||||
data-testid="workspace.library.item.tag"
|
||||
color="brand"
|
||||
size="mini"
|
||||
className="flex-shrink-0 flex-grow-0"
|
||||
>
|
||||
{I18n.t(knowledgeTag)}
|
||||
</Tag>
|
||||
) : null}
|
||||
{knowledgeBizStatusTag ? (
|
||||
<Tag
|
||||
data-testid="workspace.library.item.tag"
|
||||
color="red"
|
||||
size="mini"
|
||||
className="flex-shrink-0 flex-grow-0"
|
||||
>
|
||||
{I18n.t(knowledgeBizStatusTag)}
|
||||
</Tag>
|
||||
) : null}
|
||||
</>
|
||||
}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
const getTypeFilters = () => ({
|
||||
label: (
|
||||
<span data-testid="space.library.filter.knowledge">
|
||||
{I18n.t('library_resource_type_knowledge')}
|
||||
</span>
|
||||
),
|
||||
filterName: I18n.t('library_resource_type_knowledge'),
|
||||
value: ResType.Knowledge,
|
||||
children: [
|
||||
{
|
||||
label: (
|
||||
<span data-testid="space.library.filter.knowledge.all_types">
|
||||
{I18n.t('library_filter_tags_all_types')}
|
||||
</span>
|
||||
),
|
||||
value: -1,
|
||||
},
|
||||
{
|
||||
label: (
|
||||
<span data-testid="space.library.filter.knowledge.text">
|
||||
{I18n.t('library_filter_tags_text')}
|
||||
</span>
|
||||
),
|
||||
value: 0,
|
||||
},
|
||||
{
|
||||
label: (
|
||||
<span data-testid="space.library.filter.knowledge.table">
|
||||
{I18n.t('library_filter_tags_table')}
|
||||
</span>
|
||||
),
|
||||
value: 1,
|
||||
},
|
||||
{
|
||||
label: (
|
||||
<span data-testid="space.library.filter.knowledge.image">
|
||||
{I18n.t('library_filter_tags_image')}
|
||||
</span>
|
||||
),
|
||||
value: 2,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
export const useKnowledgeConfig: UseEntityConfigHook = ({
|
||||
spaceId,
|
||||
reloadList,
|
||||
getCommonActions,
|
||||
}) => {
|
||||
const navigate = useNavigate();
|
||||
const {
|
||||
modal: createKnowledgeModal,
|
||||
open: openCreateKnowledgeModal,
|
||||
close: closeCreateKnowledgeModal,
|
||||
} = useCreateKnowledgeModalV2({
|
||||
onFinish: (datasetID, unitType, shouldUpload) => {
|
||||
navigate(
|
||||
`/space/${spaceId}/knowledge/${datasetID}${shouldUpload ? '/upload' : ''}?type=${unitType}&from=create`,
|
||||
);
|
||||
closeCreateKnowledgeModal();
|
||||
},
|
||||
});
|
||||
|
||||
// 删除
|
||||
const { run: delKnowledge } = useRequest(
|
||||
(datasetId: string) =>
|
||||
KnowledgeApi.DeleteDataset({
|
||||
dataset_id: datasetId,
|
||||
}),
|
||||
{
|
||||
manual: true,
|
||||
onSuccess: () => {
|
||||
reloadList();
|
||||
Toast.success(I18n.t('Delete_success'));
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
// 开启开关
|
||||
const { run: enableKnowledge, loading } = useRequest(
|
||||
(enableStatus: boolean, record: ResourceInfo) =>
|
||||
KnowledgeApi.UpdateDataset({
|
||||
dataset_id: record.res_id,
|
||||
name: record.name,
|
||||
description: record.desc,
|
||||
icon_uri: record.biz_extend?.icon_uri, // 从业务字段获取
|
||||
status: enableStatus
|
||||
? DatasetStatus.DatasetReady
|
||||
: DatasetStatus.DatasetForbid,
|
||||
}),
|
||||
{
|
||||
manual: true,
|
||||
debounceWait: 300,
|
||||
onSuccess: reloadList,
|
||||
},
|
||||
);
|
||||
|
||||
return {
|
||||
modals: <>{createKnowledgeModal}</>,
|
||||
config: {
|
||||
typeFilter: getTypeFilters(),
|
||||
renderCreateMenu: () => (
|
||||
<Menu.Item
|
||||
data-testid="workspace.library.header.create.knowledge"
|
||||
icon={<IconCozKnowledge />}
|
||||
onClick={openCreateKnowledgeModal}
|
||||
>
|
||||
{I18n.t('library_resource_type_knowledge')}
|
||||
</Menu.Item>
|
||||
),
|
||||
target: [ResType.Knowledge],
|
||||
onItemClick: (item: ResourceInfo) => {
|
||||
navigate(`/space/${spaceId}/knowledge/${item.res_id}?from=library`);
|
||||
},
|
||||
renderItem: renderKnowledgeItem,
|
||||
renderActions: (item: ResourceInfo) => {
|
||||
const deleteDisabled = !item.actions?.find(
|
||||
action => action.key === ActionKey.Delete,
|
||||
)?.enable;
|
||||
// knowledge 资源启用状态开关 enable 的是否禁用状态(即switch标签的禁用状态)
|
||||
const enableDisabled = !item.actions?.find(
|
||||
action => action.key === ActionKey.EnableSwitch,
|
||||
)?.enable;
|
||||
|
||||
const deleteProps = {
|
||||
disabled: deleteDisabled,
|
||||
deleteDesc: I18n.t('library_delete_desc'),
|
||||
handler: () => {
|
||||
delKnowledge(item.res_id || '');
|
||||
},
|
||||
};
|
||||
|
||||
const enableProps = {
|
||||
actionKey: 'enable',
|
||||
actionText: I18n.t('library_actions_enable'),
|
||||
disabled: enableDisabled || loading,
|
||||
extActionDom: (
|
||||
<Switch
|
||||
size="mini"
|
||||
disabled={enableDisabled}
|
||||
loading={loading}
|
||||
defaultChecked={Boolean(
|
||||
item.biz_res_status !== KnowledgeBizStatus.Disabled,
|
||||
)}
|
||||
onChange={v => {
|
||||
enableKnowledge(v, item);
|
||||
}}
|
||||
/>
|
||||
),
|
||||
};
|
||||
|
||||
return (
|
||||
<TableAction
|
||||
deleteProps={deleteProps}
|
||||
actionList={[enableProps, ...(getCommonActions?.(item) ?? [])]}
|
||||
/>
|
||||
);
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
* 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 { useNavigate } from 'react-router-dom';
|
||||
import { useState } from 'react';
|
||||
|
||||
import {
|
||||
ActionKey,
|
||||
PluginType,
|
||||
ResType,
|
||||
type ResourceInfo,
|
||||
} from '@coze-arch/idl/plugin_develop';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import { PluginDevelopApi } from '@coze-arch/bot-api';
|
||||
import { useBotCodeEditOutPlugin } from '@coze-agent-ide/bot-plugin/hook';
|
||||
import { CreateFormPluginModal } from '@coze-agent-ide/bot-plugin/component';
|
||||
import { IconCozPlugin } from '@coze-arch/coze-design/icons';
|
||||
import { Menu, Tag, Toast, Table } from '@coze-arch/coze-design';
|
||||
|
||||
import { BaseLibraryItem } from '../../components/base-library-item';
|
||||
import PluginDefaultIcon from '../../assets/plugin_default_icon.png';
|
||||
import { type UseEntityConfigHook } from './types';
|
||||
|
||||
const { TableAction } = Table;
|
||||
|
||||
export const usePluginConfig: UseEntityConfigHook = ({
|
||||
spaceId,
|
||||
reloadList,
|
||||
getCommonActions,
|
||||
}) => {
|
||||
const [showFormPluginModel, setShowFormPluginModel] = useState(false);
|
||||
const navigate = useNavigate();
|
||||
const { modal: editPluginCodeModal, open } = useBotCodeEditOutPlugin({
|
||||
modalProps: {
|
||||
onSuccess: reloadList,
|
||||
},
|
||||
});
|
||||
|
||||
return {
|
||||
modals: (
|
||||
<>
|
||||
<CreateFormPluginModal
|
||||
isCreate={true}
|
||||
visible={showFormPluginModel}
|
||||
onSuccess={pluginID => {
|
||||
navigate(`/space/${spaceId}/plugin/${pluginID}`);
|
||||
reloadList();
|
||||
}}
|
||||
onCancel={() => {
|
||||
setShowFormPluginModel(false);
|
||||
}}
|
||||
/>
|
||||
{editPluginCodeModal}
|
||||
</>
|
||||
),
|
||||
config: {
|
||||
typeFilter: {
|
||||
label: I18n.t('library_resource_type_plugin'),
|
||||
value: ResType.Plugin,
|
||||
},
|
||||
renderCreateMenu: () => (
|
||||
<Menu.Item
|
||||
data-testid="workspace.library.header.create.plugin"
|
||||
icon={<IconCozPlugin />}
|
||||
onClick={() => {
|
||||
setShowFormPluginModel(true);
|
||||
}}
|
||||
>
|
||||
{I18n.t('library_resource_type_plugin')}
|
||||
</Menu.Item>
|
||||
),
|
||||
target: [ResType.Plugin],
|
||||
onItemClick: (item: ResourceInfo) => {
|
||||
if (
|
||||
item.res_type === ResType.Plugin &&
|
||||
item.res_sub_type === 2 //Plugin:1-Http; 2-App; 6-Local;
|
||||
) {
|
||||
const disable = !item.actions?.find(
|
||||
action => action.key === ActionKey.Delete,
|
||||
)?.enable;
|
||||
open(item.res_id || '', disable);
|
||||
} else {
|
||||
navigate(`/space/${spaceId}/plugin/${item.res_id}`);
|
||||
}
|
||||
},
|
||||
renderItem: item => (
|
||||
<BaseLibraryItem
|
||||
resourceInfo={item}
|
||||
defaultIcon={PluginDefaultIcon}
|
||||
tag={
|
||||
item.res_type === ResType.Plugin &&
|
||||
item.res_sub_type === PluginType.LOCAL ? (
|
||||
<Tag
|
||||
data-testid="workspace.library.item.tag"
|
||||
color="cyan"
|
||||
size="mini"
|
||||
className="flex-shrink-0 flex-grow-0"
|
||||
>
|
||||
{I18n.t('local_plugin_label')}
|
||||
</Tag>
|
||||
) : null
|
||||
}
|
||||
/>
|
||||
),
|
||||
renderActions: (item: ResourceInfo) => {
|
||||
const deleteDisabled = !item.actions?.find(
|
||||
action => action.key === ActionKey.Delete,
|
||||
)?.enable;
|
||||
|
||||
const deleteProps = {
|
||||
disabled: deleteDisabled,
|
||||
deleteDesc: I18n.t('library_delete_desc'),
|
||||
handler: async () => {
|
||||
await PluginDevelopApi.DelPlugin({ plugin_id: item.res_id });
|
||||
reloadList();
|
||||
Toast.success(I18n.t('Delete_success'));
|
||||
},
|
||||
};
|
||||
|
||||
return (
|
||||
<TableAction
|
||||
deleteProps={deleteProps}
|
||||
actionList={getCommonActions?.(item)}
|
||||
/>
|
||||
);
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,174 @@
|
||||
/*
|
||||
* 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 { useNavigate } from 'react-router-dom';
|
||||
import { useRef } from 'react';
|
||||
|
||||
import { useRequest } from 'ahooks';
|
||||
import {
|
||||
ActionKey,
|
||||
ResType,
|
||||
type ResourceInfo,
|
||||
} from '@coze-arch/idl/plugin_develop';
|
||||
import { type IntelligenceData } from '@coze-arch/idl/intelligence_api';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import { IconCozLightbulb } from '@coze-arch/coze-design/icons';
|
||||
import { Table, Menu, Toast } from '@coze-arch/coze-design';
|
||||
import { EVENT_NAMES, sendTeaEvent } from '@coze-arch/bot-tea';
|
||||
import { useFlags } from '@coze-arch/bot-flags';
|
||||
import { PlaygroundApi } from '@coze-arch/bot-api';
|
||||
import { useModal as useSelectIntelligenceModal } from '@coze-common/biz-components/select-intelligence-modal';
|
||||
import { usePromptConfiguratorModal } from '@coze-common/prompt-kit-adapter/create-prompt';
|
||||
|
||||
import { type UseEntityConfigHook } from './types';
|
||||
|
||||
const { TableAction } = Table;
|
||||
|
||||
export const usePromptConfig: UseEntityConfigHook = ({
|
||||
spaceId,
|
||||
isPersonalSpace = true,
|
||||
reloadList,
|
||||
getCommonActions,
|
||||
}) => {
|
||||
const navigate = useNavigate();
|
||||
const [FLAGS] = useFlags();
|
||||
const recordRef = useRef<ResourceInfo | null>(null);
|
||||
|
||||
const { open: openSelectIntelligenceModal, node: selectIntelligenceModal } =
|
||||
useSelectIntelligenceModal({
|
||||
spaceId,
|
||||
onSelect: (intelligence: IntelligenceData) => {
|
||||
const targetId = intelligence.basic_info?.id;
|
||||
const diffPromptResourceId = recordRef.current?.res_id;
|
||||
navigate(`/space/${spaceId}/bot/${targetId}`, {
|
||||
replace: true,
|
||||
state: {
|
||||
mode: 'diff',
|
||||
diffPromptResourceId,
|
||||
targetId,
|
||||
},
|
||||
});
|
||||
sendTeaEvent(EVENT_NAMES.compare_mode_front, {
|
||||
bot_id: targetId,
|
||||
compare_type: 'prompts',
|
||||
from: 'prompt_resource',
|
||||
source: 'bot_detail_page',
|
||||
action: 'start',
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
const { open: openCreatePrompt, node: promptConfiguratorModal } =
|
||||
usePromptConfiguratorModal({
|
||||
spaceId,
|
||||
source: 'resource_library',
|
||||
// 社区版暂不支持该功能
|
||||
enableDiff: FLAGS['bot.studio.prompt_diff'],
|
||||
onUpdateSuccess: reloadList,
|
||||
onDiff: ({ libraryId }) => {
|
||||
recordRef.current = {
|
||||
res_id: libraryId,
|
||||
};
|
||||
openSelectIntelligenceModal();
|
||||
},
|
||||
});
|
||||
|
||||
// 删除
|
||||
const { run: delPrompt } = useRequest(
|
||||
(promptId: string) =>
|
||||
PlaygroundApi.DeletePromptResource({
|
||||
prompt_resource_id: promptId,
|
||||
}),
|
||||
{
|
||||
manual: true,
|
||||
onSuccess: () => {
|
||||
reloadList();
|
||||
Toast.success(I18n.t('Delete_success'));
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
return {
|
||||
modals: (
|
||||
<>
|
||||
{selectIntelligenceModal}
|
||||
{promptConfiguratorModal}
|
||||
</>
|
||||
),
|
||||
config: {
|
||||
typeFilter: {
|
||||
label: I18n.t('library_resource_type_prompt'),
|
||||
value: ResType.Prompt,
|
||||
},
|
||||
renderCreateMenu: () => (
|
||||
<Menu.Item
|
||||
data-testid="workspace.library.header.create.prompt"
|
||||
icon={<IconCozLightbulb />}
|
||||
onClick={() => {
|
||||
sendTeaEvent(EVENT_NAMES.widget_create_click, {
|
||||
source: 'menu_bar',
|
||||
workspace_type: isPersonalSpace
|
||||
? 'personal_workspace'
|
||||
: 'team_workspace',
|
||||
});
|
||||
openCreatePrompt({
|
||||
mode: 'create',
|
||||
});
|
||||
}}
|
||||
>
|
||||
{I18n.t('creat_new_prompt_prompt')}
|
||||
</Menu.Item>
|
||||
),
|
||||
target: [ResType.Prompt],
|
||||
onItemClick: (record: ResourceInfo) => {
|
||||
recordRef.current = record;
|
||||
const canEdit = record.actions?.find(
|
||||
action => action.key === ActionKey.Edit,
|
||||
)?.enable;
|
||||
openCreatePrompt({
|
||||
mode: 'info',
|
||||
canEdit,
|
||||
editId: record.res_id || '',
|
||||
});
|
||||
},
|
||||
renderActions: (libraryResource: ResourceInfo) => (
|
||||
<TableAction
|
||||
deleteProps={{
|
||||
disabled: !libraryResource.actions?.find(
|
||||
action => action.key === ActionKey.Delete,
|
||||
)?.enable,
|
||||
deleteDesc: I18n.t('prompt_resource_delete_describ'),
|
||||
handler: () => {
|
||||
delPrompt(libraryResource.res_id || '');
|
||||
},
|
||||
}}
|
||||
editProps={{
|
||||
disabled: !libraryResource.actions?.find(
|
||||
action => action.key === ActionKey.Edit,
|
||||
)?.enable,
|
||||
handler: () => {
|
||||
openCreatePrompt({
|
||||
mode: 'edit',
|
||||
editId: libraryResource.res_id || '',
|
||||
});
|
||||
},
|
||||
}}
|
||||
actionList={getCommonActions?.(libraryResource)}
|
||||
/>
|
||||
),
|
||||
},
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { useWorkflowResourceAction } from '@coze-workflow/components';
|
||||
import { useUserInfo } from '@coze-foundation/account-adapter';
|
||||
import { ResType, WorkflowMode } from '@coze-arch/idl/plugin_develop';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import { IconCozChat, IconCozWorkflow } from '@coze-arch/coze-design/icons';
|
||||
import { Menu, Tag } from '@coze-arch/coze-design';
|
||||
|
||||
import { BaseLibraryItem } from '../../components/base-library-item';
|
||||
import WorkflowDefaultIcon from '../../assets/workflow_default_icon.png';
|
||||
import ImageFlowDefaultIcon from '../../assets/image_flow_default_icon.png';
|
||||
import { type UseEntityConfigHook } from './types';
|
||||
|
||||
const defaultIconMap: { [key in ResType]?: string } = {
|
||||
[ResType.Workflow]: WorkflowDefaultIcon,
|
||||
[ResType.Imageflow]: ImageFlowDefaultIcon,
|
||||
};
|
||||
|
||||
export const useWorkflowConfig: UseEntityConfigHook = ({
|
||||
spaceId,
|
||||
reloadList,
|
||||
getCommonActions,
|
||||
}) => {
|
||||
const userInfo = useUserInfo();
|
||||
const {
|
||||
workflowResourceModals,
|
||||
handleWorkflowResourceClick,
|
||||
renderWorkflowResourceActions,
|
||||
openCreateModal,
|
||||
} = useWorkflowResourceAction({
|
||||
spaceId,
|
||||
userId: userInfo?.user_id_str,
|
||||
refreshPage: reloadList,
|
||||
getCommonActions,
|
||||
});
|
||||
|
||||
return {
|
||||
modals: workflowResourceModals,
|
||||
config: {
|
||||
typeFilter: {
|
||||
label: I18n.t('library_resource_type_workflow'),
|
||||
value: ResType.Workflow,
|
||||
},
|
||||
parseParams: params => {
|
||||
// 工作流图像流合并之后 选中工作流需要同时也拉取出图像流
|
||||
if (params?.res_type_filter?.[0] === ResType.Workflow) {
|
||||
return {
|
||||
...params,
|
||||
is_get_imageflow: true,
|
||||
};
|
||||
}
|
||||
return params;
|
||||
},
|
||||
renderCreateMenu: () => (
|
||||
<>
|
||||
<Menu.Item
|
||||
data-testid="workspace.library.header.create.workflow"
|
||||
icon={<IconCozWorkflow />}
|
||||
onClick={() => {
|
||||
openCreateModal(WorkflowMode.Workflow);
|
||||
}}
|
||||
>
|
||||
{I18n.t('library_resource_type_workflow')}
|
||||
</Menu.Item>
|
||||
{/* 社区版本暂时不支持对话流 */}
|
||||
{!IS_OPEN_SOURCE ? (
|
||||
<Menu.Item
|
||||
data-testid="workspace.library.header.create.chatflow"
|
||||
icon={<IconCozChat />}
|
||||
onClick={() => {
|
||||
openCreateModal(WorkflowMode.ChatFlow);
|
||||
}}
|
||||
>
|
||||
{I18n.t('wf_chatflow_76')}
|
||||
</Menu.Item>
|
||||
) : null}
|
||||
</>
|
||||
),
|
||||
target: [ResType.Workflow, ResType.Imageflow],
|
||||
onItemClick: handleWorkflowResourceClick,
|
||||
renderItem: item => (
|
||||
<BaseLibraryItem
|
||||
resourceInfo={item}
|
||||
defaultIcon={
|
||||
item.res_type !== undefined
|
||||
? defaultIconMap[item.res_type]
|
||||
: undefined
|
||||
}
|
||||
tag={
|
||||
item.collaboration_enable === true ? (
|
||||
<Tag
|
||||
data-testid="workspace.library.item.tag"
|
||||
color="brand"
|
||||
size="mini"
|
||||
className="flex-shrink-0 flex-grow-0"
|
||||
>
|
||||
{I18n.t('library_filter_tags_collaboration')}
|
||||
</Tag>
|
||||
) : null
|
||||
}
|
||||
/>
|
||||
),
|
||||
renderResType: item =>
|
||||
item.res_type === ResType.Workflow &&
|
||||
item.res_sub_type === WorkflowMode.ChatFlow
|
||||
? I18n.t('wf_chatflow_76')
|
||||
: I18n.t('library_resource_type_workflow'),
|
||||
renderActions: renderWorkflowResourceActions,
|
||||
},
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,50 @@
|
||||
.selected-params {
|
||||
border:1px solid var(--semi-color-focus-border);
|
||||
outline:0
|
||||
}
|
||||
|
||||
.layout-content {
|
||||
height: calc(100%);
|
||||
|
||||
:global(.coz-layout-header) {
|
||||
padding-bottom: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.dropdown-options-6 {
|
||||
:global(.semi-cascader-option-lists) {
|
||||
height: 208px;
|
||||
}
|
||||
}
|
||||
|
||||
.dropdown-options-7 {
|
||||
:global(.semi-cascader-option-lists) {
|
||||
height: 242px;
|
||||
}
|
||||
}
|
||||
|
||||
.dropdown-options-8 {
|
||||
:global(.semi-cascader-option-lists) {
|
||||
height: 276px;
|
||||
}
|
||||
}
|
||||
|
||||
.dropdown-options-9 {
|
||||
:global(.semi-cascader-option-lists) {
|
||||
height: 310px;
|
||||
}
|
||||
}
|
||||
|
||||
.layout-header {
|
||||
.select {
|
||||
@apply shrink-0 !important;
|
||||
|
||||
min-width: 128px;
|
||||
}
|
||||
|
||||
.cascader{
|
||||
@apply shrink-0 !important;
|
||||
|
||||
min-width: 128px;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,299 @@
|
||||
/*
|
||||
* 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 { forwardRef, useImperativeHandle } from 'react';
|
||||
|
||||
import classNames from 'classnames';
|
||||
import { useInfiniteScroll } from 'ahooks';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import {
|
||||
Table,
|
||||
Select,
|
||||
Search,
|
||||
Layout,
|
||||
Cascader,
|
||||
Space,
|
||||
} from '@coze-arch/coze-design';
|
||||
import { renderHtmlTitle } from '@coze-arch/bot-utils';
|
||||
import { EVENT_NAMES, sendTeaEvent } from '@coze-arch/bot-tea';
|
||||
import {
|
||||
type ResType,
|
||||
type LibraryResourceListRequest,
|
||||
type ResourceInfo,
|
||||
} from '@coze-arch/bot-api/plugin_develop';
|
||||
import { PluginDevelopApi } from '@coze-arch/bot-api';
|
||||
|
||||
import { highlightFilterStyle } from '@/constants/filter-style';
|
||||
import { WorkspaceEmpty } from '@/components/workspace-empty';
|
||||
|
||||
import { type ListData, type BaseLibraryPageProps } from './types';
|
||||
import { useGetColumns } from './hooks/use-columns';
|
||||
import { useCachedQueryParams } from './hooks/use-cached-query-params';
|
||||
import {
|
||||
eventLibraryType,
|
||||
getScopeOptions,
|
||||
getStatusOptions,
|
||||
LIBRARY_PAGE_SIZE,
|
||||
} from './consts';
|
||||
import { LibraryHeader } from './components/library-header';
|
||||
|
||||
import s from './index.module.less';
|
||||
|
||||
export { useDatabaseConfig } from './hooks/use-entity-configs/use-database-config';
|
||||
export { usePluginConfig } from './hooks/use-entity-configs/use-plugin-config';
|
||||
export { useWorkflowConfig } from './hooks/use-entity-configs/use-workflow-config';
|
||||
export { usePromptConfig } from './hooks/use-entity-configs/use-prompt-config';
|
||||
export { useKnowledgeConfig } from './hooks/use-entity-configs/use-knowledge-config';
|
||||
export { type LibraryEntityConfig } from './types';
|
||||
export { type UseEntityConfigHook } from './hooks/use-entity-configs/types';
|
||||
export { BaseLibraryItem } from './components/base-library-item';
|
||||
|
||||
export const BaseLibraryPage = forwardRef<
|
||||
{ reloadList: () => void },
|
||||
BaseLibraryPageProps
|
||||
>(
|
||||
// eslint-disable-next-line @coze-arch/max-line-per-function
|
||||
({ spaceId, isPersonalSpace = true, entityConfigs }, ref) => {
|
||||
const { params, setParams, resetParams, hasFilter, ready } =
|
||||
useCachedQueryParams({
|
||||
spaceId,
|
||||
});
|
||||
|
||||
const listResp = useInfiniteScroll<ListData>(
|
||||
async prev => {
|
||||
if (!ready) {
|
||||
return {
|
||||
list: [],
|
||||
nextCursorId: undefined,
|
||||
hasMore: false,
|
||||
};
|
||||
}
|
||||
// 允许业务定制请求参数
|
||||
const resp = await PluginDevelopApi.LibraryResourceList(
|
||||
entityConfigs.reduce<LibraryResourceListRequest>(
|
||||
(res, config) => config.parseParams?.(res) ?? res,
|
||||
{
|
||||
...params,
|
||||
cursor: prev?.nextCursorId,
|
||||
space_id: spaceId,
|
||||
size: LIBRARY_PAGE_SIZE,
|
||||
},
|
||||
),
|
||||
);
|
||||
return {
|
||||
list: resp?.resource_list || [],
|
||||
nextCursorId: resp?.cursor,
|
||||
hasMore: !!resp?.has_more,
|
||||
};
|
||||
},
|
||||
{
|
||||
reloadDeps: [params, spaceId],
|
||||
},
|
||||
);
|
||||
|
||||
useImperativeHandle(ref, () => ({
|
||||
reloadList: listResp.reload,
|
||||
}));
|
||||
|
||||
const columns = useGetColumns({
|
||||
entityConfigs,
|
||||
reloadList: listResp.reload,
|
||||
isPersonalSpace,
|
||||
});
|
||||
|
||||
const typeFilterData = [
|
||||
{ label: I18n.t('library_filter_tags_all_types'), value: -1 },
|
||||
...entityConfigs.map(item => item.typeFilter).filter(filter => !!filter),
|
||||
];
|
||||
const scopeOptions = getScopeOptions();
|
||||
const statusOptions = getStatusOptions();
|
||||
|
||||
return (
|
||||
<Layout
|
||||
className={s['layout-content']}
|
||||
title={renderHtmlTitle(I18n.t('navigation_workspace_library'))}
|
||||
>
|
||||
<Layout.Header className={classNames(s['layout-header'], 'pb-0')}>
|
||||
<div className="w-full">
|
||||
<LibraryHeader entityConfigs={entityConfigs} />
|
||||
<div className="flex items-center justify-between">
|
||||
<Space>
|
||||
<Cascader
|
||||
data-testid="workspace.library.filter.type"
|
||||
className={s.cascader}
|
||||
style={
|
||||
params?.res_type_filter?.[0] !== -1
|
||||
? highlightFilterStyle
|
||||
: {}
|
||||
}
|
||||
dropdownClassName="[&_.semi-cascader-option-lists]:h-fit"
|
||||
showClear={false}
|
||||
value={params.res_type_filter}
|
||||
treeData={typeFilterData}
|
||||
onChange={v => {
|
||||
const typeFilter = typeFilterData.find(
|
||||
item =>
|
||||
item.value === ((v as Array<number>)?.[0] as number),
|
||||
);
|
||||
sendTeaEvent(EVENT_NAMES.workspace_action_front, {
|
||||
space_id: spaceId,
|
||||
space_type: isPersonalSpace ? 'personal' : 'teamspace',
|
||||
tab_name: 'library',
|
||||
action: 'filter',
|
||||
filter_type: 'types',
|
||||
filter_name: typeFilter?.filterName ?? typeFilter?.label,
|
||||
});
|
||||
|
||||
setParams(prev => ({
|
||||
...prev,
|
||||
res_type_filter: v as Array<number>,
|
||||
}));
|
||||
}}
|
||||
/>
|
||||
{!isPersonalSpace ? (
|
||||
<Select
|
||||
data-testid="workspace.library.filter.user"
|
||||
className={classNames(s.select)}
|
||||
style={
|
||||
params?.user_filter !== 0 ? highlightFilterStyle : {}
|
||||
}
|
||||
showClear={false}
|
||||
value={params.user_filter}
|
||||
optionList={scopeOptions}
|
||||
onChange={v => {
|
||||
sendTeaEvent(EVENT_NAMES.workspace_action_front, {
|
||||
space_id: spaceId,
|
||||
space_type: isPersonalSpace ? 'personal' : 'teamspace',
|
||||
tab_name: 'library',
|
||||
action: 'filter',
|
||||
filter_type: 'creators',
|
||||
filter_name: scopeOptions.find(
|
||||
item =>
|
||||
item.value ===
|
||||
((v as Array<number>)?.[0] as number),
|
||||
)?.label,
|
||||
});
|
||||
setParams(prev => ({
|
||||
...prev,
|
||||
user_filter: v as number,
|
||||
}));
|
||||
}}
|
||||
/>
|
||||
) : null}
|
||||
<Select
|
||||
data-testid="workspace.library.filter.status"
|
||||
className={s.select}
|
||||
style={
|
||||
params?.publish_status_filter !== 0
|
||||
? highlightFilterStyle
|
||||
: {}
|
||||
}
|
||||
showClear={false}
|
||||
value={params.publish_status_filter}
|
||||
optionList={statusOptions}
|
||||
onChange={v => {
|
||||
sendTeaEvent(EVENT_NAMES.workspace_action_front, {
|
||||
space_id: spaceId,
|
||||
space_type: isPersonalSpace ? 'personal' : 'teamspace',
|
||||
tab_name: 'library',
|
||||
action: 'filter',
|
||||
filter_type: 'status',
|
||||
filter_name: statusOptions.find(
|
||||
item =>
|
||||
item.value === ((v as Array<number>)?.[0] as number),
|
||||
)?.label,
|
||||
});
|
||||
setParams(prev => ({
|
||||
...prev,
|
||||
publish_status_filter: v as number,
|
||||
}));
|
||||
}}
|
||||
/>
|
||||
</Space>
|
||||
<Search
|
||||
data-testid="workspace.library.filter.name"
|
||||
className="!min-w-min"
|
||||
style={params.name ? highlightFilterStyle : {}}
|
||||
showClear={true}
|
||||
width={200}
|
||||
loading={listResp.loading}
|
||||
placeholder={I18n.t('workspace_library_search')}
|
||||
value={params.name}
|
||||
onSearch={v => {
|
||||
sendTeaEvent(EVENT_NAMES.search_front, {
|
||||
full_url: window.location.href,
|
||||
source: 'library',
|
||||
search_word: v,
|
||||
});
|
||||
setParams(prev => ({
|
||||
...prev,
|
||||
name: v,
|
||||
}));
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</Layout.Header>
|
||||
<Layout.Content>
|
||||
<Table
|
||||
data-testid="workspace.library.table"
|
||||
offsetY={178}
|
||||
tableProps={{
|
||||
loading: listResp.loading,
|
||||
dataSource: listResp.data?.list,
|
||||
columns,
|
||||
// 整行点击
|
||||
onRow: (record?: ResourceInfo) => {
|
||||
if (
|
||||
!record ||
|
||||
record.res_type === undefined ||
|
||||
record.detail_disable
|
||||
) {
|
||||
return {};
|
||||
}
|
||||
return {
|
||||
onClick: () => {
|
||||
sendTeaEvent(EVENT_NAMES.workspace_action_front, {
|
||||
space_id: spaceId,
|
||||
space_type: isPersonalSpace ? 'personal' : 'teamspace',
|
||||
tab_name: 'library',
|
||||
action: 'click',
|
||||
id: record.res_id,
|
||||
name: record.name,
|
||||
type:
|
||||
record.res_type && eventLibraryType[record.res_type],
|
||||
});
|
||||
entityConfigs
|
||||
.find(c => c.target.includes(record.res_type as ResType))
|
||||
?.onItemClick(record);
|
||||
},
|
||||
};
|
||||
},
|
||||
}}
|
||||
empty={
|
||||
<WorkspaceEmpty onClear={resetParams} hasFilter={hasFilter} />
|
||||
}
|
||||
enableLoad
|
||||
loadMode="cursor"
|
||||
strictDataSourceProp
|
||||
hasMore={listResp.data?.hasMore}
|
||||
onLoad={listResp.loadMore}
|
||||
/>
|
||||
</Layout.Content>
|
||||
</Layout>
|
||||
);
|
||||
},
|
||||
);
|
||||
@@ -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 CascaderData } from '@coze-arch/coze-design';
|
||||
import {
|
||||
type LibraryResourceListRequest,
|
||||
type ResType,
|
||||
type ResourceInfo,
|
||||
} from '@coze-arch/bot-api/plugin_develop';
|
||||
|
||||
export interface LibraryEntityConfig {
|
||||
/**
|
||||
* 资源类型筛选器配置,传入级联选择器的数据类型
|
||||
**/
|
||||
typeFilter?: CascaderData & ({ filterName: string } | { label: string });
|
||||
|
||||
/**
|
||||
* 允许各个业务定制请求参数的格式化逻辑,避免特化逻辑侵入到底层组件中
|
||||
* @param params 原始的 query 参数
|
||||
* @returns 格式化后的 query 参数
|
||||
*/
|
||||
parseParams?: (
|
||||
params: LibraryResourceListRequest,
|
||||
) => LibraryResourceListRequest;
|
||||
|
||||
/**
|
||||
* 渲染创建菜单
|
||||
* @param params 相关参数
|
||||
* @params params.spaceId 空间 ID
|
||||
* @params params.isPersonalSpace 是否是个人空间
|
||||
* @params params.reloadList 刷新列表 API
|
||||
* @returns 渲染结果
|
||||
*/
|
||||
renderCreateMenu?: () => ReactNode;
|
||||
|
||||
// #region 表格配置
|
||||
/**
|
||||
* 匹配数据项是否由当前配置控制渲染
|
||||
*/
|
||||
target: ResType[];
|
||||
/**
|
||||
* 表格行点击事件回调,一般用于打开详情弹窗或者跳转详情页
|
||||
* @param item 点击行数据;
|
||||
* @returns void;
|
||||
*/
|
||||
onItemClick: (item: ResourceInfo) => void;
|
||||
/**
|
||||
* 渲染表格资源信息列内容,不传则默认使用通用组件进行渲染
|
||||
* @param item 行数据
|
||||
* @returns 渲染结果
|
||||
*/
|
||||
renderItem?: (item: ResourceInfo) => ReactNode;
|
||||
/**
|
||||
* 渲染资源类型文案,缺省会使用 typeFilter 中的 label
|
||||
* @param resType
|
||||
* @returns
|
||||
*/
|
||||
renderResType?: (item: ResourceInfo) => string | undefined;
|
||||
/**
|
||||
* 渲染表格操作列内容
|
||||
* @param item 行数据
|
||||
* @param reloadList 刷新列表 API
|
||||
* @returns 渲染结果
|
||||
*/
|
||||
renderActions: (item: ResourceInfo, reloadList: () => void) => ReactNode;
|
||||
|
||||
// #endregion 表格配置
|
||||
}
|
||||
|
||||
export interface ListData {
|
||||
list: ResourceInfo[];
|
||||
hasMore: boolean;
|
||||
nextCursorId: string | undefined;
|
||||
}
|
||||
|
||||
export interface BaseLibraryPageProps {
|
||||
spaceId: string;
|
||||
isPersonalSpace?: boolean;
|
||||
entityConfigs: LibraryEntityConfig[];
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { MockSetList } from '@coze-agent-ide/bot-plugin/page';
|
||||
|
||||
const Plugin = ({
|
||||
toolID: propsToolID,
|
||||
}: {
|
||||
pluginID: string;
|
||||
spaceID: string;
|
||||
toolID: string;
|
||||
}) => <MockSetList toolID={propsToolID} />;
|
||||
|
||||
export default Plugin;
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { MockSetDetail } from '@coze-agent-ide/bot-plugin/page';
|
||||
|
||||
const Plugin = ({
|
||||
pluginID,
|
||||
spaceID,
|
||||
toolID: propsToolID,
|
||||
mocksetID: propsMocksetID,
|
||||
}: {
|
||||
pluginID: string;
|
||||
spaceID: string;
|
||||
toolID: string;
|
||||
mocksetID: string;
|
||||
}) => (
|
||||
<MockSetDetail
|
||||
toolID={propsToolID}
|
||||
mocksetID={propsMocksetID}
|
||||
pluginID={pluginID}
|
||||
spaceID={spaceID}
|
||||
/>
|
||||
);
|
||||
|
||||
export default Plugin;
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
import { PluginDetailPage } from '@coze-agent-ide/bot-plugin/page';
|
||||
|
||||
export default PluginDetailPage;
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
import { ToolDetailPage } from '@coze-agent-ide/bot-plugin/page';
|
||||
|
||||
export default ToolDetailPage;
|
||||
17
frontend/packages/studio/workspace/entry-base/src/typings.d.ts
vendored
Normal file
17
frontend/packages/studio/workspace/entry-base/src/typings.d.ts
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/// <reference types='@coze-arch/bot-typings' />
|
||||
71
frontend/packages/studio/workspace/entry-base/src/utils.ts
Normal file
71
frontend/packages/studio/workspace/entry-base/src/utils.ts
Normal file
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* 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 qs from 'qs';
|
||||
import { pick } from 'lodash-es';
|
||||
import { type PluginNavType } from '@coze-studio/bot-plugin-store/src/context';
|
||||
|
||||
/**
|
||||
* 比较两个对象是否相等,只比较指定的 key,通过 JSON.stringify 实现
|
||||
* @param obj1 对象1
|
||||
* @param obj2 对象2
|
||||
* @param keys 需要比较的 key
|
||||
* @returns 是否相等
|
||||
*/
|
||||
export function compareObjects<T>(
|
||||
obj1: T,
|
||||
obj2: T,
|
||||
keys: (keyof T)[],
|
||||
): boolean {
|
||||
const subset1 = pick(obj1, keys);
|
||||
const subset2 = pick(obj2, keys);
|
||||
return JSON.stringify(subset1) === JSON.stringify(subset2);
|
||||
}
|
||||
|
||||
export function resourceNavigate(
|
||||
navBase: string,
|
||||
pluginID: string,
|
||||
navigate: Function,
|
||||
): PluginNavType {
|
||||
return {
|
||||
// eslint-disable-next-line max-params
|
||||
toResource: (resource, rid, query, opts) =>
|
||||
rid
|
||||
? navigate(`${navBase}/${resource}/${rid}?${qs.stringify(query)}`, opts)
|
||||
: '',
|
||||
tool: (toolID, query, opts) =>
|
||||
navigate(
|
||||
`${navBase}/plugin/${pluginID}/tool/${toolID}?${qs.stringify(query)}`,
|
||||
opts,
|
||||
),
|
||||
mocksetList: (toolID, query, opts) =>
|
||||
navigate(
|
||||
`${navBase}/plugin/${pluginID}/tool/${toolID}/plugin-mock-set?${qs.stringify(query)}`,
|
||||
opts,
|
||||
),
|
||||
// eslint-disable-next-line max-params
|
||||
mocksetDetail: (toolID, mocksetID, query, opts) =>
|
||||
navigate(
|
||||
`${navBase}/plugin/${pluginID}/tool/${toolID}/plugin-mock-set/${mocksetID}?${qs.stringify(query)}`,
|
||||
opts,
|
||||
),
|
||||
cloudIDE: (query, opts) =>
|
||||
navigate(
|
||||
`${navBase}/plugin/${pluginID}/cloud-tool?${qs.stringify(query)}`,
|
||||
opts,
|
||||
),
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/tsconfig",
|
||||
"extends": "@coze-arch/ts-config/tsconfig.web.json",
|
||||
"compilerOptions": {
|
||||
"paths": {
|
||||
"@/*": ["./src/*"]
|
||||
},
|
||||
"types": [],
|
||||
"strictNullChecks": true,
|
||||
"noImplicitAny": true,
|
||||
"rootDir": "./src",
|
||||
"outDir": "./dist",
|
||||
"tsBuildInfoFile": "./dist/tsconfig.build.tsbuildinfo"
|
||||
},
|
||||
"include": ["src"],
|
||||
"references": [
|
||||
{
|
||||
"path": "../../../agent-ide/bot-plugin/entry/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../../../agent-ide/space-bot/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../../../arch/bot-api/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../../../arch/bot-error/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../../../arch/bot-flags/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../../../arch/bot-space-api/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../../../arch/bot-store/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../../../arch/bot-tea/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../../../arch/bot-typings/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../../../arch/bot-utils/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../../../arch/i18n/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../../../arch/idl/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../../../arch/logger/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../../../arch/report-events/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../../bot-utils/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../../../common/biz-components/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../../../common/chat-area/utils/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../../../common/coze-mitt/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../../../common/prompt-kit/adapter/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../../../common/prompt-kit/main/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../../../community/component/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../../../components/bot-semi/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../../components/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"
|
||||
},
|
||||
{
|
||||
"path": "../../../data/common/utils/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../../../data/knowledge/common/stores/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../../../data/knowledge/knowledge-ide-adapter/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../../../data/knowledge/knowledge-ide-base/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../../../data/knowledge/knowledge-modal-adapter/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../../../data/knowledge/knowledge-resource-processor-adapter/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../../../data/knowledge/knowledge-resource-processor-base/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../../../data/knowledge/knowledge-resource-processor-core/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../../../data/memory/database-v2-main/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../../../foundation/account-adapter/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../../../foundation/enterprise-store-adapter/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../../../foundation/layout/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../../../foundation/local-storage/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../../premium/premium-components-adapter/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../../premium/premium-store-adapter/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../project-entity-adapter/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../../stores/bot-plugin/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../../user-store/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../../../workflow/base/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../../../workflow/components/tsconfig.build.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
15
frontend/packages/studio/workspace/entry-base/tsconfig.json
Normal file
15
frontend/packages/studio/workspace/entry-base/tsconfig.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/tsconfig",
|
||||
"compilerOptions": {
|
||||
"composite": true
|
||||
},
|
||||
"references": [
|
||||
{
|
||||
"path": "./tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "./tsconfig.misc.json"
|
||||
}
|
||||
],
|
||||
"exclude": ["**/*"]
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"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",
|
||||
"paths": {
|
||||
"@/*": ["./src/*"]
|
||||
},
|
||||
"types": ["vitest/globals"],
|
||||
"strictNullChecks": true,
|
||||
"noImplicitAny": true
|
||||
}
|
||||
}
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
import { defineConfig } from '@coze-arch/vitest-config';
|
||||
|
||||
export default defineConfig({
|
||||
dirname: __dirname,
|
||||
preset: 'web',
|
||||
});
|
||||
@@ -0,0 +1,5 @@
|
||||
const { defineConfig } = require('@coze-arch/stylelint-config');
|
||||
|
||||
module.exports = defineConfig({
|
||||
extends: [],
|
||||
});
|
||||
@@ -0,0 +1,16 @@
|
||||
# @coze-studio/project-entity-adapter
|
||||
|
||||
> 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,44 @@
|
||||
{
|
||||
"name": "@coze-studio/project-entity-adapter",
|
||||
"version": "0.0.1",
|
||||
"description": "project entity crud",
|
||||
"license": "Apache-2.0",
|
||||
"author": "gaoyuanhan.duty@bytedance.com",
|
||||
"maintainers": [],
|
||||
"main": "src/index.ts",
|
||||
"scripts": {
|
||||
"build": "exit 0",
|
||||
"dev": "exit 0",
|
||||
"lint": "eslint ./ --cache",
|
||||
"test": "vitest --run --passWithNoTests",
|
||||
"test:cov": "npm run test -- --coverage"
|
||||
},
|
||||
"dependencies": {
|
||||
"@coze-studio/project-entity-base": "workspace:*",
|
||||
"@coze-arch/idl": "workspace:*"
|
||||
},
|
||||
"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",
|
||||
"typescript": "~5.8.2",
|
||||
"vite-plugin-svgr": "~3.3.0",
|
||||
"vitest": "~3.0.5"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=18.2.0",
|
||||
"react-dom": ">=18.2.0"
|
||||
}
|
||||
}
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
export {
|
||||
useDeleteIntelligence,
|
||||
type ProjectFormValues,
|
||||
type UpdateProjectSuccessCallbackParam,
|
||||
type CreateProjectHookProps,
|
||||
type CopyProjectSuccessCallbackParam,
|
||||
type ModifyUploadValueType,
|
||||
type RequireCopyProjectRequest,
|
||||
type DeleteIntelligenceParam,
|
||||
} from '@coze-studio/project-entity-base';
|
||||
import { type ReactNode } from 'react';
|
||||
|
||||
import { type DraftProjectCopyRequest } from '@coze-arch/idl/intelligence_api';
|
||||
import {
|
||||
useCreateProjectModalBase,
|
||||
useUpdateProjectModalBase,
|
||||
useCopyProjectModalBase,
|
||||
type ProjectFormValues,
|
||||
type UpdateProjectSuccessCallbackParam,
|
||||
type CreateProjectHookProps,
|
||||
type CopyProjectSuccessCallbackParam,
|
||||
type ModifyUploadValueType,
|
||||
type RequireCopyProjectRequest,
|
||||
} from '@coze-studio/project-entity-base';
|
||||
|
||||
export const useCreateProjectModal = (
|
||||
params: CreateProjectHookProps,
|
||||
): {
|
||||
modalContextHolder: ReactNode;
|
||||
createProject: () => void;
|
||||
} => useCreateProjectModalBase(params);
|
||||
|
||||
export const useUpdateProjectModal = (params: {
|
||||
onSuccess?: (param: UpdateProjectSuccessCallbackParam) => void;
|
||||
}): {
|
||||
modalContextHolder: ReactNode;
|
||||
openModal: (params: { initialValue: ProjectFormValues }) => void;
|
||||
} => useUpdateProjectModalBase(params);
|
||||
|
||||
export const useCopyProjectModal = (params: {
|
||||
onSuccess?: (param: CopyProjectSuccessCallbackParam) => void;
|
||||
}): {
|
||||
modalContextHolder: ReactNode;
|
||||
openModal: (param: {
|
||||
initialValue: ModifyUploadValueType<
|
||||
RequireCopyProjectRequest<DraftProjectCopyRequest>
|
||||
>;
|
||||
}) => void;
|
||||
} => useCopyProjectModalBase(params);
|
||||
17
frontend/packages/studio/workspace/project-entity-adapter/src/typings.d.ts
vendored
Normal file
17
frontend/packages/studio/workspace/project-entity-adapter/src/typings.d.ts
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/// <reference types='@coze-arch/bot-typings' />
|
||||
@@ -0,0 +1,37 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/tsconfig",
|
||||
"extends": "@coze-arch/ts-config/tsconfig.web.json",
|
||||
"compilerOptions": {
|
||||
"types": [],
|
||||
"strictNullChecks": true,
|
||||
"noImplicitAny": true,
|
||||
"noUncheckedIndexedAccess": true,
|
||||
"rootDir": "./src",
|
||||
"outDir": "./dist",
|
||||
"tsBuildInfoFile": "./dist/tsconfig.build.tsbuildinfo"
|
||||
},
|
||||
"include": ["src"],
|
||||
"references": [
|
||||
{
|
||||
"path": "../../../arch/bot-typings/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../../../arch/idl/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"
|
||||
},
|
||||
{
|
||||
"path": "../project-entity-base/tsconfig.build.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/tsconfig",
|
||||
"exclude": ["**/*"],
|
||||
"compilerOptions": {
|
||||
"composite": true
|
||||
},
|
||||
"references": [
|
||||
{
|
||||
"path": "./tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "./tsconfig.misc.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"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,
|
||||
"noUncheckedIndexedAccess": true
|
||||
}
|
||||
}
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
import { defineConfig } from '@coze-arch/vitest-config';
|
||||
|
||||
export default defineConfig({
|
||||
dirname: __dirname,
|
||||
preset: 'web',
|
||||
});
|
||||
@@ -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-studio/project-entity-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,62 @@
|
||||
{
|
||||
"name": "@coze-studio/project-entity-base",
|
||||
"version": "0.0.1",
|
||||
"description": "project entity crud",
|
||||
"license": "Apache-2.0",
|
||||
"author": "gaoyuanhan.duty@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-agent-ide/bot-input-length-limit": "workspace:*",
|
||||
"@coze-agent-ide/space-bot": "workspace:*",
|
||||
"@coze-arch/bot-api": "workspace:*",
|
||||
"@coze-arch/bot-studio-store": "workspace:*",
|
||||
"@coze-arch/bot-tea": "workspace:*",
|
||||
"@coze-arch/bot-utils": "workspace:*",
|
||||
"@coze-arch/coze-design": "0.0.6-alpha.346d77",
|
||||
"@coze-arch/i18n": "workspace:*",
|
||||
"@coze-arch/idl": "workspace:*",
|
||||
"@coze-common/biz-components": "workspace:*",
|
||||
"@coze-common/chat-area-utils": "workspace:*",
|
||||
"@coze-foundation/local-storage": "workspace:*",
|
||||
"@coze-studio/components": "workspace:*",
|
||||
"@coze-studio/entity-adapter": "workspace:*",
|
||||
"@douyinfe/semi-illustrations": "^2.36.0",
|
||||
"ahooks": "^3.7.8",
|
||||
"classnames": "^2.3.2",
|
||||
"lodash-es": "^4.17.21",
|
||||
"react-markdown": "^8.0.3",
|
||||
"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",
|
||||
"typescript": "~5.8.2",
|
||||
"vite-plugin-svgr": "~3.3.0",
|
||||
"vitest": "~3.0.5"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=18.2.0",
|
||||
"react-dom": ">=18.2.0"
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user