feat: manually mirror opencoze's code from bytedance
Change-Id: I09a73aadda978ad9511264a756b2ce51f5761adf
This commit is contained in:
31
frontend/packages/agent-ide/agent-publish/.storybook/main.js
Normal file
31
frontend/packages/agent-ide/agent-publish/.storybook/main.js
Normal file
@@ -0,0 +1,31 @@
|
||||
import { mergeConfig } from 'vite';
|
||||
import svgr from 'vite-plugin-svgr';
|
||||
|
||||
/** @type { import('@storybook/react-vite').StorybookConfig } */
|
||||
const config = {
|
||||
stories: ['../stories/**/*.mdx', '../stories/**/*.stories.tsx'],
|
||||
addons: [
|
||||
'@storybook/addon-links',
|
||||
'@storybook/addon-essentials',
|
||||
'@storybook/addon-onboarding',
|
||||
'@storybook/addon-interactions',
|
||||
],
|
||||
framework: {
|
||||
name: '@storybook/react-vite',
|
||||
options: {},
|
||||
},
|
||||
docs: {
|
||||
autodocs: 'tag',
|
||||
},
|
||||
viteFinal: config =>
|
||||
mergeConfig(config, {
|
||||
plugins: [
|
||||
svgr({
|
||||
svgrOptions: {
|
||||
native: false,
|
||||
},
|
||||
}),
|
||||
],
|
||||
}),
|
||||
};
|
||||
export default config;
|
||||
@@ -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/agent-ide/agent-publish/README.md
Normal file
16
frontend/packages/agent-ide/agent-publish/README.md
Normal file
@@ -0,0 +1,16 @@
|
||||
# @coze-agent-ide/agent-publish
|
||||
|
||||
> 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: {},
|
||||
});
|
||||
74
frontend/packages/agent-ide/agent-publish/package.json
Normal file
74
frontend/packages/agent-ide/agent-publish/package.json
Normal file
@@ -0,0 +1,74 @@
|
||||
{
|
||||
"name": "@coze-agent-ide/agent-publish",
|
||||
"version": "0.0.1",
|
||||
"description": "agent publish",
|
||||
"license": "Apache-2.0",
|
||||
"author": "gaoyuanhan.duty@bytedance.com",
|
||||
"maintainers": [],
|
||||
"main": "src/index.ts",
|
||||
"scripts": {
|
||||
"build": "exit 0",
|
||||
"lint": "eslint ./ --cache",
|
||||
"test": "vitest --run --passWithNoTests",
|
||||
"test:cov": "npm run test -- --coverage"
|
||||
},
|
||||
"dependencies": {
|
||||
"@blueprintjs/core": "^5.1.5",
|
||||
"@coze-agent-ide/agent-ide-commons": "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-hooks": "workspace:*",
|
||||
"@coze-arch/bot-icons": "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/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-arch/report-tti": "workspace:*",
|
||||
"@coze-foundation/layout": "workspace:*",
|
||||
"@coze-studio/bot-detail-store": "workspace:*",
|
||||
"@coze-studio/components": "workspace:*",
|
||||
"@coze-studio/open-auth": "workspace:*",
|
||||
"@coze-studio/premium-components-adapter": "workspace:*",
|
||||
"@coze-studio/publish-manage-hooks": "workspace:*",
|
||||
"@coze-studio/user-store": "workspace:*",
|
||||
"@douyinfe/semi-icons": "^2.36.0",
|
||||
"ahooks": "^3.7.8",
|
||||
"classnames": "^2.3.2",
|
||||
"copy-to-clipboard": "^3.3.3",
|
||||
"lodash-es": "^4.17.21",
|
||||
"nanoid": "^4.0.2",
|
||||
"react-markdown": "^8.0.3",
|
||||
"react-router-dom": "^6.22.0"
|
||||
},
|
||||
"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,46 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { useLocation } from 'react-router-dom';
|
||||
import { useEffect } from 'react';
|
||||
|
||||
import { AuthStatus } from '@coze-arch/idl/developer_api';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import { UIModal } from '@coze-arch/bot-semi';
|
||||
import { useResetLocationState } from '@coze-arch/bot-hooks';
|
||||
|
||||
// 三方授权失败,callback至发布页需要显式阻塞弹窗
|
||||
export const useAuthFail = () => {
|
||||
const { state } = useLocation();
|
||||
const { authFailMessage = '', authStatus } = (state ??
|
||||
history.state ??
|
||||
{}) as Record<string, unknown>;
|
||||
|
||||
const resetLocationState = useResetLocationState();
|
||||
|
||||
useEffect(() => {
|
||||
if (authStatus === AuthStatus.Unauthorized && authFailMessage) {
|
||||
resetLocationState();
|
||||
|
||||
UIModal.warning({
|
||||
title: I18n.t('bot_publish_columns_status_unauthorized'),
|
||||
content: authFailMessage as string,
|
||||
okText: I18n.t('got_it'),
|
||||
hasCancel: false,
|
||||
});
|
||||
}
|
||||
}, [authStatus, resetLocationState, authFailMessage]);
|
||||
};
|
||||
@@ -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 { useNavigate, useParams } from 'react-router-dom';
|
||||
import { useEffect, useCallback } from 'react';
|
||||
|
||||
import { useSafeState, useUnmountedRef } from 'ahooks';
|
||||
import { logger } from '@coze-arch/logger';
|
||||
import { type PluginAPIDetal } from '@coze-arch/idl/playground_api';
|
||||
import { type DynamicParams } from '@coze-arch/bot-typings/teamspace';
|
||||
import { getFlags } from '@coze-arch/bot-flags';
|
||||
import { type PluginPricingRule } from '@coze-arch/bot-api/plugin_develop';
|
||||
import {
|
||||
MonetizationEntityType,
|
||||
type BotMonetizationConfigData,
|
||||
} from '@coze-arch/bot-api/benefit';
|
||||
import {
|
||||
PlaygroundApi,
|
||||
PluginDevelopApi,
|
||||
benefitApi,
|
||||
} from '@coze-arch/bot-api';
|
||||
import { useBotModeStore } from '@coze-agent-ide/space-bot/store';
|
||||
import { type PublisherBotInfo } from '@coze-agent-ide/space-bot';
|
||||
|
||||
const DEFAULT_BOT_INFO: PublisherBotInfo = {
|
||||
name: '',
|
||||
description: '',
|
||||
prompt: '',
|
||||
};
|
||||
|
||||
// 获取plugin收费插件信息
|
||||
const getPricingRules: (
|
||||
pluginApiDetailMap?: Record<string | number, PluginAPIDetal>,
|
||||
) => Promise<PluginPricingRule[] | undefined> = async pluginApiDetailMap => {
|
||||
if (!pluginApiDetailMap) {
|
||||
return undefined;
|
||||
}
|
||||
const { pricing_rules } = await PluginDevelopApi.BatchGetPluginPricingRules({
|
||||
plugin_apis: Object.keys(pluginApiDetailMap)?.map(item => ({
|
||||
name: pluginApiDetailMap[item].name,
|
||||
plugin_id: pluginApiDetailMap[item].plugin_id,
|
||||
api_id: item,
|
||||
})),
|
||||
});
|
||||
return pricing_rules;
|
||||
};
|
||||
|
||||
// 是否有plugin
|
||||
const hasPluginApi: (
|
||||
pluginApiDetailMap?: Record<string | number, PluginAPIDetal>,
|
||||
) => boolean = pluginApiDetailMap =>
|
||||
!!(pluginApiDetailMap && Array.isArray(Object.keys(pluginApiDetailMap)));
|
||||
|
||||
export const useGetPublisherInitInfo: () => {
|
||||
botInfo: PublisherBotInfo;
|
||||
monetizeConfig: BotMonetizationConfigData | undefined;
|
||||
} = () => {
|
||||
const params = useParams<DynamicParams>();
|
||||
const navigate = useNavigate();
|
||||
const { bot_id, commit_version } = params;
|
||||
const unmountedRef = useUnmountedRef();
|
||||
const setIsCollaboration = useBotModeStore(s => s.setIsCollaboration);
|
||||
|
||||
const setSafeIsCollaboration = useCallback((currentState: boolean) => {
|
||||
/** if component is unmounted, stop update */
|
||||
if (unmountedRef.current) {
|
||||
return;
|
||||
}
|
||||
setIsCollaboration(currentState);
|
||||
}, []);
|
||||
const [botInfo, setBotInfo] =
|
||||
useSafeState<PublisherBotInfo>(DEFAULT_BOT_INFO);
|
||||
const [monetizeConfig, setMonetizeConfig] = useSafeState<
|
||||
BotMonetizationConfigData | undefined
|
||||
>();
|
||||
useEffect(() => {
|
||||
if (!bot_id) {
|
||||
navigate('/', { replace: true });
|
||||
return;
|
||||
}
|
||||
|
||||
(async () => {
|
||||
try {
|
||||
const FLAGS = getFlags();
|
||||
const [botInfoResp, monetizeResp] = await Promise.all([
|
||||
PlaygroundApi.GetDraftBotInfoAgw({ bot_id, commit_version }),
|
||||
FLAGS['bot.studio.monetize_config']
|
||||
? benefitApi.PublicGetBotMonetizationConfig({
|
||||
entity_id: bot_id,
|
||||
entity_type: MonetizationEntityType.Bot,
|
||||
})
|
||||
: Promise.resolve(undefined),
|
||||
]);
|
||||
setMonetizeConfig(monetizeResp?.data);
|
||||
const {
|
||||
bot_info,
|
||||
in_collaboration,
|
||||
branch,
|
||||
has_publish,
|
||||
bot_option_data,
|
||||
} = botInfoResp?.data ?? {};
|
||||
|
||||
// 获取plugin扣费信息
|
||||
let pluginPricingRules: Array<PluginPricingRule> = [];
|
||||
if (
|
||||
hasPluginApi(bot_option_data?.plugin_api_detail_map) &&
|
||||
!IS_OPEN_SOURCE
|
||||
) {
|
||||
pluginPricingRules =
|
||||
(await getPricingRules(bot_option_data?.plugin_api_detail_map)) ??
|
||||
[];
|
||||
}
|
||||
|
||||
const {
|
||||
name = '',
|
||||
prompt_info,
|
||||
description = '',
|
||||
bot_mode,
|
||||
business_type,
|
||||
} = bot_info;
|
||||
setBotInfo({
|
||||
name,
|
||||
prompt: prompt_info?.prompt ?? '',
|
||||
description,
|
||||
branch,
|
||||
botMode: bot_mode,
|
||||
hasPublished: has_publish,
|
||||
pluginPricingRules,
|
||||
businessType: business_type,
|
||||
});
|
||||
|
||||
setSafeIsCollaboration(!!in_collaboration);
|
||||
} catch (error) {
|
||||
logger.error({ error: error as Error });
|
||||
}
|
||||
})();
|
||||
}, []);
|
||||
|
||||
return {
|
||||
botInfo,
|
||||
monetizeConfig,
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,567 @@
|
||||
/* stylelint-disable declaration-no-important */
|
||||
/* stylelint-disable no-descending-specificity */
|
||||
/* stylelint-disable custom-property-pattern */
|
||||
.publish-header {
|
||||
@apply coz-bg-primary;
|
||||
|
||||
flex-shrink: 0;
|
||||
height: 74px;
|
||||
padding: 16px;
|
||||
border-bottom: 1px solid theme('colors.stroke.5');
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
align-self: stretch;
|
||||
justify-content: space-between;
|
||||
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.title {
|
||||
margin-left: 12px;
|
||||
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
font-style: normal;
|
||||
color: var(--light-color-black-black, #000);
|
||||
}
|
||||
}
|
||||
|
||||
.publish-table-wrapper {
|
||||
height: fit-content;
|
||||
margin-bottom: 24px;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 64px;
|
||||
}
|
||||
}
|
||||
|
||||
.publish-content {
|
||||
overflow-y: auto;
|
||||
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: auto;
|
||||
padding: 0;
|
||||
padding-top: 24px;
|
||||
}
|
||||
|
||||
.link-underline {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.publish-wrapper .publish-title-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
margin-top: 40px;
|
||||
margin-bottom: 16px;
|
||||
|
||||
font-size: 18px;
|
||||
line-height: 24px;
|
||||
color: var(--light-usage-text-color-text-0, #1c1d23);
|
||||
|
||||
.publish-title {
|
||||
margin: 0;
|
||||
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
line-height: 24px;
|
||||
color: var(--light-usage-text-color-text-0, #1c1d23);
|
||||
}
|
||||
}
|
||||
|
||||
.changelog-textarea_disabled {
|
||||
pointer-events: none;
|
||||
|
||||
:global {
|
||||
.semi-input-clearbtn {
|
||||
visibility: hidden;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.publish-desc {
|
||||
display: block;
|
||||
|
||||
margin-bottom: 16px;
|
||||
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
color: var(--Light-usage-text---color-text-1, rgb(29 28 35 / 80%));
|
||||
}
|
||||
|
||||
.publish-result-container .publish-result-tip {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
margin-bottom: 24px;
|
||||
padding: 24px;
|
||||
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
line-height: 24px;
|
||||
color: var(--light-color-black-black, #000);
|
||||
|
||||
:global {
|
||||
.semi-banner-extra {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.publish-footer {
|
||||
justify-content: flex-end;
|
||||
width: 100%;
|
||||
padding: 24px 0;
|
||||
}
|
||||
|
||||
.publish-wrapper .text-label {
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
font-style: normal;
|
||||
line-height: 24px;
|
||||
color: var(--Light-usage-text---color-text-0, #1C1D23);
|
||||
}
|
||||
|
||||
.text-area {
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
.publish-result-table {
|
||||
border-top: 1px solid var(--semi-color-border);
|
||||
|
||||
:global {
|
||||
.semi-table-header {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.semi-table-row:hover>.semi-table-row-cell {
|
||||
background-color: transparent !important;
|
||||
border-bottom: 1px solid var(--semi-color-border) !important;
|
||||
}
|
||||
|
||||
// tr hover 无样式
|
||||
.semi-table-row:hover>.semi-table-row-cell::before {
|
||||
content: '';
|
||||
width: 100%;
|
||||
height: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.publish-table {
|
||||
margin-top: 0;
|
||||
|
||||
.diff-icon {
|
||||
cursor: pointer !important;
|
||||
width: 14px;
|
||||
}
|
||||
|
||||
:global {
|
||||
.semi-table-container {
|
||||
background: #fff;
|
||||
border: 1px solid rgb(29 28 35 / 12%);
|
||||
// padding: 0 16px;
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
// 全选按钮不展示
|
||||
.semi-table-thead>.semi-table-row>.semi-table-row-head:first-child {
|
||||
.semi-table-selection-wrap {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.semi-table-header {
|
||||
border-top-left-radius: 12px;
|
||||
border-top-right-radius: 12px;
|
||||
}
|
||||
|
||||
.semi-table-body {
|
||||
border-bottom-right-radius: 12px;
|
||||
border-bottom-left-radius: 12px;
|
||||
|
||||
}
|
||||
|
||||
.semi-table-tbody>.semi-table-row:hover>.semi-table-row-cell {
|
||||
border-radius: 0 !important;
|
||||
}
|
||||
|
||||
.semi-table-thead>.semi-table-row>.semi-table-row-head {
|
||||
height: 40px;
|
||||
padding: 0;
|
||||
background-color: transparent;
|
||||
border-radius: unset;
|
||||
|
||||
// &:first-child {
|
||||
// padding-left: 12px;
|
||||
// }
|
||||
}
|
||||
|
||||
.semi-table-row {
|
||||
background-color: #fff !important;
|
||||
}
|
||||
|
||||
.semi-table-tbody .semi-table-row .semi-table-row-cell {
|
||||
padding: 10px 0 !important;
|
||||
line-height: 14px;
|
||||
|
||||
// &:first-child {
|
||||
// padding-left: 12px !important;
|
||||
// }
|
||||
}
|
||||
|
||||
.semi-table-tbody>.semi-table-row:last-child:hover>.semi-table-row-cell {
|
||||
border-bottom: none !important;
|
||||
}
|
||||
|
||||
.semi-table .semi-table-selection-wrap {
|
||||
width: 16px;
|
||||
}
|
||||
|
||||
// .semi-table-row:hover>.semi-table-row-cell {
|
||||
// background-color: #fff !important;
|
||||
// border-bottom: 1px solid var(--semi-color-border) !important;
|
||||
// }
|
||||
|
||||
// tr hover 无样式
|
||||
.semi-table-row:hover>.semi-table-row-cell::before {
|
||||
content: '';
|
||||
width: 100%;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
.semi-table-tbody>.semi-table-row:last-child>.semi-table-row-cell {
|
||||
border-bottom: none;
|
||||
}
|
||||
}
|
||||
|
||||
.orange-tag {
|
||||
margin-left: 8px;
|
||||
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
font-style: normal;
|
||||
line-height: 16px;
|
||||
color: var(--light-color-orange-orange-5, rgb(255 150 0 / 100%));
|
||||
|
||||
background: var(--light-color-orange-orange-1, #FFF1CC);
|
||||
border-radius: 6px;
|
||||
|
||||
svg {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
margin-left: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
.grey-info {
|
||||
padding: 5px;
|
||||
color: var(--light-color-grey-grey-5, rgb(107 107 117 / 100%));
|
||||
background: var(--light-color-grey-grey-1, #F0F0F5);
|
||||
border-radius: 6px;
|
||||
|
||||
svg {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.disable-tooltip {
|
||||
position: absolute;
|
||||
top: 2px;
|
||||
left: 0;
|
||||
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
.platform-avater {
|
||||
flex-shrink: 0;
|
||||
|
||||
width: 26px;
|
||||
height: 26px;
|
||||
|
||||
background: #fff;
|
||||
border: 1px solid var(--light-usage-fill-color-fill-1, rgb(46 46 56 / 8%));
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.platform-name {
|
||||
max-width: 140px !important;
|
||||
|
||||
font-size: 14px !important;
|
||||
font-weight: 600 !important;
|
||||
line-height: 20px;
|
||||
color: var(--light-usage-text-color-text-0, #1c1d23);
|
||||
}
|
||||
|
||||
|
||||
|
||||
.platform-info {
|
||||
width: calc(100% - 50px);
|
||||
|
||||
.platform-desc {
|
||||
display: block;
|
||||
font-size: 12px;
|
||||
line-height: 16px;
|
||||
color: var(--light-usage-text-color-text-1, rgb(28 29 35 / 80%));
|
||||
}
|
||||
}
|
||||
|
||||
.config-status {
|
||||
.markdown {
|
||||
max-width: 265px;
|
||||
font-size: 12px;
|
||||
line-height: 16px;
|
||||
color: var(--light-usage-text-color-text-0, #1D1C23);
|
||||
}
|
||||
|
||||
:global {
|
||||
.semi-tag {
|
||||
margin-right: 4px;
|
||||
font-weight: 500;
|
||||
|
||||
svg {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
margin-left: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
.semi-button-borderless {
|
||||
height: 24px;
|
||||
padding: 0 8px;
|
||||
font-size: 12px;
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.config-area {
|
||||
.config-step-area {
|
||||
display: flex;
|
||||
// padding: 16px;
|
||||
// padding-bottom: 32px;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
align-items: flex-start;
|
||||
align-self: stretch;
|
||||
|
||||
margin-top: 32px;
|
||||
|
||||
border-radius: 8px;
|
||||
// border: 1px solid var(--light-usage-border-color-border-1, rgba(29, 28, 35, 0.12));
|
||||
|
||||
.step-order {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin-top: 2px;
|
||||
|
||||
font-size: 10px;
|
||||
font-weight: 600;
|
||||
color: var(--light-color-white-white, #fff);
|
||||
|
||||
background: var(--light-color-brand-brand-5, #4d53e8);
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.step-content {
|
||||
// gap: 8px;
|
||||
// display: flex;
|
||||
// flex-direction: column;
|
||||
}
|
||||
|
||||
.step-title {
|
||||
/* 157.143% */
|
||||
margin-bottom: 8px;
|
||||
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
line-height: 22px;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.step-link {
|
||||
margin-bottom: 8px;
|
||||
font-size: 14px;
|
||||
line-height: 22px;
|
||||
color: var(--light-usage-text-color-text-3, rgb(29 28 35 / 35%));
|
||||
}
|
||||
}
|
||||
|
||||
.config-form {
|
||||
width: 100%;
|
||||
|
||||
.disable-field {
|
||||
padding: 12px 0 24px;
|
||||
|
||||
.title {
|
||||
margin-bottom: 8px;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
|
||||
:global {
|
||||
.semi-form-field-label {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.semi-form-field-label-text {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
line-height: 22px;
|
||||
color: var(--Light-usage-text---color-text-0, #1D1C23);
|
||||
}
|
||||
}
|
||||
|
||||
.no-eye {
|
||||
:global {
|
||||
|
||||
// app_secret纯密文不展示眼睛
|
||||
.semi-input-modebtn {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
.start-text {
|
||||
font-size: 14px;
|
||||
line-height: 22px;
|
||||
color: var(--light-usage-text-color-text-0, #1D1C23);
|
||||
}
|
||||
|
||||
.config-link {
|
||||
font-size: 12px;
|
||||
line-height: 16px;
|
||||
color: var(--light-color-brand-brand-5, #4D53E8);
|
||||
|
||||
}
|
||||
|
||||
.step-order {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin-top: 2px;
|
||||
|
||||
font-size: 10px;
|
||||
font-weight: 600;
|
||||
color: var(--light-color-white-white, #fff);
|
||||
|
||||
background: var(--light-color-brand-brand-5, #4d53e8);
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.step-title {
|
||||
margin-bottom: 8px;
|
||||
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
line-height: 22px;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.markdown {
|
||||
font-size: 14px;
|
||||
line-height: 22px;
|
||||
color: var(--Light-usage-text---color-text-0, #1D1C23);
|
||||
}
|
||||
|
||||
|
||||
|
||||
.link-area {
|
||||
margin-top: 32px;
|
||||
}
|
||||
|
||||
.link-list {
|
||||
margin-top: 16px;
|
||||
|
||||
.title {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
line-height: 22px;
|
||||
color: var(--Light-usage-text---color-text-0, #1D1C23);
|
||||
|
||||
}
|
||||
|
||||
.semi-form-field-error-message {
|
||||
position: absolute;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.publish-modal {
|
||||
:global {
|
||||
.semi-modal {
|
||||
width: 560px;
|
||||
}
|
||||
|
||||
.semi-modal-content {
|
||||
.semi-modal-header {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.semi-modal-body {
|
||||
padding-bottom: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.semi-modal-footer {
|
||||
margin-top: 32px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.check-error {
|
||||
ul {
|
||||
margin: 0;
|
||||
padding-left: 14px;
|
||||
}
|
||||
|
||||
li {
|
||||
padding-top: 6px;
|
||||
}
|
||||
}
|
||||
|
||||
.diff-modal {
|
||||
:global {
|
||||
.semi-modal {
|
||||
width: 960px;
|
||||
}
|
||||
|
||||
.semi-modal-content {
|
||||
height: 740px;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.diff-modal-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
@@ -0,0 +1,200 @@
|
||||
/*
|
||||
* 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 { useMemo, useRef, useState } from 'react';
|
||||
|
||||
import { useRequest } from 'ahooks';
|
||||
import { userStoreService } from '@coze-studio/user-store';
|
||||
import { BackButton } from '@coze-foundation/layout';
|
||||
import { useReportTti } from '@coze-arch/report-tti';
|
||||
import {
|
||||
createReportEvent,
|
||||
REPORT_EVENTS as ReportEventNames,
|
||||
} from '@coze-arch/report-events';
|
||||
import { useErrorHandler } from '@coze-arch/logger';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import { type DynamicParams } from '@coze-arch/bot-typings/teamspace';
|
||||
import { SpaceApi } from '@coze-arch/bot-space-api';
|
||||
import { UILayout, UIButton, Spin, Tooltip } from '@coze-arch/bot-semi';
|
||||
import {
|
||||
Publish,
|
||||
type PublishConnectorInfo,
|
||||
type ConnectorBrandInfo,
|
||||
} from '@coze-arch/bot-api/developer_api';
|
||||
import {
|
||||
type PublishResultInfo,
|
||||
type PublishRef,
|
||||
PublishDisabledType,
|
||||
} from '@coze-agent-ide/space-bot';
|
||||
|
||||
import { PublishTableContext, PublishTable } from './publish-table';
|
||||
import { PublishResult } from './publish-result';
|
||||
import { useGetPublisherInitInfo } from './hooks/use-get-bot-info';
|
||||
import { useAuthFail } from './hooks/use-auth-fail';
|
||||
|
||||
import styles from './index.module.less';
|
||||
|
||||
const getPublishPlatformEvent = createReportEvent({
|
||||
eventName: ReportEventNames.publishPlatform,
|
||||
});
|
||||
|
||||
export const AgentPublishPage = () => {
|
||||
const params = useParams<DynamicParams>();
|
||||
const navigate = useNavigate();
|
||||
const errorHandler = useErrorHandler();
|
||||
|
||||
const { bot_id, commit_version } = params;
|
||||
|
||||
const { botInfo, monetizeConfig } = useGetPublisherInitInfo();
|
||||
|
||||
const [publishStatus, setPublishStatus] = useState(Publish.NoPublish);
|
||||
const [connectInfoList, setConnectInfoList] =
|
||||
useState<PublishConnectorInfo[]>();
|
||||
const [connectorBrandInfoMap, setConnectorBrandInfoMap] =
|
||||
useState<Record<string, ConnectorBrandInfo>>();
|
||||
const [publishResult, setPublishResult] = useState<PublishResultInfo>();
|
||||
const [publishDisabled, setPublishDisabled] = useState<PublishDisabledType>();
|
||||
const [publishLoading, setPublishLoading] = useState(false);
|
||||
const [canOpenSource, setCanOpenSource] = useState(false);
|
||||
const [publishTips, setPublishTips] = useState<string>('');
|
||||
const publishRef = useRef<PublishRef>(null);
|
||||
|
||||
const userAuthInfos = userStoreService.useUserAuthInfo();
|
||||
|
||||
useAuthFail();
|
||||
const { loading, refresh } = useRequest(
|
||||
async () => {
|
||||
const res = await SpaceApi.PublishConnectorList({
|
||||
bot_id: bot_id ?? '',
|
||||
commit_version,
|
||||
});
|
||||
return res;
|
||||
},
|
||||
{
|
||||
onBefore: () => {
|
||||
getPublishPlatformEvent.start();
|
||||
},
|
||||
onSuccess: data => {
|
||||
getPublishPlatformEvent.success();
|
||||
setConnectInfoList(data?.publish_connector_list);
|
||||
setConnectorBrandInfoMap(data?.connector_brand_info_map);
|
||||
setCanOpenSource(
|
||||
data?.submit_bot_market_option?.can_open_source ?? true,
|
||||
);
|
||||
setPublishTips(data?.publish_tips?.cost_tips ?? '');
|
||||
},
|
||||
onError: error => {
|
||||
getPublishPlatformEvent.error({ error, reason: error.message });
|
||||
errorHandler(error);
|
||||
},
|
||||
refreshDeps: [userAuthInfos],
|
||||
},
|
||||
);
|
||||
useReportTti({ isLive: !loading });
|
||||
const goBack = () => {
|
||||
navigate(`/space/${params.space_id}/bot/${params.bot_id}`);
|
||||
};
|
||||
|
||||
const handlePublish = () => {
|
||||
publishRef.current?.publish();
|
||||
};
|
||||
|
||||
const disabledTooltip = useMemo(() => {
|
||||
if (publishDisabled === PublishDisabledType.NotSelectCategory) {
|
||||
return I18n.t('publish_tooltip_select_category');
|
||||
} else if (publishDisabled === PublishDisabledType.NotSelectPlatform) {
|
||||
return I18n.t('publish_tooltip_select_platform');
|
||||
} else if (publishDisabled === PublishDisabledType.NotSelectIndustry) {
|
||||
return I18n.t('dy_avatar_evaluation_publish_tip');
|
||||
}
|
||||
}, [publishDisabled]);
|
||||
|
||||
const publishBtn = (
|
||||
<UIButton
|
||||
theme="solid"
|
||||
//解决异步请求botInfo未返回时可以点击publish产生的错误
|
||||
disabled={Boolean(publishDisabled) || !botInfo.name}
|
||||
loading={publishLoading}
|
||||
onClick={handlePublish}
|
||||
data-testid="agent-ide.publish-button"
|
||||
>
|
||||
{I18n.t('Publish')}
|
||||
</UIButton>
|
||||
);
|
||||
|
||||
return (
|
||||
<UILayout title={`${botInfo?.name} - Publish`}>
|
||||
<UILayout.Header className={styles['publish-header']}>
|
||||
<div className={styles.header}>
|
||||
<div className="flex items-center">
|
||||
<BackButton onClickBack={goBack} />
|
||||
<div className={styles.title}>
|
||||
{I18n.t('card_builder_releaseBtn_release_btn')}
|
||||
</div>
|
||||
</div>
|
||||
{publishStatus === Publish.NoPublish ? (
|
||||
disabledTooltip ? (
|
||||
<Tooltip content={disabledTooltip}>{publishBtn}</Tooltip>
|
||||
) : (
|
||||
publishBtn
|
||||
)
|
||||
) : (
|
||||
<UIButton
|
||||
theme="solid"
|
||||
onClick={() => {
|
||||
goBack();
|
||||
}}
|
||||
>
|
||||
{I18n.t('bot_publish_success_back')}
|
||||
</UIButton>
|
||||
)}
|
||||
</div>
|
||||
</UILayout.Header>
|
||||
|
||||
<UILayout.Content className={styles['publish-content']}>
|
||||
<PublishTableContext.Provider
|
||||
value={{
|
||||
publishLoading,
|
||||
refreshTableData: refresh,
|
||||
}}
|
||||
>
|
||||
<Spin spinning={loading} style={{ width: 800, margin: '0 auto' }}>
|
||||
{publishStatus === Publish.NoPublish ? (
|
||||
<PublishTable
|
||||
setPublishStatus={setPublishStatus}
|
||||
setPublishResult={setPublishResult}
|
||||
connectInfoList={connectInfoList ?? []}
|
||||
connectorBrandInfoMap={connectorBrandInfoMap ?? {}}
|
||||
botInfo={botInfo}
|
||||
monetizeConfig={monetizeConfig}
|
||||
publishTips={publishTips}
|
||||
getPublishDisabled={disabled => {
|
||||
setPublishDisabled(disabled);
|
||||
}}
|
||||
getPublishLoading={pubLoading => setPublishLoading(pubLoading)}
|
||||
ref={publishRef}
|
||||
canOpenSource={canOpenSource}
|
||||
/>
|
||||
) : (
|
||||
<PublishResult publishResult={publishResult} />
|
||||
)}
|
||||
</Spin>
|
||||
</PublishTableContext.Provider>
|
||||
</UILayout.Content>
|
||||
</UILayout>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,30 @@
|
||||
.config-status {
|
||||
.markdown {
|
||||
max-width: 265px;
|
||||
font-size: 12px;
|
||||
line-height: 16px;
|
||||
color: var(--light-usage-text-color-text-0, #1D1C23);
|
||||
}
|
||||
|
||||
:global {
|
||||
.semi-tag {
|
||||
margin-right: 4px;
|
||||
font-weight: 500;
|
||||
|
||||
svg {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
margin-left: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
.semi-button-borderless {
|
||||
height: 24px;
|
||||
padding: 0 8px;
|
||||
font-size: 12px;
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* 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 ReactMarkdown from 'react-markdown';
|
||||
|
||||
import copy from 'copy-to-clipboard';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import { Tooltip, UIButton, UITag, UIToast, Space } from '@coze-arch/bot-semi';
|
||||
import { CustomError } from '@coze-arch/bot-error';
|
||||
import { BindType } from '@coze-arch/bot-api/developer_api';
|
||||
import { IconInfoCircle } from '@douyinfe/semi-icons';
|
||||
|
||||
import { type ConnectResultInfo } from '../../typings';
|
||||
|
||||
import styles from './index.module.less';
|
||||
|
||||
interface PublishStatusProp {
|
||||
record: ConnectResultInfo;
|
||||
}
|
||||
|
||||
export const PublishResultArea = (props: PublishStatusProp) => {
|
||||
const { record } = props;
|
||||
|
||||
const onCopy = (text: string) => {
|
||||
const res = copy(text);
|
||||
if (!res) {
|
||||
throw new CustomError('normal_error', 'custom error');
|
||||
}
|
||||
UIToast.success({
|
||||
content: I18n.t('copy_success'),
|
||||
showClose: false,
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Space className={styles['config-status']}>
|
||||
{record.fail_text ? (
|
||||
<Tooltip
|
||||
content={
|
||||
record.fail_text ? (
|
||||
<ReactMarkdown
|
||||
skipHtml={true}
|
||||
className={styles.markdown}
|
||||
linkTarget="_blank"
|
||||
>
|
||||
{record.fail_text}
|
||||
</ReactMarkdown>
|
||||
) : null
|
||||
}
|
||||
>
|
||||
<UITag color={'green'}>
|
||||
{I18n.t('Success')}
|
||||
<IconInfoCircle />
|
||||
</UITag>
|
||||
</Tooltip>
|
||||
) : (
|
||||
<UITag color={'green'}>{I18n.t('Success')}</UITag>
|
||||
)}
|
||||
{record.share_link ? (
|
||||
<UIButton
|
||||
theme="borderless"
|
||||
onClick={() => {
|
||||
window.open(record.share_link);
|
||||
}}
|
||||
>
|
||||
{I18n.t('bot_list_open_button', {
|
||||
platform: record.name,
|
||||
})}
|
||||
</UIButton>
|
||||
) : null}
|
||||
{record.share_link ? (
|
||||
<UIButton
|
||||
theme="borderless"
|
||||
onClick={() => {
|
||||
onCopy(record.share_link);
|
||||
}}
|
||||
>
|
||||
{I18n.t('bot_publish_result_copy_bot_link')}
|
||||
</UIButton>
|
||||
) : null}
|
||||
{record.bind_type === BindType.ApiBind ? (
|
||||
<UIButton
|
||||
theme="borderless"
|
||||
onClick={() => window.open('/docs/developer_guides')}
|
||||
>
|
||||
{I18n.t('coze_api_instru')}
|
||||
</UIButton>
|
||||
) : null}
|
||||
</Space>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,282 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/* eslint-disable @coze-arch/max-line-per-function */
|
||||
import { NavLink, useParams } from 'react-router-dom';
|
||||
import ReactMarkdown from 'react-markdown';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
import { partition } from 'lodash-es';
|
||||
import classNames from 'classnames';
|
||||
import { useIsPublishRecordReady } from '@coze-studio/publish-manage-hooks';
|
||||
import { IntelligenceType } from '@coze-arch/idl/intelligence_api';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import { IconCozInfoCircleFill } from '@coze-arch/coze-design/icons';
|
||||
import { type DynamicParams } from '@coze-arch/bot-typings/teamspace';
|
||||
import { type ColumnProps } from '@coze-arch/bot-semi/Table';
|
||||
import {
|
||||
Avatar,
|
||||
Banner,
|
||||
UITable,
|
||||
UITag,
|
||||
Typography,
|
||||
Tag,
|
||||
Space,
|
||||
} from '@coze-arch/bot-semi';
|
||||
import { useFlags } from '@coze-arch/bot-flags';
|
||||
import {
|
||||
BindType,
|
||||
PublishResultStatus,
|
||||
} from '@coze-arch/bot-api/developer_api';
|
||||
import { PublishPlatformDescription } from '@coze-agent-ide/space-bot/component';
|
||||
import {
|
||||
type PublishResultInfo,
|
||||
type ConnectResultInfo,
|
||||
} from '@coze-agent-ide/space-bot';
|
||||
|
||||
import styles from '../index.module.less';
|
||||
import { PublishResultArea } from './component/publish-result-area';
|
||||
|
||||
interface PublishResultProps {
|
||||
// 隐藏Banner
|
||||
hiddenBanner?: boolean;
|
||||
publishResult?: PublishResultInfo;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line complexity
|
||||
export const PublishResult = ({
|
||||
hiddenBanner,
|
||||
publishResult,
|
||||
}: PublishResultProps) => {
|
||||
const { bot_id: botId, space_id: spaceId } = useParams<DynamicParams>();
|
||||
|
||||
const columns = useMemo(() => {
|
||||
const columnList: ColumnProps<ConnectResultInfo>[] = [
|
||||
{
|
||||
title: (
|
||||
<div className="pl-4">{I18n.t('bot_publish_columns_platform')}</div>
|
||||
),
|
||||
render: record => (
|
||||
<Space style={{ width: '100%' }} className="pl-4">
|
||||
<Avatar
|
||||
size="small"
|
||||
shape="square"
|
||||
src={record.icon}
|
||||
className={styles['platform-avater']}
|
||||
></Avatar>
|
||||
<Typography.Text
|
||||
className={styles['platform-name']}
|
||||
ellipsis={{
|
||||
showTooltip: {
|
||||
opts: {
|
||||
content: record?.name,
|
||||
style: { wordWrap: 'break-word' },
|
||||
},
|
||||
},
|
||||
}}
|
||||
>
|
||||
{record?.name}
|
||||
</Typography.Text>
|
||||
|
||||
{record?.desc ? (
|
||||
<PublishPlatformDescription desc={record.desc} />
|
||||
) : null}
|
||||
</Space>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: I18n.t('bot_publish_columns_result'),
|
||||
dataIndex: 'publish_status',
|
||||
width: 400,
|
||||
render: (status, record) => {
|
||||
const color =
|
||||
status === PublishResultStatus.InReview ? 'orange' : 'red';
|
||||
const showStatus =
|
||||
status === PublishResultStatus.InReview
|
||||
? I18n.t('bot_publish_columns_status_in_review')
|
||||
: I18n.t('bot_publish_columns_status_failed');
|
||||
switch (status) {
|
||||
case PublishResultStatus.Success:
|
||||
return record.id !== FLOW_PUBLISH_ID ? (
|
||||
<PublishResultArea record={record} />
|
||||
) : (
|
||||
<Space className={styles['config-status']}>
|
||||
<UITag color={'green'}>{I18n.t('Success')}</UITag>
|
||||
</Space>
|
||||
);
|
||||
case PublishResultStatus.InReview:
|
||||
case PublishResultStatus.Failed:
|
||||
return (
|
||||
<Space
|
||||
className={classNames(styles['config-status'], 'w-full pr-3')}
|
||||
>
|
||||
<Tag color={color} className="min-w-min ">
|
||||
{showStatus}
|
||||
</Tag>
|
||||
{record?.fail_text ? (
|
||||
<Typography.Text
|
||||
ellipsis={{
|
||||
showTooltip: {
|
||||
opts: {
|
||||
content: (
|
||||
<ReactMarkdown
|
||||
skipHtml
|
||||
className={styles.markdown}
|
||||
linkTarget="_blank"
|
||||
>
|
||||
{record.fail_text}
|
||||
</ReactMarkdown>
|
||||
),
|
||||
style: { wordWrap: 'break-word' },
|
||||
},
|
||||
},
|
||||
}}
|
||||
>
|
||||
{
|
||||
<ReactMarkdown
|
||||
skipHtml
|
||||
className={styles.markdown}
|
||||
linkTarget="_blank"
|
||||
>
|
||||
{record.fail_text}
|
||||
</ReactMarkdown>
|
||||
}
|
||||
</Typography.Text>
|
||||
) : null}
|
||||
</Space>
|
||||
);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
},
|
||||
},
|
||||
];
|
||||
return columnList;
|
||||
}, [publishResult]);
|
||||
|
||||
const isAllPlatformSuccess = publishResult?.connectorResult?.every(
|
||||
r => r.publish_status === PublishResultStatus.Success,
|
||||
);
|
||||
const isAllFailPublish = isAllPlatformSuccess
|
||||
? false
|
||||
: publishResult?.connectorResult?.every(
|
||||
item => item.publish_status === PublishResultStatus.Failed,
|
||||
);
|
||||
|
||||
const [publishResultForOpen, publishResultForChannel] = useMemo(
|
||||
() =>
|
||||
partition(publishResult?.connectorResult ?? [], d =>
|
||||
[BindType.ApiBind, BindType.WebSDKBind].includes(d?.bind_type),
|
||||
),
|
||||
[publishResult],
|
||||
);
|
||||
|
||||
const [FLAGS] = useFlags();
|
||||
|
||||
const { ready, inited } = useIsPublishRecordReady({
|
||||
type: IntelligenceType.Bot,
|
||||
spaceId: String(spaceId),
|
||||
intelligenceId: String(botId),
|
||||
// 社区版暂不支持该功能
|
||||
enable: FLAGS['bot.studio.publish_management'] && !IS_OPEN_SOURCE,
|
||||
});
|
||||
|
||||
return (
|
||||
<div className={styles['publish-result-container']}>
|
||||
{Boolean(publishResult?.connectorResult?.length) && (
|
||||
<section>
|
||||
{!hiddenBanner && (
|
||||
<Banner
|
||||
className="mb-[24px] p-[24px] flex flex-col"
|
||||
fullMode={false}
|
||||
type="info"
|
||||
bordered
|
||||
icon={null}
|
||||
closeIcon={null}
|
||||
data-testid="agent-ide.publish-result"
|
||||
>
|
||||
<div className={styles['publish-result-tip']}>
|
||||
{isAllFailPublish
|
||||
? `⚠️ ${I18n.t('publish_result_all_failed')}`
|
||||
: `🎉 ${I18n.t('publish_success')}`}
|
||||
</div>
|
||||
{/* 社区版暂不支持该功能 */}
|
||||
{IS_OVERSEA && !publishResult?.monetizeConfigSuccess ? (
|
||||
<div className="mt-[12px] flex items-center gap-[8px] coz-fg-primary">
|
||||
<IconCozInfoCircleFill className="coz-fg-hglt-yellow" />
|
||||
<span className="text-[12px] leading-[16px]">
|
||||
{I18n.t('monetization_publish_fail')}
|
||||
</span>
|
||||
</div>
|
||||
) : null}
|
||||
{/* 社区版暂不支持该功能 */}
|
||||
{FLAGS['bot.studio.publish_management'] && !IS_OPEN_SOURCE ? (
|
||||
<div className="coz-fg-dim text-[12px]">
|
||||
{I18n.t('release_management_detail1', {
|
||||
button: (
|
||||
<NavLink
|
||||
className={classNames(
|
||||
'no-underline',
|
||||
ready || !inited
|
||||
? 'coz-fg-hglt'
|
||||
: 'coz-fg-secondary cursor-not-allowed',
|
||||
)}
|
||||
onClick={e => {
|
||||
if (!ready) {
|
||||
e.preventDefault();
|
||||
}
|
||||
}}
|
||||
to={`/space/${spaceId}/publish/agent/${botId}`}
|
||||
>
|
||||
{I18n.t('release_management')}
|
||||
{ready || !inited
|
||||
? null
|
||||
: `(${I18n.t('release_management_generating')})`}
|
||||
</NavLink>
|
||||
),
|
||||
})}
|
||||
</div>
|
||||
) : null}
|
||||
</Banner>
|
||||
)}
|
||||
|
||||
{!!publishResultForChannel.length && (
|
||||
<UITable
|
||||
tableProps={{
|
||||
columns,
|
||||
dataSource: publishResultForChannel,
|
||||
className: classNames(styles['publish-table']),
|
||||
rowKey: 'id',
|
||||
}}
|
||||
wrapperClassName={styles['publish-table-wrapper']}
|
||||
/>
|
||||
)}
|
||||
{!!publishResultForOpen.length && (
|
||||
<UITable
|
||||
tableProps={{
|
||||
columns,
|
||||
dataSource: publishResultForOpen,
|
||||
className: classNames(styles['publish-table']),
|
||||
rowKey: 'id',
|
||||
}}
|
||||
wrapperClassName={styles['publish-table-wrapper']}
|
||||
/>
|
||||
)}
|
||||
</section>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {
|
||||
type PublishConnectorInfo,
|
||||
type PublishResultStatus,
|
||||
} from '@coze-arch/bot-api/developer_api';
|
||||
|
||||
export type ConnectResultInfo = PublishConnectorInfo & {
|
||||
publish_status: PublishResultStatus;
|
||||
fail_text?: string;
|
||||
};
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { createContext, useContext } from 'react';
|
||||
|
||||
export const PublishTableContext = createContext<{
|
||||
refreshTableData: () => void;
|
||||
publishLoading: boolean;
|
||||
}>({
|
||||
refreshTableData: () => undefined,
|
||||
publishLoading: false,
|
||||
});
|
||||
export const usePublishTableContext = () => useContext(PublishTableContext);
|
||||
|
||||
export const useRefreshPublishTableData = () =>
|
||||
useContext(PublishTableContext).refreshTableData;
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { type PublisherBotInfo } from '@coze-agent-ide/space-bot';
|
||||
import {
|
||||
BotConnectorStatus,
|
||||
ConfigStatus,
|
||||
UserAuthStatus,
|
||||
type PublishConnectorInfo,
|
||||
BindType,
|
||||
} from '@coze-arch/bot-api/developer_api';
|
||||
|
||||
const getAuthAndConfigSelectable = (item: PublishConnectorInfo) =>
|
||||
Boolean(
|
||||
item.is_last_published &&
|
||||
item.connector_status === BotConnectorStatus.Normal &&
|
||||
item.config_status === ConfigStatus.Configured &&
|
||||
item.auth_status === UserAuthStatus.Authorized,
|
||||
);
|
||||
|
||||
const getKvBindSelectable = (item: PublishConnectorInfo) =>
|
||||
Boolean(
|
||||
item.is_last_published &&
|
||||
item.bind_info &&
|
||||
item.config_status !== ConfigStatus.Disconnected &&
|
||||
item.connector_status !== BotConnectorStatus.InReview,
|
||||
);
|
||||
|
||||
const getAuthBindOrKvAuthBindSelectable = (item: PublishConnectorInfo) =>
|
||||
Boolean(
|
||||
item.is_last_published &&
|
||||
item.config_status === ConfigStatus.Configured &&
|
||||
item.connector_status !== BotConnectorStatus.InReview,
|
||||
);
|
||||
|
||||
const getApiBindOrWebSDKBindSelectable = (item: PublishConnectorInfo) =>
|
||||
Boolean(
|
||||
item.is_last_published &&
|
||||
item.config_status === ConfigStatus.Configured &&
|
||||
item.connector_status === BotConnectorStatus.Normal,
|
||||
);
|
||||
|
||||
export const getConnectorIsSelectable = (
|
||||
item: PublishConnectorInfo,
|
||||
botInfo: PublisherBotInfo,
|
||||
): boolean => {
|
||||
switch (item.bind_type) {
|
||||
case BindType.KvBind:
|
||||
return getKvBindSelectable(item);
|
||||
case BindType.AuthBind:
|
||||
case BindType.KvAuthBind:
|
||||
return getAuthBindOrKvAuthBindSelectable(item);
|
||||
case BindType.ApiBind:
|
||||
case BindType.WebSDKBind:
|
||||
return getApiBindOrWebSDKBindSelectable(item);
|
||||
case BindType.AuthAndConfig:
|
||||
return getAuthAndConfigSelectable(item);
|
||||
case BindType.StoreBind:
|
||||
return Boolean(!botInfo.hasPublished || item.is_last_published);
|
||||
default:
|
||||
return Boolean(
|
||||
item.is_last_published &&
|
||||
item.connector_status !== BotConnectorStatus.InReview,
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -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 { useParams } from 'react-router-dom';
|
||||
|
||||
import { useLockFn, useRequest } from 'ahooks';
|
||||
import { type PublisherBotInfo } from '@coze-agent-ide/space-bot';
|
||||
import { verifyBracesAndToast } from '@coze-studio/bot-detail-store';
|
||||
import {
|
||||
createReportEvent,
|
||||
REPORT_EVENTS as ReportEventNames,
|
||||
} from '@coze-arch/report-events';
|
||||
import { type DynamicParams } from '@coze-arch/bot-typings/teamspace';
|
||||
import { CustomError } from '@coze-arch/bot-error';
|
||||
import {
|
||||
type PublishDraftBotData,
|
||||
PublishType,
|
||||
} from '@coze-arch/bot-api/developer_api';
|
||||
import { DeveloperApi } from '@coze-arch/bot-api';
|
||||
|
||||
export interface UsePublishParamsType {
|
||||
botId: string;
|
||||
changeLog: string;
|
||||
connectors: Record<string, Record<string, string>>;
|
||||
publishId: string;
|
||||
}
|
||||
|
||||
export interface UsePublishProps {
|
||||
onSuccess: (res: PublishDraftBotData) => void;
|
||||
botInfo: PublisherBotInfo;
|
||||
}
|
||||
|
||||
export interface UsePublishType {
|
||||
handlePublishBot: (params: UsePublishParamsType) => void;
|
||||
loading: boolean;
|
||||
}
|
||||
|
||||
const publishBotEvent = createReportEvent({
|
||||
eventName: ReportEventNames.publishBot,
|
||||
});
|
||||
|
||||
const hasBracesErrorI18nKey = 'bot_prompt_bracket_error';
|
||||
|
||||
export const useConnectorsPublish = ({
|
||||
onSuccess,
|
||||
botInfo,
|
||||
}: UsePublishProps): UsePublishType => {
|
||||
const { commit_version, space_id = '' } = useParams<DynamicParams>();
|
||||
const { runAsync: publishBot, loading } = useRequest(
|
||||
async (params: UsePublishParamsType) => {
|
||||
const mode = botInfo.botMode;
|
||||
const { botId, changeLog, connectors, publishId } = params;
|
||||
|
||||
if (!verifyBracesAndToast(botInfo.prompt)) {
|
||||
throw new CustomError(
|
||||
ReportEventNames.publishBot,
|
||||
hasBracesErrorI18nKey,
|
||||
);
|
||||
}
|
||||
|
||||
const resp = await DeveloperApi.PublishDraftBot({
|
||||
space_id,
|
||||
bot_id: botId,
|
||||
history_info: changeLog,
|
||||
connectors,
|
||||
botMode: mode,
|
||||
publish_id: publishId,
|
||||
commit_version: commit_version ?? '',
|
||||
publish_type: PublishType.OnlinePublish,
|
||||
});
|
||||
|
||||
return resp.data;
|
||||
},
|
||||
{
|
||||
manual: true,
|
||||
onBefore: () => {
|
||||
publishBotEvent.start();
|
||||
},
|
||||
onSuccess: resp => {
|
||||
publishBotEvent.success();
|
||||
if (resp?.publish_result) {
|
||||
onSuccess(resp);
|
||||
}
|
||||
},
|
||||
onError: e => {
|
||||
if (e.message === hasBracesErrorI18nKey) {
|
||||
return;
|
||||
}
|
||||
publishBotEvent.error({
|
||||
error: e,
|
||||
reason: 'publish_bot_error',
|
||||
});
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
const handlePublishBot = useLockFn(async (params: UsePublishParamsType) => {
|
||||
await publishBot(params);
|
||||
});
|
||||
|
||||
return {
|
||||
handlePublishBot,
|
||||
loading,
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,588 @@
|
||||
/* stylelint-disable declaration-no-important */
|
||||
/* stylelint-disable no-descending-specificity */
|
||||
/* stylelint-disable custom-property-pattern */
|
||||
.header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
align-self: stretch;
|
||||
justify-content: space-between;
|
||||
|
||||
width: 100%;
|
||||
|
||||
background: #F7F7FA;
|
||||
|
||||
}
|
||||
|
||||
.publish-header {
|
||||
background: #F7F7FA;
|
||||
box-shadow: 0 2px 2px 0 rgb(29 28 35 / 4%), 0 0 2px 0 rgb(29 28 35 / 18%);
|
||||
|
||||
.exitbtn {
|
||||
margin-left: 12px;
|
||||
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
font-style: normal;
|
||||
line-height: 24px;
|
||||
color: var(--light-color-black-black, #000);
|
||||
}
|
||||
}
|
||||
|
||||
.publish-table-wrapper {
|
||||
height: fit-content;
|
||||
margin-bottom: 24px;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 64px;
|
||||
}
|
||||
}
|
||||
|
||||
.publish-content {
|
||||
overflow-y: auto;
|
||||
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: auto;
|
||||
padding: 0;
|
||||
padding-top: 24px;
|
||||
}
|
||||
|
||||
.link-underline {
|
||||
margin-left: 8px;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.publish-wrapper .publish-title-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
margin-top: 40px;
|
||||
margin-bottom: 16px;
|
||||
|
||||
font-size: 18px;
|
||||
line-height: 24px;
|
||||
color: var(--light-usage-text-color-text-0, #1c1d23);
|
||||
|
||||
.publish-title {
|
||||
margin: 0;
|
||||
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
line-height: 24px;
|
||||
color: var(--light-usage-text-color-text-0, #1c1d23);
|
||||
}
|
||||
}
|
||||
|
||||
.changelog-textarea_disabled {
|
||||
pointer-events: none;
|
||||
|
||||
:global {
|
||||
.semi-input-clearbtn {
|
||||
visibility: hidden;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.publish-desc {
|
||||
display: block;
|
||||
|
||||
margin-bottom: 16px;
|
||||
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
color: var(--Light-usage-text---color-text-1, rgb(29 28 35 / 80%));
|
||||
}
|
||||
|
||||
.publish-result-container {
|
||||
:global {
|
||||
.semi-banner-extra {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.publish-result-tip {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
line-height: 24px;
|
||||
color: var(--light-color-black-black, #000);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.publish-footer {
|
||||
justify-content: flex-end;
|
||||
width: 100%;
|
||||
padding: 24px 0;
|
||||
}
|
||||
|
||||
.publish-wrapper .text-label {
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
font-style: normal;
|
||||
line-height: 24px;
|
||||
color: var(--Light-usage-text---color-text-0, #1C1D23);
|
||||
}
|
||||
|
||||
.text-area {
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
.publish-result-table {
|
||||
border-top: 1px solid var(--semi-color-border);
|
||||
|
||||
:global {
|
||||
.semi-table-header {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.semi-table-row:hover>.semi-table-row-cell {
|
||||
background-color: transparent !important;
|
||||
border-bottom: 1px solid var(--semi-color-border) !important;
|
||||
}
|
||||
|
||||
.semi-table-row:hover>.semi-table-row-cell::before {
|
||||
content: '';
|
||||
width: 100%;
|
||||
height: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.publish-table {
|
||||
margin-top: 0;
|
||||
|
||||
.diff-icon {
|
||||
cursor: pointer !important;
|
||||
width: 14px;
|
||||
}
|
||||
|
||||
:global {
|
||||
.semi-table-container {
|
||||
background: #fff;
|
||||
border: 1px solid rgb(29 28 35 / 12%);
|
||||
// padding: 0 16px;
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
// 全选按钮不展示
|
||||
.semi-table-thead>.semi-table-row>.semi-table-row-head:first-child {
|
||||
.semi-table-selection-wrap {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.semi-table-header {
|
||||
border-top-left-radius: 12px;
|
||||
border-top-right-radius: 12px;
|
||||
}
|
||||
|
||||
.semi-table-body {
|
||||
border-bottom-right-radius: 12px;
|
||||
border-bottom-left-radius: 12px;
|
||||
|
||||
}
|
||||
|
||||
.semi-table-tbody>.semi-table-row:hover>.semi-table-row-cell {
|
||||
border-radius: 0 !important;
|
||||
}
|
||||
|
||||
.semi-table-thead>.semi-table-row>.semi-table-row-head {
|
||||
height: 40px;
|
||||
padding: 0;
|
||||
background-color: transparent;
|
||||
border-radius: unset;
|
||||
|
||||
// &:first-child {
|
||||
// padding-left: 12px;
|
||||
// }
|
||||
}
|
||||
|
||||
.semi-table-row {
|
||||
background-color: #fff !important;
|
||||
}
|
||||
|
||||
.semi-table-tbody .semi-table-row .semi-table-row-cell {
|
||||
padding: 10px 0 !important;
|
||||
line-height: 14px;
|
||||
|
||||
// &:first-child {
|
||||
// padding-left: 12px !important;
|
||||
// }
|
||||
}
|
||||
|
||||
.semi-table-tbody>.semi-table-row:last-child:hover>.semi-table-row-cell {
|
||||
border-bottom: none !important;
|
||||
}
|
||||
|
||||
.semi-table .semi-table-selection-wrap {
|
||||
width: 16px;
|
||||
}
|
||||
|
||||
// .semi-table-row:hover>.semi-table-row-cell {
|
||||
// background-color: #fff !important;
|
||||
// border-bottom: 1px solid var(--semi-color-border) !important;
|
||||
// }
|
||||
|
||||
// tr hover 无样式
|
||||
.semi-table-row:hover>.semi-table-row-cell::before {
|
||||
content: '';
|
||||
width: 100%;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
.semi-table-tbody>.semi-table-row:last-child>.semi-table-row-cell {
|
||||
border-bottom: none;
|
||||
}
|
||||
}
|
||||
|
||||
.common-tag {
|
||||
margin-left: 8px;
|
||||
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
font-style: normal;
|
||||
line-height: 16px;
|
||||
|
||||
border-radius: 6px;
|
||||
|
||||
svg {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
margin-left: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
.orange-tag {
|
||||
color: var(--light-color-orange-orange-5, rgb(255 150 0 / 100%));
|
||||
background: var(--light-color-orange-orange-1, #FFF1CC);
|
||||
.common-tag();
|
||||
}
|
||||
|
||||
.grey-info {
|
||||
padding: 5px;
|
||||
color: var(--light-color-grey-grey-5, rgb(107 107 117 / 100%));
|
||||
background: var(--light-color-grey-grey-1, #F0F0F5);
|
||||
border-radius: 6px;
|
||||
|
||||
svg {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.disable-tooltip {
|
||||
position: absolute;
|
||||
top: 2px;
|
||||
left: 0;
|
||||
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
.platform-avater {
|
||||
flex-shrink: 0;
|
||||
|
||||
width: 26px;
|
||||
height: 26px;
|
||||
|
||||
background: #fff;
|
||||
border: 1px solid var(--light-usage-fill-color-fill-1, rgb(46 46 56 / 8%));
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.platform-name {
|
||||
max-width: 140px !important;
|
||||
|
||||
font-size: 14px !important;
|
||||
font-weight: 600 !important;
|
||||
line-height: 20px;
|
||||
color: var(--light-usage-text-color-text-0, #1c1d23);
|
||||
}
|
||||
|
||||
|
||||
|
||||
.platform-info {
|
||||
width: calc(100% - 50px);
|
||||
|
||||
.platform-desc {
|
||||
display: block;
|
||||
font-size: 12px;
|
||||
line-height: 16px;
|
||||
color: var(--light-usage-text-color-text-1, rgb(28 29 35 / 80%));
|
||||
}
|
||||
}
|
||||
|
||||
.config-status {
|
||||
.markdown {
|
||||
font-size: 12px;
|
||||
line-height: 16px;
|
||||
color: var(--light-usage-text-color-text-0, #1D1C23);
|
||||
|
||||
:global {
|
||||
p {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
:global {
|
||||
.semi-tag {
|
||||
margin-right: 4px;
|
||||
font-weight: 500;
|
||||
|
||||
svg {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
margin-left: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
.semi-button-borderless {
|
||||
height: 24px;
|
||||
padding: 0 8px;
|
||||
font-size: 12px;
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.config-area {
|
||||
.config-step-area {
|
||||
display: flex;
|
||||
// padding: 16px;
|
||||
// padding-bottom: 32px;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
align-items: flex-start;
|
||||
align-self: stretch;
|
||||
|
||||
margin-top: 32px;
|
||||
|
||||
border-radius: 8px;
|
||||
// border: 1px solid var(--light-usage-border-color-border-1, rgba(29, 28, 35, 0.12));
|
||||
|
||||
.step-order {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin-top: 2px;
|
||||
|
||||
font-size: 10px;
|
||||
font-weight: 600;
|
||||
color: var(--light-color-white-white, #fff);
|
||||
|
||||
background: var(--light-color-brand-brand-5, #4d53e8);
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.step-content {
|
||||
// gap: 8px;
|
||||
// display: flex;
|
||||
// flex-direction: column;
|
||||
}
|
||||
|
||||
.step-title {
|
||||
/* 157.143% */
|
||||
margin-bottom: 8px;
|
||||
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
line-height: 22px;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.step-link {
|
||||
margin-bottom: 8px;
|
||||
font-size: 14px;
|
||||
line-height: 22px;
|
||||
color: var(--light-usage-text-color-text-3, rgb(29 28 35 / 35%));
|
||||
}
|
||||
}
|
||||
|
||||
.config-form {
|
||||
width: 100%;
|
||||
|
||||
.disable-field {
|
||||
padding: 12px 0 24px;
|
||||
|
||||
.title {
|
||||
margin-bottom: 8px;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
|
||||
:global {
|
||||
.semi-form-field-label {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.semi-form-field-label-text {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
line-height: 22px;
|
||||
color: var(--Light-usage-text---color-text-0, #1D1C23);
|
||||
}
|
||||
}
|
||||
|
||||
.no-eye {
|
||||
:global {
|
||||
|
||||
// app_secret纯密文不展示眼睛
|
||||
.semi-input-modebtn {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
.start-text {
|
||||
font-size: 14px;
|
||||
line-height: 22px;
|
||||
color: var(--light-usage-text-color-text-0, #1D1C23);
|
||||
}
|
||||
|
||||
.config-link {
|
||||
font-size: 12px;
|
||||
line-height: 16px;
|
||||
color: var(--light-color-brand-brand-5, #4D53E8);
|
||||
|
||||
}
|
||||
|
||||
.step-order {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin-top: 2px;
|
||||
|
||||
font-size: 10px;
|
||||
font-weight: 600;
|
||||
color: var(--light-color-white-white, #fff);
|
||||
|
||||
background: var(--light-color-brand-brand-5, #4d53e8);
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.step-title {
|
||||
margin-bottom: 8px;
|
||||
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
line-height: 22px;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.markdown {
|
||||
font-size: 14px;
|
||||
line-height: 22px;
|
||||
color: var(--Light-usage-text---color-text-0, #1D1C23);
|
||||
}
|
||||
|
||||
|
||||
|
||||
.link-area {
|
||||
margin-top: 32px;
|
||||
}
|
||||
|
||||
.link-list {
|
||||
margin-top: 16px;
|
||||
|
||||
.title {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
line-height: 22px;
|
||||
color: var(--Light-usage-text---color-text-0, #1D1C23);
|
||||
|
||||
}
|
||||
|
||||
.semi-form-field-error-message {
|
||||
position: absolute;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.publish-modal {
|
||||
:global {
|
||||
.semi-modal {
|
||||
width: 560px;
|
||||
}
|
||||
|
||||
.semi-modal-content {
|
||||
.semi-modal-header {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.semi-modal-body {
|
||||
padding-bottom: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.semi-modal-footer {
|
||||
margin-top: 32px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.check-error {
|
||||
ul {
|
||||
margin: 0;
|
||||
padding-left: 14px;
|
||||
}
|
||||
|
||||
li {
|
||||
padding-top: 6px;
|
||||
}
|
||||
}
|
||||
|
||||
.diff-modal {
|
||||
:global {
|
||||
.semi-modal {
|
||||
width: 960px;
|
||||
}
|
||||
|
||||
.semi-modal-content {
|
||||
height: 740px;
|
||||
}
|
||||
|
||||
.semi-modal-body{
|
||||
padding: 0 !important;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.diff-modal-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.table-row-icon-wrapper {
|
||||
:global(.semi-table-expand-icon) {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,256 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/* eslint-disable @coze-arch/max-line-per-function */
|
||||
import { useParams } from 'react-router-dom';
|
||||
import {
|
||||
type ForwardedRef,
|
||||
forwardRef,
|
||||
useEffect,
|
||||
useImperativeHandle,
|
||||
useMemo,
|
||||
useState,
|
||||
} from 'react';
|
||||
|
||||
import { nanoid } from 'nanoid';
|
||||
import classNames from 'classnames';
|
||||
import {
|
||||
PublishDisabledType,
|
||||
type PublisherBotInfo,
|
||||
type PublishRef,
|
||||
type PublishResultInfo,
|
||||
STORE_CONNECTOR_ID,
|
||||
getPublishResult,
|
||||
} from '@coze-agent-ide/space-bot';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import { IconCozEmpty, IconCozInfoCircleFill } from '@coze-arch/coze-design/icons';
|
||||
import { Tooltip } from '@coze-arch/coze-design';
|
||||
import { type DynamicParams } from '@coze-arch/bot-typings/teamspace';
|
||||
import { EVENT_NAMES, sendTeaEvent } from '@coze-arch/bot-tea';
|
||||
import { useSpaceStore } from '@coze-arch/bot-studio-store';
|
||||
import { Form, Space, TextArea } from '@coze-arch/bot-semi';
|
||||
import {
|
||||
AllowPublishStatus,
|
||||
type ConnectorBrandInfo,
|
||||
Publish,
|
||||
type PublishConnectorInfo,
|
||||
SpaceType,
|
||||
} from '@coze-arch/bot-api/developer_api';
|
||||
import { type BotMonetizationConfigData } from '@coze-arch/bot-api/benefit';
|
||||
import { PublishTermService } from '@coze-agent-ide/agent-ide-commons';
|
||||
|
||||
import { TableCollection } from './table-collection';
|
||||
import { useConnectorsPublish } from './hooks/use-connectors-publish';
|
||||
import { getConnectorIsSelectable } from './get-connector-selectable';
|
||||
|
||||
import styles from './index.module.less';
|
||||
export { PublishTableContext, usePublishTableContext } from './context';
|
||||
interface PublishTableProps {
|
||||
setPublishStatus: (status: Publish) => void;
|
||||
setPublishResult: (result: PublishResultInfo) => void;
|
||||
connectInfoList: PublishConnectorInfo[];
|
||||
connectorBrandInfoMap: Record<string, ConnectorBrandInfo>;
|
||||
botInfo: PublisherBotInfo;
|
||||
monetizeConfig?: BotMonetizationConfigData;
|
||||
getPublishDisabled: (disabledType: PublishDisabledType) => void;
|
||||
getPublishLoading: (loading: boolean) => void;
|
||||
canOpenSource: boolean;
|
||||
publishTips?: string;
|
||||
}
|
||||
|
||||
export const PublishTable = forwardRef(
|
||||
(
|
||||
{
|
||||
connectInfoList = [],
|
||||
connectorBrandInfoMap = {},
|
||||
setPublishStatus,
|
||||
setPublishResult,
|
||||
botInfo,
|
||||
monetizeConfig,
|
||||
getPublishDisabled,
|
||||
getPublishLoading,
|
||||
canOpenSource,
|
||||
publishTips,
|
||||
}: PublishTableProps,
|
||||
ref: ForwardedRef<PublishRef>,
|
||||
) => {
|
||||
const publishId = useMemo(() => nanoid(), []);
|
||||
const [dataSource, setDataSource] =
|
||||
useState<PublishConnectorInfo[]>(connectInfoList);
|
||||
|
||||
const [selectedPlatforms, setSelectedPlatforms] = useState<string[]>([]);
|
||||
|
||||
const { space_id: spaceId = '', bot_id: botId = '' } =
|
||||
useParams<DynamicParams>();
|
||||
|
||||
const { space_type: spaceType } = useSpaceStore(s => s.space);
|
||||
const [changeLog, setChangeLog] = useState('');
|
||||
const [hasCategoryList, setHasCategoryList] = useState(true);
|
||||
const isPersonal = spaceType === SpaceType.Personal;
|
||||
|
||||
useEffect(() => {
|
||||
if (connectInfoList?.length) {
|
||||
setDataSource(connectInfoList);
|
||||
const selectKeys = connectInfoList
|
||||
.filter(item => item.allow_punish === AllowPublishStatus.Allowed)
|
||||
.filter(item => getConnectorIsSelectable(item, botInfo))
|
||||
.map(node => node.id);
|
||||
setSelectedPlatforms(selectKeys);
|
||||
}
|
||||
}, [connectInfoList, botInfo]);
|
||||
|
||||
useImperativeHandle(ref, () => ({
|
||||
publish: () => handlePublish(),
|
||||
}));
|
||||
|
||||
const { loading: publishLoading, handlePublishBot } = useConnectorsPublish({
|
||||
onSuccess: resp => {
|
||||
setPublishStatus(Publish.HadPublished);
|
||||
const publishResult = getPublishResult(
|
||||
resp.publish_result ?? {},
|
||||
dataSource.filter(item => selectedPlatforms?.includes(item.id)),
|
||||
);
|
||||
setPublishResult({
|
||||
connectorResult: publishResult,
|
||||
marketResult: resp.submit_bot_market_result ?? {},
|
||||
monetizeConfigSuccess: resp.publish_monetization_result ?? false,
|
||||
});
|
||||
},
|
||||
botInfo,
|
||||
});
|
||||
|
||||
const notSelectPlatform = !selectedPlatforms?.length;
|
||||
|
||||
const notSelectCategory =
|
||||
hasCategoryList &&
|
||||
selectedPlatforms.includes(STORE_CONNECTOR_ID) &&
|
||||
!dataSource?.find(item => item.id === STORE_CONNECTOR_ID)?.bind_info
|
||||
?.category_id;
|
||||
|
||||
useEffect(() => {
|
||||
let publishDisableType;
|
||||
if (notSelectPlatform) {
|
||||
publishDisableType = PublishDisabledType.NotSelectPlatform;
|
||||
} else if (notSelectCategory) {
|
||||
publishDisableType = PublishDisabledType.NotSelectCategory;
|
||||
}
|
||||
|
||||
getPublishDisabled(publishDisableType);
|
||||
}, [notSelectPlatform, notSelectCategory]);
|
||||
|
||||
useEffect(() => {
|
||||
getPublishLoading(publishLoading);
|
||||
}, [publishLoading]);
|
||||
|
||||
const handlePublish = () => {
|
||||
const connectors: Record<string, Record<string, string>> = {};
|
||||
const list = dataSource.filter(item =>
|
||||
selectedPlatforms.includes(item.id),
|
||||
);
|
||||
list.forEach(i => {
|
||||
connectors[i.id] = i.bind_info;
|
||||
});
|
||||
|
||||
sendTeaEvent(EVENT_NAMES.bot_publish, {
|
||||
space_id: spaceId,
|
||||
bot_id: botId,
|
||||
publish_id: publishId,
|
||||
workspace_id: spaceId,
|
||||
workspace_type: isPersonal ? 'personal_workspace' : 'team_workspace',
|
||||
is_auto_gen_changelog_empty: true,
|
||||
is_changelog_empty: !changeLog,
|
||||
is_modified: false,
|
||||
});
|
||||
|
||||
handlePublishBot({
|
||||
botId,
|
||||
connectors,
|
||||
changeLog,
|
||||
publishId,
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={styles['publish-wrapper']}>
|
||||
<Form.Label
|
||||
text={I18n.t('bot_publish_changelog')}
|
||||
className={styles['text-label']}
|
||||
/>
|
||||
<TextArea
|
||||
disabled={publishLoading}
|
||||
className={classNames(styles['text-area'])}
|
||||
value={changeLog}
|
||||
rows={3}
|
||||
showClear
|
||||
maxCount={2000}
|
||||
maxLength={2000}
|
||||
onChange={setChangeLog}
|
||||
/>
|
||||
|
||||
<Space className={styles['publish-title-container']}>
|
||||
<Form.Label required className={styles['publish-title']}>
|
||||
{I18n.t('bot_publish_select_title')}
|
||||
</Form.Label>
|
||||
|
||||
{publishTips ? (
|
||||
<Tooltip content={publishTips}>
|
||||
<div className="coz-fg-hglt-yellow cursor-pointer text-[12px] font-[500]">
|
||||
<Space spacing={2}>
|
||||
<IconCozInfoCircleFill />
|
||||
<div>{I18n.t('coze_cost_sharing')}</div>
|
||||
</Space>
|
||||
</div>
|
||||
</Tooltip>
|
||||
) : null}
|
||||
</Space>
|
||||
<PublishTermService
|
||||
termServiceData={dataSource
|
||||
.filter(item => item.privacy_policy || item.user_agreement)
|
||||
?.map(i => ({
|
||||
name: i.name,
|
||||
icon: i.icon,
|
||||
privacy_policy: i.privacy_policy,
|
||||
user_agreement: i.user_agreement,
|
||||
}))}
|
||||
/>
|
||||
{dataSource.length ? (
|
||||
<TableCollection
|
||||
dataSource={dataSource}
|
||||
connectorBrandInfoMap={connectorBrandInfoMap ?? {}}
|
||||
setSelectedPlatforms={setSelectedPlatforms}
|
||||
selectedPlatforms={selectedPlatforms}
|
||||
setDataSource={setDataSource}
|
||||
canOpenSource={canOpenSource}
|
||||
setHasCategoryList={setHasCategoryList}
|
||||
botInfo={botInfo}
|
||||
monetizeConfig={monetizeConfig}
|
||||
disabled={publishLoading}
|
||||
/>
|
||||
) : (
|
||||
<div className="flex flex-col justify-center items-center w-full h-full gap-[4px] mt-[80px]">
|
||||
<IconCozEmpty className="w-[32px] h-[32px] coz-fg-dim" />
|
||||
<div className="text-[14px] font-medium coz-fg-primary">
|
||||
{I18n.t('publish_page_no_channel_status_title')}
|
||||
</div>
|
||||
<div className="text-[12px] coz-fg-primary">
|
||||
{I18n.t('publish_page_no_channel_status_desc')}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
},
|
||||
);
|
||||
@@ -0,0 +1,211 @@
|
||||
/*
|
||||
* 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 {
|
||||
Tag,
|
||||
Tooltip,
|
||||
Space,
|
||||
UITag,
|
||||
type UITagProps,
|
||||
} from '@coze-arch/bot-semi';
|
||||
import { IconInfoCircle } from '@coze-arch/bot-icons';
|
||||
import {
|
||||
AllowPublishStatus,
|
||||
BindType,
|
||||
BotConnectorStatus,
|
||||
ConfigStatus,
|
||||
UserAuthStatus,
|
||||
type PublishConnectorInfo,
|
||||
} from '@coze-arch/bot-api/developer_api';
|
||||
import {
|
||||
KvBindButton,
|
||||
DiffViewButton,
|
||||
AuthorizeButton,
|
||||
} from '@coze-agent-ide/space-bot/component';
|
||||
import { type ActionColumnProps } from '@coze-agent-ide/space-bot';
|
||||
|
||||
import styles from '../index.module.less';
|
||||
import { useAuthSuccess } from './hooks/use-auth-success';
|
||||
import { getConfigStatus } from './get-config-status';
|
||||
import { StoreBind, ApiBindButton } from './connector-action';
|
||||
|
||||
interface TipTagProps {
|
||||
showText: string;
|
||||
tip: string;
|
||||
tagProps?: UITagProps;
|
||||
}
|
||||
|
||||
const TipTag: React.FC<TipTagProps> = ({ showText, tip, tagProps }) => (
|
||||
<Tooltip content={tip}>
|
||||
{showText ? (
|
||||
<Tag className={styles['orange-tag']} color="orange" {...tagProps}>
|
||||
{showText}
|
||||
<IconInfoCircle />
|
||||
</Tag>
|
||||
) : (
|
||||
<IconInfoCircle className={styles['grey-info']} />
|
||||
)}
|
||||
</Tooltip>
|
||||
);
|
||||
|
||||
export const PublishConnectorAction: React.FC<ActionColumnProps> = ({
|
||||
record,
|
||||
setSelectedPlatforms,
|
||||
setDataSource,
|
||||
canOpenSource,
|
||||
botInfo,
|
||||
isMouseIn,
|
||||
selectedPlatforms,
|
||||
setHasCategoryList,
|
||||
dataSource,
|
||||
}) => {
|
||||
const revokeSuccess = (id: string) => {
|
||||
setDataSource((list: PublishConnectorInfo[]) => {
|
||||
const target = list.find(item => item.id === id);
|
||||
if (target) {
|
||||
target.config_status = ConfigStatus.NotConfigured;
|
||||
target.config_status_toast = undefined;
|
||||
target.auth_status = UserAuthStatus.UnAuthorized;
|
||||
}
|
||||
|
||||
return [...list];
|
||||
});
|
||||
setSelectedPlatforms(list => list.filter(i => i !== id));
|
||||
};
|
||||
|
||||
useAuthSuccess((id: string) => {
|
||||
const currentConnectorInfo = dataSource.find(item => item.id === id);
|
||||
if (
|
||||
currentConnectorInfo?.allow_punish === AllowPublishStatus.Allowed &&
|
||||
currentConnectorInfo?.connector_status === BotConnectorStatus.Normal &&
|
||||
currentConnectorInfo?.config_status === ConfigStatus.Configured
|
||||
) {
|
||||
setSelectedPlatforms(list => [...list, id]);
|
||||
}
|
||||
});
|
||||
|
||||
const action = (() => {
|
||||
switch (record.bind_type) {
|
||||
case BindType.KvBind: //仅绑定
|
||||
case BindType.KvAuthBind: //绑定+授权,取消绑定后自动取消授权
|
||||
return (
|
||||
<KvBindButton
|
||||
record={record}
|
||||
setDataSource={setDataSource}
|
||||
setSelectedPlatforms={setSelectedPlatforms}
|
||||
/>
|
||||
);
|
||||
case BindType.AuthBind:
|
||||
return record.auth_login_info ? (
|
||||
<AuthorizeButton
|
||||
origin="publish"
|
||||
id={record.id}
|
||||
channelName={record.name}
|
||||
status={record.config_status}
|
||||
revokeSuccess={revokeSuccess}
|
||||
authInfo={record.auth_login_info}
|
||||
isMouseIn={isMouseIn}
|
||||
/>
|
||||
) : null;
|
||||
case BindType.ApiBind:
|
||||
return <ApiBindButton />;
|
||||
case BindType.StoreBind:
|
||||
return (
|
||||
<StoreBind
|
||||
record={record}
|
||||
canOpenSource={canOpenSource}
|
||||
setDataSource={setDataSource}
|
||||
botInfo={botInfo}
|
||||
selectedPlatforms={selectedPlatforms}
|
||||
setHasCategoryList={setHasCategoryList}
|
||||
/>
|
||||
);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
})();
|
||||
|
||||
return (
|
||||
<div className="mr-7 flex gap-[8px]" onClick={e => e.stopPropagation()}>
|
||||
{record.config_status !== ConfigStatus.NotConfigured && (
|
||||
<DiffViewButton record={record} isMouseIn={isMouseIn} />
|
||||
)}
|
||||
{action}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const ConfigStatusColumn: React.FC<ActionColumnProps> = props => {
|
||||
const { record } = props;
|
||||
|
||||
if (record.config_status === ConfigStatus.Disconnected) {
|
||||
return (
|
||||
<Space>
|
||||
<TipTag
|
||||
showText={I18n.t('bot_publish_columns_status_disconnected')}
|
||||
tip={I18n.t('bot_publish_token_expired_notice', {
|
||||
platform: record.name,
|
||||
})}
|
||||
/>
|
||||
<PublishConnectorAction {...props} />
|
||||
</Space>
|
||||
);
|
||||
}
|
||||
|
||||
const { text, color } = getConfigStatus(record);
|
||||
|
||||
return (
|
||||
<Space
|
||||
className={styles['config-status']}
|
||||
style={{ justifyContent: 'space-between', width: '100%' }}
|
||||
>
|
||||
<div>
|
||||
{record?.config_status_toast ? (
|
||||
<TipTag
|
||||
showText={text}
|
||||
tip={record?.config_status_toast || ''}
|
||||
tagProps={{
|
||||
color,
|
||||
style: { margin: 0 },
|
||||
// 覆盖原来的orange-tag
|
||||
className: styles['common-tag'],
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<UITag color={color}>{text}</UITag>
|
||||
)}
|
||||
{record?.connector_status === BotConnectorStatus.Normal ? null : (
|
||||
<TipTag
|
||||
showText={
|
||||
record?.connector_status === BotConnectorStatus.InReview
|
||||
? I18n.t('bot_publish_columns_status_in_review')
|
||||
: I18n.t('bot_publish_columns_status_offline')
|
||||
}
|
||||
tip={
|
||||
record?.connector_status === BotConnectorStatus.InReview
|
||||
? I18n.t('bot_publish_in_review_notice')
|
||||
: I18n.t('bot_publish_offline_notice_no_certain_time', {
|
||||
platform: record?.name,
|
||||
})
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<PublishConnectorAction {...props} />
|
||||
</Space>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { useState } from 'react';
|
||||
|
||||
import { PatBody } from '@coze-studio/open-auth';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import { Modal } from '@coze-arch/coze-design';
|
||||
import { UIButton } from '@coze-arch/bot-semi';
|
||||
|
||||
export const ApiBindButton: React.FC = () => {
|
||||
const [visible, setVisible] = useState(false);
|
||||
|
||||
return (
|
||||
<>
|
||||
<UIButton
|
||||
theme="borderless"
|
||||
onClick={() => {
|
||||
setVisible(true);
|
||||
}}
|
||||
>
|
||||
{I18n.t('bot_publish_action_configure')}
|
||||
</UIButton>
|
||||
<Modal
|
||||
size="xl"
|
||||
title={I18n.t('settings_api_authorization')}
|
||||
visible={visible}
|
||||
onCancel={() => {
|
||||
setVisible(false);
|
||||
}}
|
||||
>
|
||||
<PatBody size="small" type="primary" />
|
||||
</Modal>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export { StoreBind } from './store-bind';
|
||||
export { ApiBindButton } from './api-bind-button';
|
||||
@@ -0,0 +1,282 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/* eslint-disable @coze-arch/max-line-per-function */
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { useEffect, type SetStateAction, useState } from 'react';
|
||||
|
||||
import { isEmpty, map } from 'lodash-es';
|
||||
import { useRequest } from 'ahooks';
|
||||
import { type PublisherBotInfo } from '@coze-agent-ide/space-bot';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import { type DynamicParams } from '@coze-arch/bot-typings/teamspace';
|
||||
import {
|
||||
Select,
|
||||
Space,
|
||||
Spin,
|
||||
Tooltip,
|
||||
Typography,
|
||||
UIIconButton,
|
||||
} from '@coze-arch/bot-semi';
|
||||
import { IconInfo } from '@coze-arch/bot-icons';
|
||||
import { ProductEntityType } from '@coze-arch/bot-api/product_api';
|
||||
import { type PublishConnectorInfo } from '@coze-arch/bot-api/developer_api';
|
||||
import { PlaygroundApi, ProductApi } from '@coze-arch/bot-api';
|
||||
|
||||
import { usePublishTableContext } from '../../context';
|
||||
|
||||
interface StoreBindProps {
|
||||
record: PublishConnectorInfo;
|
||||
canOpenSource: boolean;
|
||||
setDataSource: (value: SetStateAction<PublishConnectorInfo[]>) => void;
|
||||
botInfo: PublisherBotInfo;
|
||||
selectedPlatforms: string[];
|
||||
setHasCategoryList: (value: SetStateAction<boolean>) => void;
|
||||
}
|
||||
|
||||
enum BotSubmitStatus {
|
||||
Private = 'false',
|
||||
Public = 'true',
|
||||
}
|
||||
const OpenSourceConfig = {
|
||||
[BotSubmitStatus.Private]: {
|
||||
title: () => I18n.t('mkpl_bots_private_configuration'),
|
||||
desc: () => I18n.t('mkpl_bots_private_configuration_description'),
|
||||
},
|
||||
[BotSubmitStatus.Public]: {
|
||||
title: () => I18n.t('mkpl_bots_public_configuration'),
|
||||
desc: () => I18n.t('mkpl_bots_public_configuration_description'),
|
||||
},
|
||||
};
|
||||
// eslint-disable-next-line complexity
|
||||
export const StoreBind: React.FC<StoreBindProps> = ({
|
||||
record,
|
||||
canOpenSource,
|
||||
setDataSource,
|
||||
botInfo,
|
||||
selectedPlatforms,
|
||||
setHasCategoryList,
|
||||
}) => {
|
||||
const params = useParams<DynamicParams>();
|
||||
const [sourceConfig, setSourceConfig] = useState<boolean>(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (!record.bind_info?.open_source) {
|
||||
handleSelect('open_source', BotSubmitStatus.Private);
|
||||
}
|
||||
}, [record.bind_info]);
|
||||
|
||||
const getSpaceId = () => params.space_id || '';
|
||||
|
||||
useRequest(
|
||||
async () => {
|
||||
const res = await ProductApi.PublicGetTemplateWhiteListConfig(
|
||||
{},
|
||||
{ __disableErrorToast: true },
|
||||
);
|
||||
return res.data?.space_ids || [];
|
||||
},
|
||||
{
|
||||
onFinally: (_, data, e) => {
|
||||
// @ts-expect-error - skip
|
||||
if (!e && data.includes(getSpaceId())) {
|
||||
setSourceConfig(true);
|
||||
} else {
|
||||
setSourceConfig(false);
|
||||
// 兜底逻辑:如果出错,或不在白名单中,则自动更改为“私有配置”发布
|
||||
handleSelect('open_source', BotSubmitStatus.Private);
|
||||
}
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
const { data: categoryList } = useRequest(
|
||||
async () => {
|
||||
const res = await ProductApi.PublicGetProductCategoryList(
|
||||
{
|
||||
// 代表含义:无商品也返回类型,即为全量的类型
|
||||
need_empty_category: true,
|
||||
entity_type: ProductEntityType.Bot,
|
||||
},
|
||||
{ __disableErrorToast: true },
|
||||
);
|
||||
return res.data?.categories || [];
|
||||
},
|
||||
{
|
||||
onSuccess: data => {
|
||||
setHasCategoryList?.(Boolean(data.length));
|
||||
},
|
||||
onError: () => {
|
||||
setHasCategoryList?.(false);
|
||||
},
|
||||
refreshDeps: [record.id],
|
||||
},
|
||||
);
|
||||
const { loading: autoCategoryLoading } = useRequest(
|
||||
async () => {
|
||||
const { description, name, prompt } = botInfo;
|
||||
|
||||
const res = await PlaygroundApi.GenerateStoreCategory(
|
||||
{
|
||||
prompt,
|
||||
bot_name: name,
|
||||
bot_description: description,
|
||||
},
|
||||
{ __disableErrorToast: true },
|
||||
);
|
||||
return res.data?.category_id;
|
||||
},
|
||||
{
|
||||
ready:
|
||||
selectedPlatforms.includes(record.id) &&
|
||||
!record.bind_info?.category_id &&
|
||||
!isEmpty(botInfo.name),
|
||||
onSuccess: data => {
|
||||
handleSelect('category_id', data);
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
const handleSelect = (key: 'open_source' | 'category_id', value) => {
|
||||
setDataSource((list: PublishConnectorInfo[]) => {
|
||||
const target = list.find(l => l.id === record?.id);
|
||||
if (target) {
|
||||
target.bind_info = {
|
||||
...target.bind_info,
|
||||
[key]: value,
|
||||
};
|
||||
}
|
||||
return [...list];
|
||||
});
|
||||
};
|
||||
|
||||
const isCategoryError =
|
||||
selectedPlatforms?.includes(record.id) &&
|
||||
!record.bind_info?.category_id &&
|
||||
!autoCategoryLoading;
|
||||
|
||||
const selectedStore = selectedPlatforms?.includes(record.id);
|
||||
|
||||
const renderLabel = (title, desc, key) => (
|
||||
<span className="flex justify-between w-full">
|
||||
{!canOpenSource && key === BotSubmitStatus.Public ? (
|
||||
<Tooltip
|
||||
content={I18n.t('publisher_market_public_disabled')}
|
||||
position="bottom"
|
||||
>
|
||||
{title}
|
||||
</Tooltip>
|
||||
) : (
|
||||
title
|
||||
)}
|
||||
<Tooltip content={desc}>
|
||||
<UIIconButton icon={<IconInfo className="text-[#1D1C2399]" />} />
|
||||
</Tooltip>
|
||||
</span>
|
||||
);
|
||||
const { publishLoading } = usePublishTableContext();
|
||||
|
||||
const selectSourceConfig = () => {
|
||||
if (!sourceConfig) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<Select
|
||||
className="w-[180px] mr-2"
|
||||
defaultValue={BotSubmitStatus.Private}
|
||||
disabled={!selectedStore || publishLoading}
|
||||
optionList={map(OpenSourceConfig, ({ title, desc }, key) => ({
|
||||
label: (
|
||||
<Space className="w-full">
|
||||
{renderLabel(title(), desc(), key)}
|
||||
</Space>
|
||||
),
|
||||
value: key,
|
||||
title: title(),
|
||||
disabled: !canOpenSource && key === BotSubmitStatus.Public,
|
||||
}))}
|
||||
value={record.bind_info?.open_source}
|
||||
onSelect={value => handleSelect('open_source', value)}
|
||||
insetLabel={I18n.t('mkpl_bots_visibility')}
|
||||
renderSelectedItem={option => (
|
||||
<Typography.Text
|
||||
disabled={!selectedStore}
|
||||
ellipsis={{
|
||||
showTooltip: {
|
||||
opts: {
|
||||
content: option.title,
|
||||
style: { wordBreak: 'break-word' },
|
||||
},
|
||||
},
|
||||
}}
|
||||
>
|
||||
{option.title}
|
||||
</Typography.Text>
|
||||
)}
|
||||
></Select>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<div onClick={e => e.stopPropagation()}>
|
||||
{selectSourceConfig()}
|
||||
<Select
|
||||
style={{ width: 180 }}
|
||||
disabled={!selectedStore || !categoryList?.length || publishLoading}
|
||||
optionList={categoryList?.map(item => ({
|
||||
label: item.name,
|
||||
value: item.id,
|
||||
}))}
|
||||
value={
|
||||
categoryList?.length
|
||||
? record.bind_info?.category_id || undefined
|
||||
: undefined
|
||||
}
|
||||
onSelect={value => handleSelect('category_id', value)}
|
||||
insetLabel={I18n.t('mkpl_bots_category')}
|
||||
placeholder={
|
||||
!autoCategoryLoading ? (
|
||||
categoryList?.length ? (
|
||||
I18n.t('select_category')
|
||||
) : (
|
||||
I18n.t('select_later')
|
||||
)
|
||||
) : (
|
||||
<Spin spinning style={{ verticalAlign: 'middle' }}>
|
||||
{I18n.t('select_category')}
|
||||
</Spin>
|
||||
)
|
||||
}
|
||||
validateStatus={isCategoryError ? 'error' : 'default'}
|
||||
renderSelectedItem={option => (
|
||||
<Typography.Text
|
||||
disabled={!selectedStore || !categoryList?.length}
|
||||
ellipsis={{
|
||||
showTooltip: {
|
||||
opts: {
|
||||
content: option.label,
|
||||
style: { wordBreak: 'break-word' },
|
||||
},
|
||||
},
|
||||
}}
|
||||
>
|
||||
{option.label}
|
||||
</Typography.Text>
|
||||
)}
|
||||
></Select>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* 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 { reporter } from '@coze-arch/logger';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import { type TagColor } from '@coze-arch/bot-semi';
|
||||
import {
|
||||
BindType,
|
||||
ConfigStatus,
|
||||
UserAuthStatus,
|
||||
type PublishConnectorInfo,
|
||||
} from '@coze-arch/bot-api/developer_api';
|
||||
|
||||
interface ConfigStatusUI {
|
||||
text: string;
|
||||
color: TagColor;
|
||||
}
|
||||
|
||||
export const getConfigStatus = (
|
||||
record: PublishConnectorInfo,
|
||||
): ConfigStatusUI => {
|
||||
const { bind_type } = record;
|
||||
|
||||
if (bind_type === BindType.KvBind) {
|
||||
return getKvBindStatus(record);
|
||||
}
|
||||
|
||||
if (bind_type === BindType.AuthAndConfig) {
|
||||
return getAuthAndConfigStatus(record);
|
||||
}
|
||||
|
||||
return getDefaultStatus(record);
|
||||
};
|
||||
|
||||
const getKvBindStatus = (record: PublishConnectorInfo): ConfigStatusUI => {
|
||||
const { config_status } = record;
|
||||
const couldPublish = config_status === ConfigStatus.Configured;
|
||||
const color = couldPublish ? 'green' : 'grey';
|
||||
|
||||
const textMap = {
|
||||
[ConfigStatus.Configured]: I18n.t('bot_publish_columns_status_configured'),
|
||||
[ConfigStatus.NotConfigured]: I18n.t(
|
||||
'bot_publish_columns_status_not_configured',
|
||||
),
|
||||
[ConfigStatus.Configuring]: '',
|
||||
};
|
||||
|
||||
return {
|
||||
text: textMap[config_status],
|
||||
color,
|
||||
};
|
||||
};
|
||||
|
||||
const getAuthAndConfigStatus = (
|
||||
record: PublishConnectorInfo,
|
||||
): ConfigStatusUI => {
|
||||
const { config_status, auth_status } = record;
|
||||
if (auth_status === UserAuthStatus.UnAuthorized) {
|
||||
return {
|
||||
text: I18n.t('bot_publish_columns_status_unauthorized'),
|
||||
color: 'grey',
|
||||
};
|
||||
}
|
||||
switch (config_status) {
|
||||
case ConfigStatus.Configured:
|
||||
return {
|
||||
text: I18n.t('bot_publish_columns_status_configured'),
|
||||
color: 'green',
|
||||
};
|
||||
case ConfigStatus.NeedReconfiguring:
|
||||
return {
|
||||
text: I18n.t('publish_base_config_needReconfigure'),
|
||||
color: 'orange',
|
||||
};
|
||||
case ConfigStatus.NotConfigured:
|
||||
return {
|
||||
text: I18n.t('bot_publish_columns_status_not_configured'),
|
||||
color: 'grey',
|
||||
};
|
||||
default:
|
||||
reporter.errorEvent({
|
||||
eventName: 'fail_to_handle_config_status',
|
||||
error: new Error(`config status: ${config_status}`),
|
||||
});
|
||||
return {
|
||||
text: '',
|
||||
color: 'grey',
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
const getDefaultStatus = (record: PublishConnectorInfo): ConfigStatusUI => {
|
||||
const { config_status } = record;
|
||||
const couldPublish = config_status === ConfigStatus.Configured;
|
||||
const color = couldPublish ? 'green' : 'grey';
|
||||
|
||||
const textMap = {
|
||||
[ConfigStatus.Configured]: I18n.t('bot_publish_columns_status_authorized'),
|
||||
[ConfigStatus.NotConfigured]: I18n.t(
|
||||
'bot_publish_columns_status_unauthorized',
|
||||
),
|
||||
[ConfigStatus.Configuring]: I18n.t('publish_douyin_config_ing'),
|
||||
};
|
||||
|
||||
return {
|
||||
text: textMap[config_status],
|
||||
color,
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { useLocation } from 'react-router-dom';
|
||||
import { useEffect } from 'react';
|
||||
|
||||
import { AuthStatus } from '@coze-arch/idl/developer_api';
|
||||
import { useResetLocationState } from '@coze-arch/bot-hooks';
|
||||
|
||||
// 三方授权成功,调用成功回调
|
||||
export const useAuthSuccess = (bindSuccess: (id: string) => void) => {
|
||||
const { state } = useLocation();
|
||||
const { oauth2, authStatus } = (state ?? history.state ?? {}) as Record<
|
||||
string,
|
||||
unknown
|
||||
>;
|
||||
const { platform = '' } = (oauth2 ?? {}) as Record<string, string>;
|
||||
const resetLocationState = useResetLocationState();
|
||||
|
||||
useEffect(() => {
|
||||
if (authStatus === AuthStatus.Authorized) {
|
||||
resetLocationState();
|
||||
|
||||
bindSuccess(platform);
|
||||
}
|
||||
}, [platform, authStatus]);
|
||||
};
|
||||
@@ -0,0 +1,377 @@
|
||||
/*
|
||||
* 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, useMemo, useState } from 'react';
|
||||
|
||||
import { partition } from 'lodash-es';
|
||||
import classNames from 'classnames';
|
||||
import { PublishPlatformDescription } from '@coze-agent-ide/space-bot/component';
|
||||
import {
|
||||
type PublisherBotInfo,
|
||||
type MouseInValue,
|
||||
type PublishTableProps,
|
||||
} from '@coze-agent-ide/space-bot';
|
||||
import { MonetizePublishInfo } from '@coze-studio/components/monetize';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import { IconCozArrowRight, IconCozDiamondFill } from '@coze-arch/coze-design/icons';
|
||||
import { Tooltip } from '@coze-arch/coze-design';
|
||||
import { type ColumnProps } from '@coze-arch/bot-semi/Table';
|
||||
import { Avatar, Space, Typography, UITable } from '@coze-arch/bot-semi';
|
||||
import {
|
||||
AllowPublishStatus,
|
||||
BindType,
|
||||
BotConnectorStatus,
|
||||
ConfigStatus,
|
||||
type ConnectorBrandInfo,
|
||||
type PublishConnectorInfo,
|
||||
} from '@coze-arch/bot-api/developer_api';
|
||||
import { type BotMonetizationConfigData } from '@coze-arch/bot-api/benefit';
|
||||
import {
|
||||
useBenefitAvailable,
|
||||
PremiumPaywallScene,
|
||||
usePremiumPaywallModal,
|
||||
} from '@coze-studio/premium-components-adapter';
|
||||
|
||||
import styles from '../index.module.less';
|
||||
import { usePublishTableContext } from '../context';
|
||||
import { PluginPricingInfo } from './plugin-limit-tooltip';
|
||||
import { ConfigStatusColumn } from './config-status';
|
||||
|
||||
const convertFlatListToTreeList = (
|
||||
list: PublishConnectorInfo[],
|
||||
brandMap: Record<string, ConnectorBrandInfo> = {},
|
||||
) => {
|
||||
const result = {};
|
||||
const finalResult = [];
|
||||
list.forEach(item => {
|
||||
const brandId = item?.brand_id;
|
||||
if (brandId) {
|
||||
if (!result[brandId]) {
|
||||
result[brandId] = {
|
||||
...(brandMap[brandId] || {}),
|
||||
children: [],
|
||||
};
|
||||
// @ts-expect-error -- skip
|
||||
finalResult.push(result[brandId]);
|
||||
}
|
||||
result[brandId].children.push(item);
|
||||
} else {
|
||||
// @ts-expect-error -- skip
|
||||
finalResult.push(item);
|
||||
}
|
||||
});
|
||||
return finalResult;
|
||||
};
|
||||
|
||||
const getCheckBoxDisabledTips = (record: PublishConnectorInfo) => {
|
||||
const configStatusArray = [
|
||||
ConfigStatus.NotConfigured,
|
||||
ConfigStatus.Configuring,
|
||||
];
|
||||
if (
|
||||
record.allow_punish === AllowPublishStatus.Forbid &&
|
||||
record.not_allow_reason
|
||||
) {
|
||||
return record.not_allow_reason;
|
||||
}
|
||||
if (configStatusArray.some(status => record.config_status === status)) {
|
||||
return I18n.t('bot_publish_disable_check_tip');
|
||||
}
|
||||
if (record.connector_status === BotConnectorStatus.InReview) {
|
||||
return I18n.t('bot_publish_in_review_disable_check_tip');
|
||||
}
|
||||
if (record.config_status === ConfigStatus.NeedReconfiguring) {
|
||||
return I18n.t('publish_base_config_needReconfigure');
|
||||
}
|
||||
};
|
||||
|
||||
const getCheckboxProps = (record: PublishConnectorInfo, disabled: boolean) => {
|
||||
const disableTip = getCheckBoxDisabledTips(record);
|
||||
return {
|
||||
disabled: !!disableTip || disabled,
|
||||
id: record.id,
|
||||
// Offline状态没有tooltip
|
||||
children: disableTip ? (
|
||||
<Tooltip content={disableTip}>
|
||||
<span className={styles['disable-tooltip']} />
|
||||
</Tooltip>
|
||||
) : null,
|
||||
};
|
||||
};
|
||||
|
||||
const doIfDisabled = (source: PublishConnectorInfo[], disabled: boolean) =>
|
||||
source?.every(
|
||||
item =>
|
||||
item.config_status !== ConfigStatus.Configured ||
|
||||
item.allow_punish !== AllowPublishStatus.Allowed ||
|
||||
item.connector_status === BotConnectorStatus.InReview,
|
||||
) || disabled;
|
||||
|
||||
export const TableCollection = (props: PublishTableProps) => {
|
||||
const {
|
||||
dataSource,
|
||||
connectorBrandInfoMap = {},
|
||||
selectedPlatforms,
|
||||
setSelectedPlatforms,
|
||||
} = props;
|
||||
const [mouseInfo, setMouseInfo] = useState<MouseInValue>({});
|
||||
const onMouseEnter = (record: PublishConnectorInfo) => {
|
||||
setMouseInfo({ [record.id]: true });
|
||||
};
|
||||
const onMouseLeave = (record: PublishConnectorInfo) => {
|
||||
setMouseInfo({ [record.id]: false });
|
||||
};
|
||||
const [dataSourceForOpen, dataSourceForChannel] = partition(
|
||||
dataSource ?? [],
|
||||
d =>
|
||||
d?.bind_type === BindType.ApiBind || d?.bind_type === BindType.WebSDKBind,
|
||||
);
|
||||
|
||||
const { publishLoading } = usePublishTableContext();
|
||||
|
||||
const dataTreeForOpen = useMemo(
|
||||
() => convertFlatListToTreeList(dataSourceForOpen, connectorBrandInfoMap),
|
||||
[dataSourceForOpen, connectorBrandInfoMap],
|
||||
);
|
||||
const dataTreeForChannel = useMemo(
|
||||
() =>
|
||||
convertFlatListToTreeList(dataSourceForChannel, connectorBrandInfoMap),
|
||||
[dataSourceForChannel, connectorBrandInfoMap],
|
||||
);
|
||||
|
||||
// 无全选按钮因此所有表格使用相同check配置
|
||||
const baseConfigForChecker = {
|
||||
hidden: true,
|
||||
fixed: 'left' as const,
|
||||
selectedRowKeys: selectedPlatforms,
|
||||
onChange: (selectedRowKeys: (string | number)[] | undefined) => {
|
||||
setSelectedPlatforms(selectedRowKeys as string[]);
|
||||
},
|
||||
getCheckboxProps: (record: PublishConnectorInfo) =>
|
||||
getCheckboxProps(record, publishLoading),
|
||||
};
|
||||
|
||||
const getColumns = (
|
||||
type: 'connector' | 'api',
|
||||
): ColumnProps<PublishConnectorInfo>[] => [
|
||||
{
|
||||
title: <TableTitle type={type} />,
|
||||
width: 220,
|
||||
useFullRender: true,
|
||||
render: (...params) => {
|
||||
// @ts-expect-error -- skip
|
||||
const [record, , , { expandIcon, selection }] = params;
|
||||
return (
|
||||
<PlatformInfoColumn
|
||||
platform={record}
|
||||
rowIcon={record.children ? expandIcon : selection}
|
||||
/>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: (
|
||||
<TableTittleExtra
|
||||
botInfo={props.botInfo}
|
||||
type={type}
|
||||
monetizeConfig={props.monetizeConfig}
|
||||
platforms={dataSource}
|
||||
/>
|
||||
),
|
||||
render: (
|
||||
record: PublishConnectorInfo & { children?: PublishConnectorInfo[] },
|
||||
) =>
|
||||
record.children ? null : (
|
||||
<ConfigStatusColumn
|
||||
isMouseIn={Boolean(mouseInfo[record.id])}
|
||||
record={record}
|
||||
{...props}
|
||||
/>
|
||||
),
|
||||
},
|
||||
];
|
||||
const handleOnRow = (record: PublishConnectorInfo) => ({
|
||||
onClick: () => {
|
||||
if (!doIfDisabled([record], publishLoading)) {
|
||||
setSelectedPlatforms(ids =>
|
||||
ids?.includes(record.id)
|
||||
? ids.filter(i => i !== record.id)
|
||||
: [record.id, ...ids],
|
||||
);
|
||||
}
|
||||
}, // 点击行选中
|
||||
onMouseEnter: () => onMouseEnter(record), // 鼠标移入行
|
||||
onMouseLeave: () => onMouseLeave(record), // 鼠标移出行
|
||||
});
|
||||
const tableCommonProps = {
|
||||
className: classNames(styles['publish-table']),
|
||||
rowKey: 'id',
|
||||
onRow: handleOnRow,
|
||||
defaultExpandAllRows: true,
|
||||
expandIcon: <IconCozArrowRight style={{ fontSize: 16 }} />,
|
||||
keepDOM: true,
|
||||
expandRowByClick: true,
|
||||
};
|
||||
return (
|
||||
<>
|
||||
{!!dataSourceForChannel.length && (
|
||||
<UITable
|
||||
tableProps={{
|
||||
columns: getColumns('connector'),
|
||||
dataSource: dataTreeForChannel,
|
||||
rowSelection: baseConfigForChecker,
|
||||
...tableCommonProps,
|
||||
}}
|
||||
wrapperClassName={classNames(styles['publish-table-wrapper'])}
|
||||
/>
|
||||
)}
|
||||
{!!dataSourceForOpen.length && (
|
||||
<UITable
|
||||
tableProps={{
|
||||
columns: getColumns('api'),
|
||||
dataSource: dataTreeForOpen,
|
||||
rowSelection: baseConfigForChecker,
|
||||
...tableCommonProps,
|
||||
}}
|
||||
wrapperClassName={styles['publish-table-wrapper']}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
function TableTitle({ type }: { type: 'connector' | 'api' }) {
|
||||
const apiTitle = IS_OVERSEA
|
||||
? I18n.t('api_sdk_published', {
|
||||
coze_token: (
|
||||
<Typography.Text
|
||||
link
|
||||
size="small"
|
||||
onClick={() => window.open('/docs/guides/token')}
|
||||
>
|
||||
{I18n.t('Coze_token_title')}
|
||||
</Typography.Text>
|
||||
),
|
||||
})
|
||||
: I18n.t('api');
|
||||
return (
|
||||
<div className="pl-3">
|
||||
{type === 'connector' ? I18n.t('bot_publish_columns_platform') : apiTitle}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function TableTittleExtra({
|
||||
monetizeConfig,
|
||||
platforms,
|
||||
type,
|
||||
botInfo,
|
||||
}: {
|
||||
type: 'connector' | 'api';
|
||||
monetizeConfig?: BotMonetizationConfigData;
|
||||
platforms: PublishConnectorInfo[];
|
||||
botInfo: PublisherBotInfo;
|
||||
}) {
|
||||
// 付费墙
|
||||
const isAvailable = useBenefitAvailable({
|
||||
scene: PremiumPaywallScene.API,
|
||||
});
|
||||
const { node: premiumPaywallModal, open: openPremiumPaywallModal } =
|
||||
usePremiumPaywallModal({ scene: PremiumPaywallScene.API });
|
||||
|
||||
if (type === 'api' && !isAvailable) {
|
||||
return (
|
||||
<>
|
||||
<Space className="text-[12px] w-full justify-end pr-[28px]" spacing={2}>
|
||||
<IconCozDiamondFill className="coz-fg-hglt" />
|
||||
累计100条,
|
||||
<div
|
||||
className="coz-fg-hglt cursor-pointer"
|
||||
onClick={openPremiumPaywallModal}
|
||||
>
|
||||
升级套餐
|
||||
</div>
|
||||
豁免额度限制
|
||||
</Space>
|
||||
{premiumPaywallModal}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
if (IS_OVERSEA && type === 'api') {
|
||||
return (
|
||||
<PluginPricingInfo pluginPricingRules={botInfo.pluginPricingRules} />
|
||||
);
|
||||
}
|
||||
|
||||
if (!IS_OVERSEA || !monetizeConfig || type !== 'connector') {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<MonetizePublishInfo
|
||||
className="pr-[24px]"
|
||||
monetizeConfig={monetizeConfig}
|
||||
supportPlatforms={platforms.filter(p => p.support_monetization)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
function PlatformInfoColumn({
|
||||
platform,
|
||||
rowIcon,
|
||||
}: {
|
||||
platform: PublishConnectorInfo;
|
||||
rowIcon: ReactNode;
|
||||
}) {
|
||||
return (
|
||||
<Space style={{ width: '100%' }}>
|
||||
<div
|
||||
className={classNames(
|
||||
styles['table-row-icon-wrapper'],
|
||||
'pr-1',
|
||||
platform.brand_id ? 'pl-1' : 'pl-3',
|
||||
{ 'ml-10': !!platform.brand_id },
|
||||
)}
|
||||
>
|
||||
{rowIcon}
|
||||
</div>
|
||||
<Avatar
|
||||
size="small"
|
||||
shape="square"
|
||||
src={platform.icon}
|
||||
className={styles['platform-avater']}
|
||||
></Avatar>
|
||||
<Typography.Text
|
||||
className={styles['platform-name']}
|
||||
ellipsis={{
|
||||
showTooltip: {
|
||||
opts: {
|
||||
content: platform?.name,
|
||||
style: { wordWrap: 'break-word' },
|
||||
},
|
||||
},
|
||||
}}
|
||||
>
|
||||
{platform?.name}
|
||||
</Typography.Text>
|
||||
|
||||
{platform?.desc ? (
|
||||
<PublishPlatformDescription desc={platform.desc} />
|
||||
) : null}
|
||||
</Space>
|
||||
);
|
||||
}
|
||||
@@ -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 { type FC } from 'react';
|
||||
|
||||
import {
|
||||
transPricingRules,
|
||||
usePluginLimitModal,
|
||||
} from '@coze-studio/components';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import { Typography } from '@coze-arch/coze-design';
|
||||
import { type PluginPricingRule } from '@coze-arch/bot-api/plugin_develop';
|
||||
|
||||
// 发布页提示
|
||||
export const PluginPricingInfo: FC<{
|
||||
pluginPricingRules?: Array<PluginPricingRule>;
|
||||
}> = ({ pluginPricingRules }) => {
|
||||
const pricingRules = transPricingRules(pluginPricingRules);
|
||||
|
||||
const { node, open } = usePluginLimitModal({
|
||||
// @ts-expect-error - skip
|
||||
dataSource: pricingRules,
|
||||
content: (
|
||||
<div>
|
||||
{I18n.t('professional_plan_n_paid_plugins_included_in_bot', {
|
||||
count: pricingRules.length,
|
||||
})}
|
||||
</div>
|
||||
),
|
||||
});
|
||||
|
||||
if (pricingRules.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{node}
|
||||
<div className="pr-[24px] flex justify-end items-center gap-[6px]">
|
||||
{I18n.t('plugins_with_limited_calls_added_tip')}
|
||||
<Typography.Text className="font-bold" link size="small" onClick={open}>
|
||||
{I18n.t('plugin_usage_limits_modal_view_details')}
|
||||
</Typography.Text>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
17
frontend/packages/agent-ide/agent-publish/src/index.ts
Normal file
17
frontend/packages/agent-ide/agent-publish/src/index.ts
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.
|
||||
*/
|
||||
|
||||
export { AgentPublishPage } from './components/bot-publish';
|
||||
17
frontend/packages/agent-ide/agent-publish/src/typings.d.ts
vendored
Normal file
17
frontend/packages/agent-ide/agent-publish/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' />
|
||||
100
frontend/packages/agent-ide/agent-publish/tsconfig.build.json
Normal file
100
frontend/packages/agent-ide/agent-publish/tsconfig.build.json
Normal file
@@ -0,0 +1,100 @@
|
||||
{
|
||||
"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"],
|
||||
"target": "ES2020",
|
||||
"tsBuildInfoFile": "dist/tsconfig.build.tsbuildinfo"
|
||||
},
|
||||
"include": ["src"],
|
||||
"exclude": ["node_modules", "dist"],
|
||||
"references": [
|
||||
{
|
||||
"path": "../../arch/bot-api/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../../arch/bot-error/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../../arch/bot-flags/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../../arch/bot-hooks/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/i18n/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../../arch/idl/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../../arch/logger/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../../arch/report-events/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../../arch/report-tti/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../commons/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../../components/bot-icons/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../../components/bot-semi/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../../../config/eslint-config/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../../../config/stylelint-config/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../../../config/ts-config/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../../../config/vitest-config/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../../foundation/layout/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../space-bot/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../../studio/components/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../../studio/open-platform/open-auth/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../../studio/premium/premium-components-adapter/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../../studio/publish-manage-hooks/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../../studio/stores/bot-detail/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../../studio/user-store/tsconfig.build.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
15
frontend/packages/agent-ide/agent-publish/tsconfig.json
Normal file
15
frontend/packages/agent-ide/agent-publish/tsconfig.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/tsconfig",
|
||||
"exclude": ["**/*"],
|
||||
"compilerOptions": {
|
||||
"composite": true
|
||||
},
|
||||
"references": [
|
||||
{
|
||||
"path": "./tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "./tsconfig.misc.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
20
frontend/packages/agent-ide/agent-publish/tsconfig.misc.json
Normal file
20
frontend/packages/agent-ide/agent-publish/tsconfig.misc.json
Normal file
@@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
22
frontend/packages/agent-ide/agent-publish/vitest.config.ts
Normal file
22
frontend/packages/agent-ide/agent-publish/vitest.config.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
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: [],
|
||||
});
|
||||
67
frontend/packages/agent-ide/bot-audit-adapter/README.md
Normal file
67
frontend/packages/agent-ide/bot-audit-adapter/README.md
Normal file
@@ -0,0 +1,67 @@
|
||||
# @coze-studio/bot-audit-adapter
|
||||
|
||||
bot audit pkg
|
||||
|
||||
## Overview
|
||||
|
||||
This package is part of the Coze Studio monorepo and provides ide features functionality. It includes hook.
|
||||
|
||||
## Getting Started
|
||||
|
||||
### Installation
|
||||
|
||||
Add this package to your `package.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"dependencies": {
|
||||
"@coze-studio/bot-audit-adapter": "workspace:*"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Then run:
|
||||
|
||||
```bash
|
||||
rush update
|
||||
```
|
||||
|
||||
### Usage
|
||||
|
||||
```typescript
|
||||
import { /* exported functions/components */ } from '@coze-studio/bot-audit-adapter';
|
||||
|
||||
// Example usage
|
||||
// TODO: Add specific usage examples
|
||||
```
|
||||
|
||||
## Features
|
||||
|
||||
- Hook
|
||||
|
||||
## API Reference
|
||||
|
||||
### Exports
|
||||
|
||||
- `botInfoAudit, useBotInfoAuditor`
|
||||
- `AuditErrorMessage`
|
||||
|
||||
|
||||
For detailed API documentation, please refer to the TypeScript definitions.
|
||||
|
||||
## Development
|
||||
|
||||
This package is built with:
|
||||
|
||||
- TypeScript
|
||||
- Modern JavaScript
|
||||
- Vitest for testing
|
||||
- ESLint for code quality
|
||||
|
||||
## Contributing
|
||||
|
||||
This package is part of the Coze Studio monorepo. Please follow the monorepo contribution guidelines.
|
||||
|
||||
## License
|
||||
|
||||
Apache-2.0
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
describe('Hello World', () => {
|
||||
it('test', () => {
|
||||
expect(1).toBe(1);
|
||||
});
|
||||
});
|
||||
@@ -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: 'node',
|
||||
rules: {},
|
||||
});
|
||||
41
frontend/packages/agent-ide/bot-audit-adapter/package.json
Normal file
41
frontend/packages/agent-ide/bot-audit-adapter/package.json
Normal file
@@ -0,0 +1,41 @@
|
||||
{
|
||||
"name": "@coze-studio/bot-audit-adapter",
|
||||
"version": "0.0.1",
|
||||
"description": "bot audit pkg",
|
||||
"license": "Apache-2.0",
|
||||
"author": "lengfangbing@bytedance.com",
|
||||
"maintainers": [],
|
||||
"main": "src/index.ts",
|
||||
"scripts": {
|
||||
"build": "exit 0",
|
||||
"lint": "eslint ./ --cache",
|
||||
"test": "vitest --run --passWithNoTests",
|
||||
"test:cov": "npm run test -- --coverage"
|
||||
},
|
||||
"dependencies": {
|
||||
"@coze-studio/bot-audit-base": "workspace:*",
|
||||
"@coze-studio/bot-detail-store": "workspace:*",
|
||||
"@coze-arch/bot-api": "workspace:*",
|
||||
"@coze-arch/bot-flags": "workspace:*",
|
||||
"@coze-arch/bot-space-api": "workspace:*",
|
||||
"@coze-arch/i18n": "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:*",
|
||||
"@types/node": "^18",
|
||||
"@types/react": "18.2.37",
|
||||
"@types/react-dom": "18.2.15",
|
||||
"@vitest/coverage-v8": "~3.0.5",
|
||||
"sucrase": "^3.32.0",
|
||||
"vitest": "~3.0.5"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=18.2.0",
|
||||
"react-dom": ">=18.2.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { useState } from 'react';
|
||||
|
||||
import {
|
||||
type BotAuditInfo,
|
||||
type BotInfoAuditData,
|
||||
} from '@coze-arch/bot-api/playground_api';
|
||||
import {
|
||||
type UseBotInfoAuditorHook,
|
||||
type BotInfoAuditFunc,
|
||||
} from '@coze-studio/bot-audit-base';
|
||||
|
||||
const defaultPassState = true;
|
||||
|
||||
export const botInfoAudit: BotInfoAuditFunc = (
|
||||
_: BotAuditInfo,
|
||||
): Promise<BotInfoAuditData> => Promise.resolve({});
|
||||
|
||||
export const useBotInfoAuditor: UseBotInfoAuditorHook = () => {
|
||||
const [pass, setPass] = useState(defaultPassState);
|
||||
|
||||
return {
|
||||
check: (_: BotAuditInfo) => Promise.resolve({}),
|
||||
pass,
|
||||
setPass,
|
||||
reset: () => {
|
||||
setPass(defaultPassState);
|
||||
},
|
||||
};
|
||||
};
|
||||
19
frontend/packages/agent-ide/bot-audit-adapter/src/index.ts
Normal file
19
frontend/packages/agent-ide/bot-audit-adapter/src/index.ts
Normal file
@@ -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 { botInfoAudit, useBotInfoAuditor } from './hooks/use-bot-audit';
|
||||
|
||||
export { AuditErrorMessage } from '@coze-studio/bot-audit-base';
|
||||
21
frontend/packages/agent-ide/bot-audit-adapter/src/typings.d.ts
vendored
Normal file
21
frontend/packages/agent-ide/bot-audit-adapter/src/typings.d.ts
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/// <reference types='@coze-arch/bot-typings' />
|
||||
declare module '*.less' {
|
||||
const resource: { [key: string]: string };
|
||||
export = resource;
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/tsconfig",
|
||||
"extends": "@coze-arch/ts-config/tsconfig.node.json",
|
||||
"compilerOptions": {
|
||||
"types": [],
|
||||
"jsx": "react",
|
||||
"rootDir": "./src",
|
||||
"outDir": "./dist",
|
||||
"tsBuildInfoFile": "./dist/tsconfig.build.tsbuildinfo"
|
||||
},
|
||||
"include": ["src"],
|
||||
"references": [
|
||||
{
|
||||
"path": "../../arch/bot-api/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../../arch/bot-flags/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../../arch/bot-space-api/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../../arch/bot-typings/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../../arch/i18n/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../bot-audit-base/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": "../../studio/stores/bot-detail/tsconfig.build.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
15
frontend/packages/agent-ide/bot-audit-adapter/tsconfig.json
Normal file
15
frontend/packages/agent-ide/bot-audit-adapter/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,17 @@
|
||||
{
|
||||
"extends": "@coze-arch/ts-config/tsconfig.node.json",
|
||||
"$schema": "https://json.schemastore.org/tsconfig",
|
||||
"include": ["__tests__", "vitest.config.ts"],
|
||||
"exclude": ["./dist"],
|
||||
"references": [
|
||||
{
|
||||
"path": "./tsconfig.build.json"
|
||||
}
|
||||
],
|
||||
"compilerOptions": {
|
||||
"rootDir": "./",
|
||||
"outDir": "./dist",
|
||||
"types": ["vitest/globals"],
|
||||
"jsx": "react"
|
||||
}
|
||||
}
|
||||
@@ -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 { defineConfig } from '@coze-arch/vitest-config';
|
||||
|
||||
export default defineConfig({
|
||||
dirname: __dirname,
|
||||
preset: 'node',
|
||||
test: {
|
||||
coverage: {
|
||||
all: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,5 @@
|
||||
const { defineConfig } = require('@coze-arch/stylelint-config');
|
||||
|
||||
module.exports = defineConfig({
|
||||
extends: [],
|
||||
});
|
||||
132
frontend/packages/agent-ide/bot-audit-base/README.md
Normal file
132
frontend/packages/agent-ide/bot-audit-base/README.md
Normal file
@@ -0,0 +1,132 @@
|
||||
# @coze-studio/bot-audit-base
|
||||
|
||||
> Audit base package for bot content validation and error handling
|
||||
|
||||
## Project Overview
|
||||
|
||||
This package provides foundational components and interfaces for bot content auditing within the Coze Studio platform. It includes UI components for displaying audit error messages and TypeScript interfaces for audit functionality integration.
|
||||
|
||||
## Features
|
||||
|
||||
- **AuditErrorMessage Component**: Pre-styled React component for displaying audit failure messages with customizable documentation links
|
||||
- **Type Definitions**: Comprehensive TypeScript interfaces for bot audit hooks and functions
|
||||
- **Internationalization Support**: Built-in i18n support for error messages
|
||||
- **Storybook Integration**: Component documentation and testing environment
|
||||
|
||||
## Get Started
|
||||
|
||||
### Installation
|
||||
|
||||
Add this package to your `package.json` dependencies and set it to `workspace:*` version:
|
||||
|
||||
```json
|
||||
{
|
||||
"dependencies": {
|
||||
"@coze-studio/bot-audit-base": "workspace:*"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Then run:
|
||||
```bash
|
||||
rush update
|
||||
```
|
||||
|
||||
### Basic Usage
|
||||
|
||||
#### Using the AuditErrorMessage Component
|
||||
|
||||
```tsx
|
||||
import { AuditErrorMessage } from '@coze-studio/bot-audit-base';
|
||||
|
||||
function MyComponent() {
|
||||
return (
|
||||
<AuditErrorMessage
|
||||
link="/docs/custom-guidelines"
|
||||
/>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
#### Implementing Audit Functionality
|
||||
|
||||
```tsx
|
||||
import type { UseBotInfoAuditorHook, BotInfoAuditFunc } from '@coze-studio/bot-audit-base';
|
||||
|
||||
// Example hook implementation
|
||||
const useBotAuditor: UseBotInfoAuditorHook = () => {
|
||||
const [pass, setPass] = useState(false);
|
||||
|
||||
const check: BotInfoAuditFunc = async (params) => {
|
||||
// Your audit logic here
|
||||
const result = await performAudit(params);
|
||||
setPass(result.success);
|
||||
return result;
|
||||
};
|
||||
|
||||
const reset = () => setPass(false);
|
||||
|
||||
return { check, pass, setPass, reset };
|
||||
};
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### Components
|
||||
|
||||
#### `AuditErrorMessage`
|
||||
|
||||
Displays standardized audit error messages with documentation links.
|
||||
|
||||
**Props:**
|
||||
- `link` (optional): Custom documentation link URL. Defaults to `/docs/guides/content_principles`
|
||||
|
||||
### Types
|
||||
|
||||
#### `UseBotInfoAuditorHook`
|
||||
|
||||
Hook interface for bot audit functionality.
|
||||
|
||||
**Returns:**
|
||||
- `check`: Function to perform audit checks
|
||||
- `pass`: Boolean indicating audit status
|
||||
- `setPass`: State setter for audit status
|
||||
- `reset`: Function to reset audit state
|
||||
|
||||
#### `BotInfoAuditFunc`
|
||||
|
||||
Function type for audit operations.
|
||||
|
||||
**Parameters:**
|
||||
- `params`: `BotAuditInfo` - Audit parameters
|
||||
**Returns:** `Promise<BotInfoAuditData>` - Audit result data
|
||||
|
||||
## Development
|
||||
|
||||
### Available Scripts
|
||||
|
||||
- `npm run dev` - Start Storybook development server
|
||||
- `npm run build` - Build the package
|
||||
- `npm run lint` - Run ESLint
|
||||
- `npm run test` - Run tests with Vitest
|
||||
|
||||
### Project Structure
|
||||
|
||||
```
|
||||
src/
|
||||
├── components/
|
||||
│ └── audit-error-message/ # AuditErrorMessage component
|
||||
├── interfaces/ # TypeScript type definitions
|
||||
└── index.ts # Main export file
|
||||
```
|
||||
|
||||
## Dependencies
|
||||
|
||||
This package depends on:
|
||||
- `@coze-arch/bot-api` - Bot API types and interfaces
|
||||
- `@coze-arch/i18n` - Internationalization utilities
|
||||
- `classnames` - CSS class utility
|
||||
|
||||
## License
|
||||
|
||||
Apache-2.0
|
||||
@@ -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: {},
|
||||
});
|
||||
43
frontend/packages/agent-ide/bot-audit-base/package.json
Normal file
43
frontend/packages/agent-ide/bot-audit-base/package.json
Normal file
@@ -0,0 +1,43 @@
|
||||
{
|
||||
"name": "@coze-studio/bot-audit-base",
|
||||
"version": "0.0.1",
|
||||
"description": "audit base package",
|
||||
"license": "Apache-2.0",
|
||||
"author": "sunzhiyuan.evan@bytedance.com",
|
||||
"maintainers": [],
|
||||
"main": "src/index.ts",
|
||||
"scripts": {
|
||||
"build": "exit 0",
|
||||
"lint": "eslint ./ --cache",
|
||||
"test": "vitest --run --passWithNoTests",
|
||||
"test:cov": "npm run test -- --coverage"
|
||||
},
|
||||
"dependencies": {
|
||||
"@coze-arch/bot-api": "workspace:*",
|
||||
"@coze-arch/i18n": "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/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,9 @@
|
||||
.error-message {
|
||||
@apply text-left;
|
||||
|
||||
color: rgb(255, 68, 30);
|
||||
|
||||
.link {
|
||||
color: #4d53e8;
|
||||
}
|
||||
}
|
||||
@@ -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 React from 'react';
|
||||
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
|
||||
import styles from './index.module.less';
|
||||
|
||||
export function AuditErrorMessage({
|
||||
link = '/docs/guides/content_principles',
|
||||
}: {
|
||||
link?: string;
|
||||
}) {
|
||||
return (
|
||||
<div className={styles['error-message']}>
|
||||
{I18n.t('audit_unsuccess_general_type', {
|
||||
link: (
|
||||
<a
|
||||
rel="noreferrer noopener"
|
||||
href={link}
|
||||
target="_blank"
|
||||
className={styles.link}
|
||||
>
|
||||
{I18n.t('audit_unsuccess_general_type_url')}
|
||||
</a>
|
||||
),
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
18
frontend/packages/agent-ide/bot-audit-base/src/index.ts
Normal file
18
frontend/packages/agent-ide/bot-audit-base/src/index.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export { AuditErrorMessage } from './components/audit-error-message';
|
||||
export { UseBotInfoAuditorHook, BotInfoAuditFunc } from './interfaces';
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import type React from 'react';
|
||||
|
||||
import {
|
||||
type BotAuditInfo,
|
||||
type BotInfoAuditData,
|
||||
} from '@coze-arch/bot-api/playground_api';
|
||||
|
||||
export declare type UseBotInfoAuditorHook = () => {
|
||||
check: (params: BotAuditInfo) => Promise<BotInfoAuditData>;
|
||||
pass: boolean;
|
||||
setPass: React.Dispatch<React.SetStateAction<boolean>>;
|
||||
reset: () => void;
|
||||
};
|
||||
|
||||
export declare type BotInfoAuditFunc = (
|
||||
params: BotAuditInfo,
|
||||
) => Promise<BotInfoAuditData>;
|
||||
17
frontend/packages/agent-ide/bot-audit-base/src/typings.d.ts
vendored
Normal file
17
frontend/packages/agent-ide/bot-audit-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' />
|
||||
@@ -0,0 +1,37 @@
|
||||
{
|
||||
"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"],
|
||||
"target": "ES2020",
|
||||
"tsBuildInfoFile": "dist/tsconfig.build.tsbuildinfo"
|
||||
},
|
||||
"include": ["src"],
|
||||
"exclude": ["node_modules", "dist"],
|
||||
"references": [
|
||||
{
|
||||
"path": "../../arch/bot-api/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../../arch/bot-typings/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../../arch/i18n/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"
|
||||
}
|
||||
]
|
||||
}
|
||||
15
frontend/packages/agent-ide/bot-audit-base/tsconfig.json
Normal file
15
frontend/packages/agent-ide/bot-audit-base/tsconfig.json
Normal file
@@ -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,18 @@
|
||||
{
|
||||
"extends": "@coze-arch/ts-config/tsconfig.web.json",
|
||||
"$schema": "https://json.schemastore.org/tsconfig",
|
||||
"compilerOptions": {
|
||||
"rootDir": "./",
|
||||
"outDir": "./dist",
|
||||
"jsx": "react-jsx",
|
||||
"lib": ["DOM", "ESNext"],
|
||||
"target": "ES2020"
|
||||
},
|
||||
"include": ["__tests__", "vitest.config.ts", "stories"],
|
||||
"exclude": ["./dist"],
|
||||
"references": [
|
||||
{
|
||||
"path": "./tsconfig.build.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
22
frontend/packages/agent-ide/bot-audit-base/vitest.config.ts
Normal file
22
frontend/packages/agent-ide/bot-audit-base/vitest.config.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
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-agent-ide/bot-config-area-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,51 @@
|
||||
{
|
||||
"name": "@coze-agent-ide/bot-config-area-adapter",
|
||||
"version": "0.0.1",
|
||||
"description": "@coze-agent-ide/bot-config-area-adapter",
|
||||
"license": "Apache-2.0",
|
||||
"author": "haozhenfei@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-config-area": "workspace:*",
|
||||
"@coze-agent-ide/model-manager": "workspace:*",
|
||||
"@coze-agent-ide/space-bot": "workspace:*",
|
||||
"@coze-agent-ide/tool": "workspace:*",
|
||||
"@coze-arch/bot-api": "workspace:*",
|
||||
"@coze-arch/bot-semi": "workspace:*",
|
||||
"@coze-arch/coze-design": "0.0.6-alpha.346d77",
|
||||
"@coze-arch/i18n": "workspace:*",
|
||||
"@coze-studio/bot-detail-store": "workspace:*",
|
||||
"@coze-studio/components": "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/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,79 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { type FC } from 'react';
|
||||
|
||||
import { ToolMenu } from '@coze-agent-ide/tool';
|
||||
import { useRiskWarningStore } from '@coze-agent-ide/space-bot/store';
|
||||
import { CollapsibleIconButtonGroup } from '@coze-studio/components/collapsible-icon-button';
|
||||
import { useBotInfoStore } from '@coze-studio/bot-detail-store/bot-info';
|
||||
import { useBotDetailIsReadonly } from '@coze-studio/bot-detail-store';
|
||||
import { BotPageFromEnum } from '@coze-arch/bot-typings/common';
|
||||
import { BotMode, RiskAlertType } from '@coze-arch/bot-api/playground_api';
|
||||
import { PlaygroundApi } from '@coze-arch/bot-api';
|
||||
import { MonetizeConfigButton } from '@coze-agent-ide/bot-config-area';
|
||||
|
||||
import { ModelConfigView } from './model-config-view';
|
||||
|
||||
export interface BotConfigAreaProps {
|
||||
pageFrom?: BotPageFromEnum;
|
||||
editable?: boolean;
|
||||
modelListExtraHeaderSlot?: React.ReactNode;
|
||||
}
|
||||
|
||||
export const BotConfigArea: FC<BotConfigAreaProps> = ({
|
||||
pageFrom,
|
||||
editable,
|
||||
modelListExtraHeaderSlot,
|
||||
}) => {
|
||||
const mode = useBotInfoStore(state => state.mode);
|
||||
const isReadonly = useBotDetailIsReadonly();
|
||||
|
||||
const toolHiddenModeNewbieGuideIsRead = useRiskWarningStore(
|
||||
state => state.toolHiddenModeNewbieGuideIsRead,
|
||||
);
|
||||
|
||||
const onNewbieGuidePopoverClose = () => {
|
||||
useRiskWarningStore.getState().setToolHiddenModeNewbieGuideIsRead(true);
|
||||
PlaygroundApi.UpdateUserConfig({
|
||||
risk_alert_type: RiskAlertType.NewBotIDEGuide,
|
||||
});
|
||||
};
|
||||
|
||||
const isSingleLLM = mode === BotMode.SingleMode;
|
||||
const isSingleWorkflow = mode === BotMode.WorkflowMode;
|
||||
|
||||
return (
|
||||
<div className="flex items-center justify-end gap-[12px] flex-1 overflow-hidden">
|
||||
<CollapsibleIconButtonGroup>
|
||||
<ModelConfigView
|
||||
mode={mode}
|
||||
modelListExtraHeaderSlot={modelListExtraHeaderSlot}
|
||||
/>
|
||||
{pageFrom === BotPageFromEnum.Bot && IS_OVERSEA ? (
|
||||
<MonetizeConfigButton />
|
||||
) : null}
|
||||
</CollapsibleIconButtonGroup>
|
||||
{!isReadonly && (isSingleLLM || isSingleWorkflow) ? (
|
||||
<ToolMenu
|
||||
newbieGuideVisible={!toolHiddenModeNewbieGuideIsRead}
|
||||
onNewbieGuidePopoverClose={onNewbieGuidePopoverClose}
|
||||
rePosKey={Math.random()}
|
||||
/>
|
||||
) : 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 { BotConfigArea } from './bot-config-area';
|
||||
|
||||
export { SingleAgentModelView } from './model-config-view/single-agent-model-view';
|
||||
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export { ModelConfigView } from './model-config-view';
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import { BotMode } from '@coze-arch/bot-api/playground_api';
|
||||
import { useGetSingleAgentCurrentModel } from '@coze-agent-ide/model-manager';
|
||||
import { DialogueConfigView } from '@coze-agent-ide/bot-config-area';
|
||||
|
||||
import { SingleAgentModelView } from './single-agent-model-view';
|
||||
|
||||
export const ModelConfigView: React.FC<{
|
||||
mode: BotMode;
|
||||
modelListExtraHeaderSlot?: React.ReactNode;
|
||||
}> = ({ mode, modelListExtraHeaderSlot }) => {
|
||||
const currentModel = useGetSingleAgentCurrentModel();
|
||||
|
||||
if (mode === BotMode.SingleMode) {
|
||||
return currentModel?.model_type ? (
|
||||
<SingleAgentModelView
|
||||
modelListExtraHeaderSlot={modelListExtraHeaderSlot}
|
||||
/>
|
||||
) : null;
|
||||
}
|
||||
if (mode === BotMode.MultiMode || mode === BotMode.WorkflowMode) {
|
||||
return (
|
||||
<DialogueConfigView
|
||||
tips={
|
||||
mode === BotMode.WorkflowMode
|
||||
? I18n.t('workflow_agent_dialog_set_desc')
|
||||
: null
|
||||
}
|
||||
/>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import { Image } from '@coze-arch/bot-semi';
|
||||
import { Collapsible } from '@coze-studio/components/collapsible-icon-button';
|
||||
import { ModelOptionThumb } from '@coze-agent-ide/model-manager/model-select-v2';
|
||||
import {
|
||||
SingleAgentModelView as SingleAgentModelViewBase,
|
||||
type SingleAgentModelViewProps,
|
||||
} from '@coze-agent-ide/bot-config-area';
|
||||
import { IconCozArrowDown } from '@coze-arch/coze-design/icons';
|
||||
import { Button, Tag } from '@coze-arch/coze-design';
|
||||
|
||||
const itemKey = Symbol.for('SingleAgentModelView');
|
||||
|
||||
export function SingleAgentModelView(props: SingleAgentModelViewProps) {
|
||||
return (
|
||||
<SingleAgentModelViewBase
|
||||
{...props}
|
||||
triggerRender={m => (
|
||||
// 模型临期时强制完整展示临期提示
|
||||
<Collapsible
|
||||
itemKey={itemKey}
|
||||
fullContent={
|
||||
<Button
|
||||
color="secondary"
|
||||
size="default"
|
||||
data-testid="bot.ide.bot_creator.set_model_view_button"
|
||||
>
|
||||
{m ? <ModelOptionThumb model={m} /> : null}
|
||||
<IconCozArrowDown className="coz-fg-secondary" />
|
||||
</Button>
|
||||
}
|
||||
collapsedContent={
|
||||
<Button
|
||||
size="default"
|
||||
color="secondary"
|
||||
icon={
|
||||
<Image
|
||||
preview={false}
|
||||
className="leading-none"
|
||||
width={16}
|
||||
height={16}
|
||||
src={m?.model_icon}
|
||||
/>
|
||||
}
|
||||
>
|
||||
{m?.model_status_details?.is_upcoming_deprecated ? (
|
||||
<span className="h-full flex items-center">
|
||||
<Tag size="mini" color="yellow" className="font-medium">
|
||||
{I18n.t('model_list_willDeprecated')}
|
||||
</Tag>
|
||||
</span>
|
||||
) : null}
|
||||
</Button>
|
||||
}
|
||||
collapsedTooltip={m?.name}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
18
frontend/packages/agent-ide/bot-config-area-adapter/src/typings.d.ts
vendored
Normal file
18
frontend/packages/agent-ide/bot-config-area-adapter/src/typings.d.ts
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/// <reference types='@coze-arch/bot-typings' />
|
||||
declare const IS_OVERSEA: boolean;
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { DemoComponent } from '../src';
|
||||
|
||||
export default {
|
||||
title: 'Example/Demo',
|
||||
component: DemoComponent,
|
||||
parameters: {
|
||||
// Optional parameter to center the component in the Canvas. More info: https://storybook.js.org/docs/configure/story-layout
|
||||
layout: 'centered',
|
||||
},
|
||||
// This component will have an automatically generated Autodocs entry: https://storybook.js.org/docs/writing-docs/autodocs
|
||||
tags: ['autodocs'],
|
||||
// More on argTypes: https://storybook.js.org/docs/api/argtypes
|
||||
argTypes: {},
|
||||
};
|
||||
|
||||
// More on writing stories with args: https://storybook.js.org/docs/writing-stories/args
|
||||
export const Base = {
|
||||
args: {
|
||||
name: 'tecvan',
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,34 @@
|
||||
import { Meta } from "@storybook/blocks";
|
||||
|
||||
<Meta title="Hello world" />
|
||||
|
||||
<div className="sb-container">
|
||||
<div className='sb-section-title'>
|
||||
# Hello world
|
||||
|
||||
Hello world
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
{`
|
||||
.sb-container {
|
||||
margin-bottom: 48px;
|
||||
}
|
||||
|
||||
.sb-section {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
img {
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.sb-section-title {
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
`}
|
||||
</style>
|
||||
@@ -0,0 +1,60 @@
|
||||
{
|
||||
"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-typings/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../../arch/i18n/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../bot-config-area/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../../components/bot-semi/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../../../config/eslint-config/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../../../config/stylelint-config/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../../../config/ts-config/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../../../config/vitest-config/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../model-manager/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../space-bot/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../../studio/components/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../../studio/stores/bot-detail/tsconfig.build.json"
|
||||
},
|
||||
{
|
||||
"path": "../tool/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/agent-ide/bot-config-area/README.md
Normal file
16
frontend/packages/agent-ide/bot-config-area/README.md
Normal file
@@ -0,0 +1,16 @@
|
||||
# @coze-agent-ide/bot-config-area
|
||||
|
||||
> 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: {},
|
||||
});
|
||||
58
frontend/packages/agent-ide/bot-config-area/package.json
Normal file
58
frontend/packages/agent-ide/bot-config-area/package.json
Normal file
@@ -0,0 +1,58 @@
|
||||
{
|
||||
"name": "@coze-agent-ide/bot-config-area",
|
||||
"version": "0.0.1",
|
||||
"description": "@coze-agent-ide/bot-config-area",
|
||||
"license": "Apache-2.0",
|
||||
"author": "haozhenfei@bytedance.com",
|
||||
"maintainers": [],
|
||||
"main": "src/index.ts",
|
||||
"scripts": {
|
||||
"build": "exit 0",
|
||||
"lint": "eslint ./ --cache",
|
||||
"test": "vitest --run --passWithNoTests",
|
||||
"test:cov": "npm run test -- --coverage"
|
||||
},
|
||||
"dependencies": {
|
||||
"@coze-agent-ide/bot-creator-context": "workspace:*",
|
||||
"@coze-agent-ide/bot-editor-context-store": "workspace:*",
|
||||
"@coze-agent-ide/model-manager": "workspace:*",
|
||||
"@coze-agent-ide/space-bot": "workspace:*",
|
||||
"@coze-agent-ide/tool": "workspace:*",
|
||||
"@coze-arch/bot-api": "workspace:*",
|
||||
"@coze-arch/bot-semi": "workspace:*",
|
||||
"@coze-arch/bot-studio-store": "workspace:*",
|
||||
"@coze-arch/coze-design": "0.0.6-alpha.346d77",
|
||||
"@coze-arch/i18n": "workspace:*",
|
||||
"@coze-arch/idl": "workspace:*",
|
||||
"@coze-studio/bot-detail-store": "workspace:*",
|
||||
"@coze-studio/components": "workspace:*",
|
||||
"ahooks": "^3.7.8",
|
||||
"classnames": "^2.3.2",
|
||||
"lodash-es": "^4.17.21",
|
||||
"zustand": "^4.4.7"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@coze-arch/bot-typings": "workspace:*",
|
||||
"@coze-arch/eslint-config": "workspace:*",
|
||||
"@coze-arch/stylelint-config": "workspace:*",
|
||||
"@coze-arch/ts-config": "workspace:*",
|
||||
"@coze-arch/vitest-config": "workspace:*",
|
||||
"@testing-library/jest-dom": "^6.1.5",
|
||||
"@testing-library/react": "^14.1.2",
|
||||
"@testing-library/react-hooks": "^8.0.1",
|
||||
"@types/lodash-es": "^4.17.10",
|
||||
"@types/react": "18.2.37",
|
||||
"@types/react-dom": "18.2.15",
|
||||
"@vitest/coverage-v8": "~3.0.5",
|
||||
"react": "~18.2.0",
|
||||
"react-dom": "~18.2.0",
|
||||
"stylelint": "^15.11.0",
|
||||
"vite-plugin-svgr": "~3.3.0",
|
||||
"vitest": "~3.0.5"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=18.2.0",
|
||||
"react-dom": ">=18.2.0"
|
||||
}
|
||||
}
|
||||
|
||||
23
frontend/packages/agent-ide/bot-config-area/src/index.ts
Normal file
23
frontend/packages/agent-ide/bot-config-area/src/index.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export { DialogueConfigView } from './model-config-view/dialogue-config-view';
|
||||
export { SingleAgentModelView } from './model-config-view/single-agent-model-view';
|
||||
export { MonetizeConfigButton } from './monetize-config/button';
|
||||
export { MonetizeConfigPanel } from './monetize-config/panel';
|
||||
export { QueryCollect } from './query-collect';
|
||||
export { ModelConfigView } from './model-config-view';
|
||||
export type { SingleAgentModelViewProps } from './model-config-view/single-agent-model-view';
|
||||
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { type FC, type ReactNode } from 'react';
|
||||
|
||||
import { useShallow } from 'zustand/react/shallow';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import { Popover } from '@coze-arch/bot-semi';
|
||||
import { CollapsibleIconButton } from '@coze-studio/components/collapsible-icon-button';
|
||||
import { InputSlider } from '@coze-studio/components';
|
||||
import { useModelStore } from '@coze-studio/bot-detail-store/model';
|
||||
import { ModelFormItem } from '@coze-agent-ide/model-manager';
|
||||
import { IconCozChatSetting } from '@coze-arch/coze-design/icons';
|
||||
|
||||
const DialogueConfig: FC<{ tips: ReactNode }> = ({ tips }) => {
|
||||
const { model, setModelByImmer } = useModelStore(
|
||||
useShallow(state => ({
|
||||
model: state,
|
||||
setModelByImmer: state.setModelByImmer,
|
||||
})),
|
||||
);
|
||||
|
||||
const handleChange = (value: number) => {
|
||||
setModelByImmer(draft => {
|
||||
if (!draft.config.ShortMemPolicy) {
|
||||
draft.config.ShortMemPolicy = { HistoryRound: value };
|
||||
return;
|
||||
}
|
||||
draft.config.ShortMemPolicy.HistoryRound = value;
|
||||
});
|
||||
};
|
||||
return (
|
||||
<div className="p-[24px]">
|
||||
<div className="leading-[32px] coz-fg-plus text-[20px] font-[500]">
|
||||
{I18n.t('workflow_agent_dialog_set')}
|
||||
</div>
|
||||
{tips ? (
|
||||
<div className="mt-[16px] coz-fg-secondary text-[14px] leading-[20px]">
|
||||
{tips}
|
||||
</div>
|
||||
) : null}
|
||||
<div className="mt-[16px] coz-fg-plus text-[14px] leading-[20px] font-[500]">
|
||||
{I18n.t('workflow_agent_dialog_set_chathistory')}
|
||||
</div>
|
||||
<ModelFormItem
|
||||
popoverContent={I18n.t('model_config_history_round_explain')}
|
||||
label={I18n.t('model_config_history_round')}
|
||||
>
|
||||
<InputSlider
|
||||
step={1}
|
||||
min={0}
|
||||
max={100}
|
||||
decimalPlaces={0}
|
||||
value={model.config.ShortMemPolicy?.HistoryRound}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
</ModelFormItem>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const itemKey = Symbol.for('DialogueConfigView');
|
||||
|
||||
export const DialogueConfigView: FC<{
|
||||
tips: ReactNode;
|
||||
}> = ({ tips }) => (
|
||||
<Popover
|
||||
className="overflow-hidden rounded-[12px] w-[600px]"
|
||||
trigger="click"
|
||||
autoAdjustOverflow={true}
|
||||
content={<DialogueConfig tips={tips} />}
|
||||
>
|
||||
<CollapsibleIconButton
|
||||
itemKey={itemKey}
|
||||
data-testid="bot.ide.bot_creator.set_model_view_button"
|
||||
icon={<IconCozChatSetting className="text-[16px]" />}
|
||||
text={I18n.t('workflow_agent_dialog_set')}
|
||||
/>
|
||||
</Popover>
|
||||
);
|
||||
@@ -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 { DialogueConfigView } from './dialogue-config-view';
|
||||
export { SingleAgentModelView } from './single-agent-model-view';
|
||||
export { ModelConfigView } from './model-config-view';
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import { BotMode } from '@coze-arch/bot-api/playground_api';
|
||||
import { useGetSingleAgentCurrentModel } from '@coze-agent-ide/model-manager';
|
||||
|
||||
import { SingleAgentModelView } from './single-agent-model-view';
|
||||
import { DialogueConfigView } from './dialogue-config-view';
|
||||
|
||||
export const ModelConfigView: React.FC<{
|
||||
mode: BotMode;
|
||||
modelListExtraHeaderSlot?: React.ReactNode;
|
||||
}> = ({ mode, modelListExtraHeaderSlot }) => {
|
||||
const currentModel = useGetSingleAgentCurrentModel();
|
||||
|
||||
if (mode === BotMode.SingleMode) {
|
||||
return currentModel?.model_type ? (
|
||||
<SingleAgentModelView
|
||||
modelListExtraHeaderSlot={modelListExtraHeaderSlot}
|
||||
/>
|
||||
) : null;
|
||||
}
|
||||
if (mode === BotMode.MultiMode || mode === BotMode.WorkflowMode) {
|
||||
return (
|
||||
<DialogueConfigView
|
||||
tips={
|
||||
mode === BotMode.WorkflowMode
|
||||
? I18n.t('workflow_agent_dialog_set_desc')
|
||||
: null
|
||||
}
|
||||
/>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
import { useShallow } from 'zustand/react/shallow';
|
||||
import { useModelStore } from '@coze-studio/bot-detail-store/model';
|
||||
import { useBotDetailIsReadonly } from '@coze-studio/bot-detail-store';
|
||||
import { useSpaceStore } from '@coze-arch/bot-studio-store';
|
||||
import { type Model } from '@coze-arch/bot-api/developer_api';
|
||||
import { ModelSelect } from '@coze-agent-ide/model-manager/model-select-v2';
|
||||
import {
|
||||
useModelCapabilityCheckModal,
|
||||
useGetSingleAgentCurrentModel,
|
||||
getModelOptionList,
|
||||
} from '@coze-agent-ide/model-manager';
|
||||
import { useBotEditor } from '@coze-agent-ide/bot-editor-context-store';
|
||||
import {
|
||||
useBotCreatorContext,
|
||||
BotCreatorScene,
|
||||
} from '@coze-agent-ide/bot-creator-context';
|
||||
|
||||
export interface SingleAgentModelViewProps {
|
||||
modelListExtraHeaderSlot?: React.ReactNode;
|
||||
triggerRender?: (model?: Model, popoverVisible?: boolean) => React.ReactNode;
|
||||
}
|
||||
|
||||
export function SingleAgentModelView(props: SingleAgentModelViewProps) {
|
||||
const { modelListExtraHeaderSlot, triggerRender } = props;
|
||||
const spaceId = useSpaceStore(store => store.space.id);
|
||||
const { scene } = useBotCreatorContext();
|
||||
const currentModel = useGetSingleAgentCurrentModel();
|
||||
const currentModelId = currentModel?.model_type
|
||||
? String(currentModel.model_type)
|
||||
: undefined;
|
||||
|
||||
const { storeSet } = useBotEditor();
|
||||
const modelStore = storeSet.useModelStore(
|
||||
useShallow(state => ({
|
||||
onlineModelList: state.onlineModelList,
|
||||
offlineModelMap: state.offlineModelMap,
|
||||
getModelPreset: state.getModelPreset,
|
||||
})),
|
||||
);
|
||||
|
||||
const [currentModelIdState, setCurrentModelIdState] = useState<
|
||||
string | undefined
|
||||
>(currentModelId);
|
||||
|
||||
const { modelConfig, setModelByImmer } = useModelStore(
|
||||
useShallow(state => ({
|
||||
modelConfig: state.config,
|
||||
setModelByImmer: state.setModelByImmer,
|
||||
})),
|
||||
);
|
||||
|
||||
const { modalNode, checkAndOpenModal } = useModelCapabilityCheckModal({
|
||||
onOk: modelId => {
|
||||
setCurrentModelIdState(modelId);
|
||||
},
|
||||
});
|
||||
|
||||
const isReadonly = useBotDetailIsReadonly();
|
||||
|
||||
const modelList = getModelOptionList({
|
||||
onlineModelList: modelStore.onlineModelList,
|
||||
offlineModelMap: modelStore.offlineModelMap,
|
||||
currentModelId: String(currentModel?.model_type),
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
setCurrentModelIdState(currentModelId);
|
||||
}, [currentModelId]);
|
||||
|
||||
return currentModelIdState ? (
|
||||
<>
|
||||
<ModelSelect
|
||||
popoverClassName="h-auto !max-h-[70vh]"
|
||||
disabled={isReadonly}
|
||||
enableJumpDetail={
|
||||
scene === BotCreatorScene.Bot && spaceId && !IS_OPEN_SOURCE
|
||||
? { spaceId }
|
||||
: undefined
|
||||
}
|
||||
modelListExtraHeaderSlot={modelListExtraHeaderSlot}
|
||||
selectedModelId={currentModelIdState}
|
||||
modelList={modelList}
|
||||
onModelChange={m => {
|
||||
const modelId = String(m.model_type);
|
||||
const checkPassed = checkAndOpenModal(modelId);
|
||||
if (checkPassed) {
|
||||
setCurrentModelIdState(modelId);
|
||||
}
|
||||
return checkPassed;
|
||||
}}
|
||||
modelConfigProps={{
|
||||
hideDiversityCollapseButton: true,
|
||||
agentType: 'single',
|
||||
currentConfig: modelConfig,
|
||||
onConfigChange: v => {
|
||||
setModelByImmer(draft => {
|
||||
draft.config = {
|
||||
model: currentModelIdState,
|
||||
...v,
|
||||
};
|
||||
});
|
||||
},
|
||||
modelStore,
|
||||
}}
|
||||
triggerRender={triggerRender}
|
||||
modalSlot={modalNode}
|
||||
/>
|
||||
</>
|
||||
) : null;
|
||||
}
|
||||
@@ -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 { CollapsibleIconButton } from '@coze-studio/components/collapsible-icon-button';
|
||||
import { useMonetizeConfigStore } from '@coze-studio/bot-detail-store';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import { IconCozWallet } from '@coze-arch/coze-design/icons';
|
||||
import { Popover } from '@coze-arch/coze-design';
|
||||
|
||||
import { MonetizeConfigPanel } from '../panel';
|
||||
|
||||
const itemKey = Symbol.for('MonetizeConfigButton');
|
||||
|
||||
export function MonetizeConfigButton() {
|
||||
const isOn = useMonetizeConfigStore(store => store.isOn);
|
||||
|
||||
return (
|
||||
<Popover
|
||||
trigger="click"
|
||||
autoAdjustOverflow={true}
|
||||
content={<MonetizeConfigPanel />}
|
||||
>
|
||||
<CollapsibleIconButton
|
||||
itemKey={itemKey}
|
||||
icon={<IconCozWallet className="text-[16px]" />}
|
||||
text={isOn ? I18n.t('monetization_on') : I18n.t('monetization_off')}
|
||||
color={isOn ? 'highlight' : 'secondary'}
|
||||
/>
|
||||
</Popover>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Copyright 2025 coze-dev Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { useDebounceFn } from 'ahooks';
|
||||
import { useMonetizeConfigReadonly } from '@coze-agent-ide/space-bot/hook';
|
||||
import {
|
||||
MonetizeCreditRefreshCycle,
|
||||
MonetizeDescription,
|
||||
MonetizeFreeChatCount,
|
||||
MonetizeSwitch,
|
||||
} from '@coze-studio/components/monetize';
|
||||
import { useBotInfoStore } from '@coze-studio/bot-detail-store/bot-info';
|
||||
import { useMonetizeConfigStore } from '@coze-studio/bot-detail-store';
|
||||
import {
|
||||
MonetizationEntityType,
|
||||
type BotMonetizationRefreshPeriod,
|
||||
} from '@coze-arch/idl/benefit';
|
||||
import { benefitApi } from '@coze-arch/bot-api';
|
||||
|
||||
export function MonetizeConfigPanel() {
|
||||
const botId = useBotInfoStore(store => store.botId);
|
||||
const {
|
||||
isOn,
|
||||
freeCount,
|
||||
refreshCycle,
|
||||
setIsOn,
|
||||
setFreeCount,
|
||||
setRefreshCycle,
|
||||
} = useMonetizeConfigStore();
|
||||
const isReadonly = useMonetizeConfigReadonly();
|
||||
|
||||
const { run: debouncedSaveBotConfig } = useDebounceFn(
|
||||
({
|
||||
isEnable,
|
||||
freeChats,
|
||||
}: {
|
||||
isEnable: boolean;
|
||||
freeChats: number;
|
||||
refreshCycle: BotMonetizationRefreshPeriod;
|
||||
}) => {
|
||||
benefitApi.PublicSaveBotDraftMonetizationConfig({
|
||||
entity_id: botId,
|
||||
entity_type: MonetizationEntityType.Bot,
|
||||
is_enable: isEnable,
|
||||
free_chat_allowance_count: freeChats,
|
||||
refresh_period: refreshCycle,
|
||||
});
|
||||
},
|
||||
{ wait: 300 },
|
||||
);
|
||||
|
||||
const refreshCycleDisabled = !isOn || isReadonly || freeCount <= 0;
|
||||
|
||||
return (
|
||||
<div className="w-[480px] p-[24px] flex flex-col gap-[24px]">
|
||||
<MonetizeSwitch
|
||||
disabled={isReadonly}
|
||||
isOn={isOn}
|
||||
onChange={value => {
|
||||
setIsOn(value);
|
||||
debouncedSaveBotConfig({
|
||||
isEnable: value,
|
||||
freeChats: freeCount,
|
||||
refreshCycle,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
<MonetizeDescription isOn={isOn} />
|
||||
<MonetizeFreeChatCount
|
||||
isOn={isOn}
|
||||
disabled={isReadonly}
|
||||
freeCount={freeCount}
|
||||
onFreeCountChange={value => {
|
||||
setFreeCount(value);
|
||||
debouncedSaveBotConfig({
|
||||
isEnable: isOn,
|
||||
freeChats: value,
|
||||
refreshCycle,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
<MonetizeCreditRefreshCycle
|
||||
freeCount={freeCount}
|
||||
disabled={refreshCycleDisabled}
|
||||
refreshCycle={refreshCycle}
|
||||
onRefreshCycleChange={value => {
|
||||
setRefreshCycle(value);
|
||||
debouncedSaveBotConfig({
|
||||
isEnable: isOn,
|
||||
freeChats: freeCount,
|
||||
refreshCycle: value,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,237 @@
|
||||
/*
|
||||
* 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, type MouseEvent, useEffect, useRef, useState } from 'react';
|
||||
|
||||
import { get } from 'lodash-es';
|
||||
import { useBotInfoStore } from '@coze-studio/bot-detail-store/bot-info';
|
||||
import { I18n } from '@coze-arch/i18n';
|
||||
import { IconCozTamplate } from '@coze-arch/coze-design/icons';
|
||||
import {
|
||||
Button,
|
||||
Form,
|
||||
type FormApi,
|
||||
IconButton,
|
||||
Popover,
|
||||
Typography,
|
||||
} from '@coze-arch/coze-design';
|
||||
import { type GenerateUserQueryCollectPolicyRequest } from '@coze-arch/bot-api/playground_api';
|
||||
|
||||
import { Tips } from './tips';
|
||||
|
||||
import s from './index.module.less';
|
||||
|
||||
const options = [
|
||||
{
|
||||
label: I18n.t('bot_dev_privacy_setting_conversation'),
|
||||
value: I18n.t('bot_dev_privacy_setting_conversation'),
|
||||
},
|
||||
];
|
||||
const defaultOptionsValue = [I18n.t('bot_dev_privacy_setting_conversation')];
|
||||
interface GenerateByTemplateProps {
|
||||
handleGenerate: (v: GenerateUserQueryCollectPolicyRequest) => void;
|
||||
loading: boolean;
|
||||
templateLink: string;
|
||||
link: string;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @coze-arch/max-line-per-function
|
||||
export const GenerateByTemplate: FC<GenerateByTemplateProps> = ({
|
||||
handleGenerate,
|
||||
loading,
|
||||
templateLink,
|
||||
link,
|
||||
}) => {
|
||||
const { botId } = useBotInfoStore($store => ({
|
||||
botId: $store.botId,
|
||||
}));
|
||||
const [visible, setVisible] = useState(false);
|
||||
const [configInfo, setConfigInfo] =
|
||||
useState<GenerateUserQueryCollectPolicyRequest>();
|
||||
const [isFailToValid, setIsFailToValid] = useState(true);
|
||||
|
||||
const formApi = useRef<FormApi<GenerateUserQueryCollectPolicyRequest>>();
|
||||
|
||||
const onFormValueChange = (values: GenerateUserQueryCollectPolicyRequest) => {
|
||||
const developerName = get(values, 'developer_name');
|
||||
const contactInformation = get(values, 'contact_information');
|
||||
setIsFailToValid(!(developerName && contactInformation));
|
||||
setConfigInfo({
|
||||
...values,
|
||||
});
|
||||
};
|
||||
|
||||
const onVisibleChange = (isVisble: boolean) => {
|
||||
if (isVisble) {
|
||||
setDefaultValue();
|
||||
}
|
||||
};
|
||||
|
||||
const setDefaultValue = () => {
|
||||
if (configInfo) {
|
||||
formApi.current?.setValue('developer_name', configInfo.developer_name);
|
||||
formApi.current?.setValue(
|
||||
'contact_information',
|
||||
configInfo.contact_information,
|
||||
);
|
||||
}
|
||||
};
|
||||
useEffect(() => {
|
||||
if (link) {
|
||||
setConfigInfo({ developer_name: '', contact_information: '' });
|
||||
setVisible(false);
|
||||
}
|
||||
}, [link]);
|
||||
|
||||
const onClickGenerate = () => {
|
||||
handleGenerate({ ...configInfo, bot_id: botId });
|
||||
};
|
||||
const onOpen = (e: MouseEvent) => {
|
||||
e.stopPropagation();
|
||||
setVisible(true);
|
||||
};
|
||||
return (
|
||||
<Popover
|
||||
position="right"
|
||||
trigger="custom"
|
||||
stopPropagation={true}
|
||||
onVisibleChange={onVisibleChange}
|
||||
visible={visible}
|
||||
onClickOutSide={() => setVisible(false)}
|
||||
content={
|
||||
<div className="p-[16px] w-[320px]">
|
||||
<div className="coz-fg-plus text-[20px] font-medium leading-[32px]">
|
||||
{I18n.t('bot_dev_privacy_setting_privacy_template_1')}
|
||||
</div>
|
||||
<div className="coz-fg-primary text-[14px] font-normal leading-[20px] pb-[12px]">
|
||||
{I18n.t('bot_dev_privacy_setting_privacy_template_2', {
|
||||
privacy_template: (
|
||||
<Typography.Text link onClick={() => window.open(templateLink)}>
|
||||
{I18n.t('bot_dev_privacy_setting_privacy_template_3')}
|
||||
</Typography.Text>
|
||||
),
|
||||
})}
|
||||
</div>
|
||||
<div>
|
||||
<Form<GenerateUserQueryCollectPolicyRequest>
|
||||
getFormApi={api => (formApi.current = api)}
|
||||
labelPosition="top"
|
||||
showValidateIcon={false}
|
||||
className={s['form-wrap']}
|
||||
onValueChange={values =>
|
||||
onFormValueChange(
|
||||
values as GenerateUserQueryCollectPolicyRequest,
|
||||
)
|
||||
}
|
||||
autoComplete="off"
|
||||
disabled={loading}
|
||||
>
|
||||
<Form.Input
|
||||
field="developer_name"
|
||||
label={I18n.t('bot_dev_privacy_setting_developer_name')}
|
||||
style={{ width: '100%' }}
|
||||
trigger="blur"
|
||||
maxLength={50}
|
||||
placeholder={I18n.t(
|
||||
'bot_dev_privacy_setting_developer_collect3',
|
||||
)}
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: I18n.t(
|
||||
'bot_dev_privacy_setting_developer_collect3',
|
||||
),
|
||||
},
|
||||
]}
|
||||
/>
|
||||
<Form.Select
|
||||
field="collect_detail"
|
||||
label={{
|
||||
text: I18n.t('bot_dev_privacy_setting_developer_collect1'),
|
||||
extra: (
|
||||
<Tips
|
||||
content={I18n.t(
|
||||
'bot_dev_privacy_setting_developer_collect7',
|
||||
)}
|
||||
size="small"
|
||||
/>
|
||||
),
|
||||
}}
|
||||
optionList={options}
|
||||
disabled
|
||||
initValue={defaultOptionsValue}
|
||||
style={{ width: '100%' }}
|
||||
placeholder={I18n.t(
|
||||
'bot_dev_privacy_setting_developer_collect4',
|
||||
)}
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: I18n.t(
|
||||
'bot_dev_privacy_setting_developer_collect4',
|
||||
),
|
||||
},
|
||||
]}
|
||||
/>
|
||||
|
||||
<Form.Input
|
||||
field="contact_information"
|
||||
label={I18n.t('bot_dev_privacy_setting_developer_collect2')}
|
||||
style={{ width: '100%' }}
|
||||
trigger="blur"
|
||||
maxLength={50}
|
||||
placeholder={I18n.t(
|
||||
'bot_dev_privacy_setting_developer_collect5',
|
||||
)}
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: I18n.t(
|
||||
'bot_dev_privacy_setting_developer_collect5',
|
||||
),
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</Form>
|
||||
</div>
|
||||
<div className="flex justify-end mt-[12px]">
|
||||
<Button
|
||||
loading={loading}
|
||||
onClick={onClickGenerate}
|
||||
disabled={isFailToValid}
|
||||
>
|
||||
{I18n.t(
|
||||
loading
|
||||
? 'bot_dev_privacy_setting_generate_link2'
|
||||
: 'bot_dev_privacy_setting_generate_link1',
|
||||
)}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<IconButton
|
||||
icon={<IconCozTamplate />}
|
||||
iconPosition="left"
|
||||
color="secondary"
|
||||
size="small"
|
||||
onClick={onOpen}
|
||||
>
|
||||
{I18n.t('bot_dev_privacy_setting_privacy_template')}
|
||||
</IconButton>
|
||||
</Popover>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,96 @@
|
||||
/* stylelint-disable max-nesting-depth */
|
||||
/* stylelint-disable selector-class-pattern */
|
||||
.query-collect-modal {
|
||||
:global {
|
||||
.semi-modal-header {
|
||||
align-items: center;
|
||||
|
||||
.semi-button-borderless {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
padding: 11px;
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(var(--coze-bg-6), var(--coze-bg-6-alpha));
|
||||
}
|
||||
|
||||
&:active {
|
||||
background-color: rgba(var(--coze-bg-8), var(--coze-bg-8-alpha));
|
||||
}
|
||||
|
||||
.semi-button-content {
|
||||
color: rgba(var(--coze-fg-2), var(--coze-fg-2-alpha));
|
||||
|
||||
.semi-icon {
|
||||
font-size: 18px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.semi-modal-footer {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.semi-switch:not(.semi-switch-checked){
|
||||
background-color: var(--semi-color-fill-0);
|
||||
}
|
||||
|
||||
.semi-switch:not(.semi-switch-checked):hover {
|
||||
background-color: var(--semi-color-fill-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.form-wrap {
|
||||
:global {
|
||||
.semi-form-field {
|
||||
padding: 0;
|
||||
padding-bottom: 16px;
|
||||
}
|
||||
|
||||
.semi-form-field-label {
|
||||
margin-bottom: 6px;
|
||||
padding: 0 8px;
|
||||
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
font-style: normal;
|
||||
line-height: 16px;
|
||||
color: var(--coz-fg-secondary);
|
||||
}
|
||||
|
||||
.semi-form-field-error-message {
|
||||
padding-left: 8px;
|
||||
}
|
||||
|
||||
.semi-input-prefix-text {
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
color: var(--coz-fg-secondary);
|
||||
}
|
||||
|
||||
.semi-input-wrapper {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.semi-input-suffix {
|
||||
.coz-icon-button {
|
||||
display: flex;
|
||||
padding-right: 4px;
|
||||
|
||||
.coz-button.coz-btn-small{
|
||||
border-radius: 6px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.semi-form-field-label-required .semi-form-field-label-text::after{
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.semi-input-wrapper__with-suffix .semi-input{
|
||||
padding-right: 4px;
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user