chore: replace all cn comments of fe to en version by volc api (#320)
This commit is contained in:
parent
716ec0cba8
commit
71f6245a01
|
|
@ -83,7 +83,7 @@ const mergedConfig = defineConfig({
|
|||
source: {
|
||||
define: {
|
||||
'process.env.IS_REACT18': JSON.stringify(true),
|
||||
// arcosite editor sdk 内部使用
|
||||
// Arcosite editor sdk internal use
|
||||
'process.env.ARCOSITE_SDK_REGION': JSON.stringify(
|
||||
GLOBAL_ENVS.IS_OVERSEA ? 'VA' : 'CN',
|
||||
),
|
||||
|
|
@ -99,7 +99,7 @@ const mergedConfig = defineConfig({
|
|||
include: [
|
||||
path.resolve(__dirname, '../../packages'),
|
||||
path.resolve(__dirname, '../../infra/flags-devtool'),
|
||||
// 以下几个包包含未降级的 ES 2022 语法(private methods)需要参与打包
|
||||
// The following packages contain undegraded ES 2022 syntax (private methods) that need to be packaged
|
||||
/\/node_modules\/(marked|@dagrejs|@tanstack)\//,
|
||||
],
|
||||
alias: {
|
||||
|
|
|
|||
|
|
@ -31,15 +31,15 @@ const initFlags = () => {
|
|||
};
|
||||
|
||||
const main = () => {
|
||||
// 初始化功能开关的值
|
||||
// Initialize the value of the function switch
|
||||
initFlags();
|
||||
// 初始化i18n
|
||||
// Initialize i18n
|
||||
initI18nInstance({
|
||||
lng: (localStorage.getItem('i18next') ?? (IS_OVERSEA ? 'en' : 'zh-CN')) as
|
||||
| 'en'
|
||||
| 'zh-CN',
|
||||
});
|
||||
// 动态导入mdbox 样式
|
||||
// Import mdbox styles dynamically
|
||||
dynamicImportMdBoxStyle();
|
||||
|
||||
const $root = document.getElementById('root');
|
||||
|
|
|
|||
|
|
@ -16,128 +16,128 @@
|
|||
|
||||
import { lazy } from 'react';
|
||||
|
||||
// 登录页面
|
||||
// login page
|
||||
export const LoginPage = lazy(() =>
|
||||
import('@coze-foundation/account-ui-adapter').then(res => ({
|
||||
default: res.LoginPage,
|
||||
})),
|
||||
);
|
||||
|
||||
// 文档页面
|
||||
// documentation page
|
||||
export const Redirect = lazy(() => import('../pages/redirect'));
|
||||
|
||||
// 工作空间侧边栏组件
|
||||
// Workspace Sidebar Component
|
||||
export const spaceSubMenu = lazy(() =>
|
||||
import('@coze-foundation/space-ui-adapter').then(exps => ({
|
||||
default: exps.WorkspaceSubMenu,
|
||||
})),
|
||||
);
|
||||
|
||||
// 工作空间布局组件
|
||||
// Workspace Layout Component
|
||||
export const SpaceLayout = lazy(() =>
|
||||
import('@coze-foundation/space-ui-adapter').then(exps => ({
|
||||
default: exps.SpaceLayout,
|
||||
})),
|
||||
);
|
||||
|
||||
// 某个具体的工作空间布局组件
|
||||
// A specific workspace layout component
|
||||
export const SpaceIdLayout = lazy(() =>
|
||||
import('@coze-foundation/space-ui-base').then(exps => ({
|
||||
default: exps.SpaceIdLayout,
|
||||
})),
|
||||
);
|
||||
|
||||
// 项目开发页面
|
||||
// project development page
|
||||
export const Develop = lazy(() => import('../pages/develop'));
|
||||
|
||||
// 资源库页面
|
||||
// resource library page
|
||||
export const Library = lazy(() => import('../pages/library'));
|
||||
|
||||
// Agent IDE布局组件
|
||||
// Agent IDE Layout Component
|
||||
export const AgentIDELayout = lazy(
|
||||
() => import('@coze-agent-ide/layout-adapter'),
|
||||
);
|
||||
|
||||
// Agent IDE页面
|
||||
// Agent IDE page
|
||||
export const AgentIDE = lazy(() =>
|
||||
import('@coze-agent-ide/entry-adapter').then(res => ({
|
||||
default: res.BotEditor,
|
||||
})),
|
||||
);
|
||||
|
||||
// Agent IDE发布页面
|
||||
// Agent IDE Release Page
|
||||
export const AgentPublishPage = lazy(() =>
|
||||
import('@coze-agent-ide/agent-publish').then(exps => ({
|
||||
default: exps.AgentPublishPage,
|
||||
})),
|
||||
);
|
||||
|
||||
// Project IDE页面
|
||||
// Project IDE Page
|
||||
export const ProjectIDE = lazy(() =>
|
||||
import('@coze-project-ide/main').then(exps => ({
|
||||
default: exps.IDELayout,
|
||||
})),
|
||||
);
|
||||
|
||||
// Project IDE发布页面
|
||||
// Project IDE Release Page
|
||||
export const ProjectIDEPublish = lazy(() =>
|
||||
import('@coze-studio/project-publish').then(exps => ({
|
||||
default: exps.ProjectPublish,
|
||||
})),
|
||||
);
|
||||
|
||||
// 知识库预览页面
|
||||
// Knowledge Base Preview Page
|
||||
export const KnowledgePreview = lazy(() =>
|
||||
import('@coze-studio/workspace-base/knowledge-preview').then(exps => ({
|
||||
default: exps.KnowledgePreviewPage,
|
||||
})),
|
||||
);
|
||||
|
||||
// 知识库上传页面
|
||||
// Knowledge base upload page
|
||||
export const KnowledgeUpload = lazy(() =>
|
||||
import('@coze-studio/workspace-base/knowledge-upload').then(exps => ({
|
||||
default: exps.KnowledgeUploadPage,
|
||||
})),
|
||||
);
|
||||
|
||||
// 数据库资源页面
|
||||
// database resource page
|
||||
export const DatabaseDetail = lazy(() =>
|
||||
import('@coze-studio/workspace-base').then(exps => ({
|
||||
default: exps.DatabaseDetailPage,
|
||||
})),
|
||||
);
|
||||
|
||||
// 工作流页面
|
||||
// workflow page
|
||||
export const WorkflowPage = lazy(() =>
|
||||
import('@coze-workflow/playground-adapter').then(res => ({
|
||||
default: res.WorkflowPage,
|
||||
})),
|
||||
);
|
||||
|
||||
// 插件资源页面布局组件
|
||||
// plugin resource page layout component
|
||||
export const PluginLayout = lazy(() => import('../pages/plugin/layout'));
|
||||
|
||||
// 插件资源页面
|
||||
// plugin resource page
|
||||
export const PluginPage = lazy(() => import('../pages/plugin/page'));
|
||||
|
||||
// 插件工具页面
|
||||
// plugin tool page
|
||||
export const PluginToolPage = lazy(() => import('../pages/plugin/tool/page'));
|
||||
|
||||
// 探索体验页面二级导航组件
|
||||
// Explore the experience page secondary navigation component
|
||||
export const exploreSubMenu = lazy(() =>
|
||||
import('@coze-community/explore').then(exps => ({
|
||||
default: exps.ExploreSubMenu,
|
||||
})),
|
||||
);
|
||||
|
||||
// 模版页面
|
||||
// template page
|
||||
export const ExploreTemplatePage = lazy(() =>
|
||||
import('@coze-community/explore').then(exps => ({
|
||||
default: exps.TemplatePage,
|
||||
})),
|
||||
);
|
||||
|
||||
// 插件商店页面
|
||||
// plugin store page
|
||||
export const ExplorePluginPage = lazy(() =>
|
||||
import('@coze-community/explore').then(exps => ({
|
||||
default: exps.PluginPage,
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ import {
|
|||
|
||||
export const router: ReturnType<typeof createBrowserRouter> =
|
||||
createBrowserRouter([
|
||||
// 文档路由
|
||||
// Document routing
|
||||
{
|
||||
path: '/open/docs/*',
|
||||
Component: Redirect,
|
||||
|
|
@ -73,7 +73,7 @@ export const router: ReturnType<typeof createBrowserRouter> =
|
|||
requireAuth: false,
|
||||
}),
|
||||
},
|
||||
// 主应用路由
|
||||
// main application route
|
||||
{
|
||||
path: '/',
|
||||
Component: Layout,
|
||||
|
|
@ -83,7 +83,7 @@ export const router: ReturnType<typeof createBrowserRouter> =
|
|||
index: true,
|
||||
element: <Navigate to="/space" replace />,
|
||||
},
|
||||
// 登录页路由
|
||||
// login page routing
|
||||
{
|
||||
path: 'sign',
|
||||
Component: LoginPage,
|
||||
|
|
@ -94,7 +94,7 @@ export const router: ReturnType<typeof createBrowserRouter> =
|
|||
}),
|
||||
},
|
||||
|
||||
// 工作空间路由
|
||||
// Workspace Routing
|
||||
{
|
||||
path: 'space',
|
||||
Component: SpaceLayout,
|
||||
|
|
@ -114,7 +114,7 @@ export const router: ReturnType<typeof createBrowserRouter> =
|
|||
element: <Navigate to="develop" replace />,
|
||||
},
|
||||
|
||||
// 项目开发
|
||||
// Project Development
|
||||
{
|
||||
path: 'develop',
|
||||
Component: Develop,
|
||||
|
|
@ -171,7 +171,7 @@ export const router: ReturnType<typeof createBrowserRouter> =
|
|||
}),
|
||||
},
|
||||
|
||||
// 资源库
|
||||
// resource library
|
||||
{
|
||||
path: 'library',
|
||||
Component: Library,
|
||||
|
|
@ -180,7 +180,7 @@ export const router: ReturnType<typeof createBrowserRouter> =
|
|||
}),
|
||||
},
|
||||
|
||||
// 知识库资源
|
||||
// Knowledge Base Resources
|
||||
{
|
||||
path: 'knowledge',
|
||||
children: [
|
||||
|
|
@ -198,7 +198,7 @@ export const router: ReturnType<typeof createBrowserRouter> =
|
|||
}),
|
||||
},
|
||||
|
||||
// 数据库资源
|
||||
// database resources
|
||||
{
|
||||
path: 'database',
|
||||
children: [
|
||||
|
|
@ -213,7 +213,7 @@ export const router: ReturnType<typeof createBrowserRouter> =
|
|||
}),
|
||||
},
|
||||
|
||||
// 插件资源
|
||||
// plugin resources
|
||||
{
|
||||
path: 'plugin/:plugin_id',
|
||||
Component: PluginLayout,
|
||||
|
|
@ -238,7 +238,7 @@ export const router: ReturnType<typeof createBrowserRouter> =
|
|||
],
|
||||
},
|
||||
|
||||
// 工作流路由
|
||||
// workflow routing
|
||||
{
|
||||
path: 'work_flow',
|
||||
Component: WorkflowPage,
|
||||
|
|
@ -248,7 +248,7 @@ export const router: ReturnType<typeof createBrowserRouter> =
|
|||
}),
|
||||
},
|
||||
|
||||
// 探索
|
||||
// explore
|
||||
{
|
||||
path: 'explore',
|
||||
Component: null,
|
||||
|
|
@ -263,7 +263,7 @@ export const router: ReturnType<typeof createBrowserRouter> =
|
|||
index: true,
|
||||
element: <Navigate to="plugin" replace />,
|
||||
},
|
||||
// 插件商店
|
||||
// plugin store
|
||||
{
|
||||
path: 'plugin',
|
||||
element: <ExplorePluginPage />,
|
||||
|
|
@ -271,7 +271,7 @@ export const router: ReturnType<typeof createBrowserRouter> =
|
|||
type: 'plugin',
|
||||
}),
|
||||
},
|
||||
// 模版
|
||||
// template
|
||||
{
|
||||
path: 'template',
|
||||
element: <ExploreTemplatePage />,
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ console.log(`Got ${contents.length} contents for tailwind`);
|
|||
|
||||
export default {
|
||||
content: contents,
|
||||
// safelist的内容可以允许动态生成tailwind className
|
||||
// Safelist content can allow dynamic tailwind className
|
||||
safelist: [
|
||||
{
|
||||
pattern: /(gap-|grid-).+/,
|
||||
|
|
@ -47,7 +47,7 @@ export default {
|
|||
},
|
||||
},
|
||||
corePlugins: {
|
||||
preflight: false, // 关闭@tailwind base默认样式,避免对现有样式影响
|
||||
preflight: false, // Turn off @tailwind base default styles to avoid affecting existing styles
|
||||
},
|
||||
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
||||
plugins: [require('@coze-arch/tailwind-config/coze')],
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ module.exports = [
|
|||
...require('./eslint.config.base.js'),
|
||||
{
|
||||
plugins: {
|
||||
// TODO: 需要根据不同类型配置plugin?需要阅读源码确认是否影响性能
|
||||
// TODO: Need to configure plugins according to different types? You need to read the source code to confirm whether it affects performance
|
||||
'react-hooks': require('eslint-plugin-react-hooks'),
|
||||
react: require('eslint-plugin-react'),
|
||||
risxss: require('eslint-plugin-risxss'),
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ const readBlockList = () =>
|
|||
|
||||
/** @type {(import('eslint').Linter.Config)[]} */
|
||||
module.exports = [
|
||||
// NOTE: 不能和下一项配置合并
|
||||
// NOTE: Cannot be merged with the next configuration
|
||||
{
|
||||
ignores: [
|
||||
'**/*.d.ts',
|
||||
|
|
@ -68,7 +68,7 @@ module.exports = [
|
|||
...require('@coze-arch/eslint-plugin').configs.recommended,
|
||||
require('@coze-arch/eslint-plugin/zustand').configs.recommended,
|
||||
{
|
||||
files: ['**/*.?(m|c)?(j|t)s?(x)'], // 排除规则对package.json生效
|
||||
files: ['**/*.?(m|c)?(j|t)s?(x)'], // Exclusion rules take effect for package.json
|
||||
plugins: {
|
||||
prettier: require('eslint-plugin-prettier'),
|
||||
'@babel': require('@babel/eslint-plugin'),
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ module.exports = [
|
|||
{
|
||||
files: ['**/*.?(m|c)?(j|t)s?(x)'],
|
||||
settings: {
|
||||
// TODO: 全局保留一份配置
|
||||
// TODO: Keep a configuration globally
|
||||
'import/resolver': {
|
||||
node: {
|
||||
moduleDirectory: ['node_modules', 'src'],
|
||||
|
|
@ -72,8 +72,8 @@ module.exports = [
|
|||
},
|
||||
},
|
||||
rules: {
|
||||
// TODO: 目前由于 edenx 会动态生成一些插件模块,因此启动会报错
|
||||
// 后续需要修复问题,启动下述规则
|
||||
// TODO: At present, because edenx will dynamically generate some plug-in modules, an error will be reported when starting.
|
||||
// You need to fix the problem later, and start the following rules.
|
||||
// "import/no-unresolved": "error"
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -59,9 +59,9 @@ module.exports = [
|
|||
{
|
||||
vars: 'all',
|
||||
args: 'none', // function arguments should not force to match this rule.
|
||||
argsIgnorePattern: '^_', // 规范允许下划线
|
||||
ignoreRestSiblings: true, //使用rest语法(如 `var { foo, ...rest } = data`) 忽略foo。
|
||||
destructuredArrayIgnorePattern: '^_', //结构数组允许使用_
|
||||
argsIgnorePattern: '^_', // Specifications allow underlining
|
||||
ignoreRestSiblings: true, //Use rest syntax (such as'var {foo,... rest} = data ') to ignore foo.
|
||||
destructuredArrayIgnorePattern: '^_', //Structural arrays allow _
|
||||
caughtErrors: 'none',
|
||||
// "caughtErrorsIgnorePattern": "^e$"
|
||||
},
|
||||
|
|
@ -314,7 +314,7 @@ module.exports = [
|
|||
},
|
||||
},
|
||||
|
||||
// TODO: 之前overides的内容,后需可考虑直接合入上面标准配置
|
||||
// TODO: The content of overides before can be considered to be directly integrated into the above standard configuration later
|
||||
{
|
||||
files: ['**/*.?(m|c)ts?(x)'],
|
||||
rules: {
|
||||
|
|
@ -324,8 +324,8 @@ module.exports = [
|
|||
fixStyle: 'inline-type-imports',
|
||||
},
|
||||
],
|
||||
// 这些规则都是从 packages/config/.eslintrc.react.js 复制迁移过来
|
||||
// 后续在做调整
|
||||
// These rules are copied and migrated from packages/config/.eslintrc.react.js
|
||||
// Adjustments are being made later.
|
||||
'@typescript-eslint/no-redundant-type-constituents': 0,
|
||||
'@typescript-eslint/no-throw-literal': 'off',
|
||||
'@typescript-eslint/no-unnecessary-condition': 0,
|
||||
|
|
@ -335,14 +335,14 @@ module.exports = [
|
|||
'@typescript-eslint/explicit-function-return-type': 'off',
|
||||
'no-shadow': 'off',
|
||||
'@typescript-eslint/no-shadow': 'error',
|
||||
// TODO: 后续开启
|
||||
// TODO: Follow-up opening
|
||||
// 'import/no-cycle': 'error',
|
||||
|
||||
'@typescript-eslint/prefer-string-starts-ends-with': 0,
|
||||
'@typescript-eslint/no-unnecessary-boolean-literal-compare': 0,
|
||||
'@typescript-eslint/no-implied-eval': 0, // warning
|
||||
|
||||
// TODO: 打开下面这些配置
|
||||
// TODO: Open the following configurations
|
||||
// fix: https://stackoverflow.com/questions/63961803/eslint-says-all-enums-in-typescript-app-are-already-declared-in-the-upper-scope
|
||||
// 'no-shadow': 'off',
|
||||
// '@typescript-eslint/no-shadow': ['error'],
|
||||
|
|
@ -364,7 +364,7 @@ module.exports = [
|
|||
// },
|
||||
// ],
|
||||
// complexity: ['error', { max: 15 }],
|
||||
// 后面统一使用CustomError后 再开启
|
||||
// After using CustomError uniformly later, open it again.
|
||||
'@coze-arch/no-new-error': 'off',
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#!/usr/bin/env bash
|
||||
BASE_DIR=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
|
||||
|
||||
# 某些系统可能没有 realpath 命令,
|
||||
# Some systems may not have the realpath command.
|
||||
if ! command -v realpath &>/dev/null; then
|
||||
echo "未找到 realpath 命令"
|
||||
echo "请执行以下命令安装必要依赖"
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#!/usr/bin/env bash
|
||||
BASE_DIR=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
|
||||
|
||||
# 某些系统可能没有 realpath 命令,
|
||||
# Some systems may not have the realpath command.
|
||||
if ! command -v realpath &>/dev/null; then
|
||||
echo "未找到 realpath 命令"
|
||||
echo "请执行以下命令安装必要依赖"
|
||||
|
|
|
|||
|
|
@ -2,9 +2,9 @@ require('sucrase/register/ts');
|
|||
|
||||
const { defineConfig } = require('./define-config');
|
||||
|
||||
// node@16 没有 structuredClone 方法导致报错:
|
||||
// node@16 no structuredClone method causes an error:
|
||||
// ReferenceError: Error while loading rule '@typescript-eslint/naming-convention': structuredClone is not defined
|
||||
// 此处做个简单 polyfill
|
||||
// Make a simple polyfill here
|
||||
if (typeof structuredClone === 'undefined') {
|
||||
global.structuredClone = obj => JSON.parse(JSON.stringify(obj));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ import { SemiRspackPlugin } from '@douyinfe/semi-rspack-plugin';
|
|||
const getDefine = () => {
|
||||
const define = {};
|
||||
Object.keys(GLOBAL_ENVS).forEach(key => {
|
||||
// 在rspack的define中,字符串需要前后拼接上双引号,才能在代码中作为字符串使用。
|
||||
// In the definition of rspack, strings need to be enclosed in double quotes before they can be used as strings in code.
|
||||
if (typeof GLOBAL_ENVS[key] === 'string') {
|
||||
define[key] = `"${GLOBAL_ENVS[key]}"`;
|
||||
} else {
|
||||
|
|
@ -115,7 +115,7 @@ export const defineConfig = (options: Partial<RsbuildConfig>) => {
|
|||
),
|
||||
},
|
||||
include: [
|
||||
// 以下几个包包含未降级的 ES 2022 语法(private methods)需要参与打包
|
||||
// The following packages contain undegraded ES 2022 syntax (private methods) that need to be packaged
|
||||
/\/node_modules\/(marked|@dagrejs|@tanstack)\//,
|
||||
],
|
||||
},
|
||||
|
|
|
|||
|
|
@ -6,9 +6,9 @@ module.exports = {
|
|||
],
|
||||
plugins: ['./plugins/plugin-disallow-nesting-level-one-global.js'],
|
||||
rules: {
|
||||
// 变量命名规则,适应仓库内的代码风格
|
||||
// Variable naming rules to adapt to the code style in the warehouse
|
||||
'custom-property-pattern': '^([A-Za-z0-9]*)([-_]+[A-Za-z0-9]+)*$',
|
||||
// 对于less函数判断有问题
|
||||
// There is a problem with judging the less function
|
||||
'less/no-duplicate-variables': null,
|
||||
'media-feature-range-notation': null,
|
||||
'max-nesting-depth': [
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ const plugin = require('tailwindcss/plugin');
|
|||
const lightModeVariables = require('./light');
|
||||
const darkModeVariables = require('./dark');
|
||||
|
||||
// 用于生成 CSS 变量的帮助函数
|
||||
// Helper functions for generating CSS variables
|
||||
function generateCssVariables(variables, theme) {
|
||||
return Object.entries(variables).reduce((acc, [key, value]) => {
|
||||
acc[`--${key}`] = theme ? theme(value) : value;
|
||||
|
|
@ -13,7 +13,7 @@ function generateCssVariables(variables, theme) {
|
|||
}, {});
|
||||
}
|
||||
|
||||
// 样式语义化
|
||||
// style semantics
|
||||
function generateSemanticVariables(semantics, theme, property) {
|
||||
return Object.entries(semantics).map(([key, value]) => ({
|
||||
[`.${key}`]: {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// 暗色模式的 CSS 变量
|
||||
// CSS Variables for Dark Mode
|
||||
const darkModeVariables = {
|
||||
background: '2, 8, 23',
|
||||
foreground: '249, 249, 249',
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// 消费者和生产者公共的 tailwind 配置和工具函数
|
||||
// Common tailwind configurations and tool functions for consumers and producers
|
||||
|
||||
export function designTokenToTailwindConfig(
|
||||
tokenJson: Record<string, unknown>,
|
||||
|
|
@ -103,6 +103,6 @@ function borderRadiusTransformer(borderRadiusObj: Record<string, string>) {
|
|||
return res;
|
||||
}
|
||||
|
||||
// 获取其他packages,并且拼接上 /src/**/*.{ts,tsx}
|
||||
// Get other packages and splice /src /**/*.{ ts, tsx}
|
||||
|
||||
export { getTailwindContents } from './tailwind-contents';
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// 浅色模式的 CSS 变量
|
||||
// CSS Variables for Light Mode
|
||||
const lightModeVariables = {
|
||||
background: '255, 255, 255',
|
||||
foreground: '28, 28, 35',
|
||||
|
|
@ -27,7 +27,7 @@ const lightModeVariables = {
|
|||
'coze-fg-3': '15, 21, 40',
|
||||
'coze-fg-2': '32, 41, 69',
|
||||
'coze-fg-1': '55, 67, 106',
|
||||
// TODO: 需要删除bg9
|
||||
// TODO: need to remove bg9
|
||||
'coze-bg-9': '6, 7, 9',
|
||||
'coze-bg-8': '68, 83, 130',
|
||||
'coze-bg-7': '75, 90, 140',
|
||||
|
|
@ -151,7 +151,7 @@ const lightModeVariables = {
|
|||
'coze-3': '3px',
|
||||
'coze-2': '2px',
|
||||
'coze-1': '1px',
|
||||
// TODO: rspress编译不出来,需要通过一些工具处理,目前没有用到,暂时注释处理
|
||||
// TODO: rspress cannot be compiled, and it needs to be processed by some tools. It is not used at present. Temporary comment processing
|
||||
// 'coze-0.5': '0.5px',
|
||||
'coze-0-5': '0.5px',
|
||||
|
||||
|
|
@ -174,7 +174,7 @@ const lightModeVariables = {
|
|||
'coze-bg-6-alpha': '0.13',
|
||||
'coze-bg-7-alpha': '0.19',
|
||||
'coze-bg-8-alpha': '0.25',
|
||||
// TODO: 需要删除bg9
|
||||
// TODO: need to remove bg9
|
||||
'coze-bg-9-alpha': '0.16',
|
||||
'coze-stroke-5-alpha': '0.13',
|
||||
'coze-stroke-6-alpha': '0.25',
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ export const getTailwindContents = (projectRoot: string) => {
|
|||
.map(location => path.resolve(location, 'src/**/*.{ts,tsx}')),
|
||||
);
|
||||
|
||||
// 兼容 coze-design 内部 tailwind 样式
|
||||
// Compatible with coze-design internal tailwind style
|
||||
contents.push('./node_modules/@coze-arch/coze-design/**/*.{js,jsx}');
|
||||
|
||||
return contents;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#!/usr/bin/env bash
|
||||
BASE_DIR=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
|
||||
|
||||
# 某些系统可能没有 realpath 命令,
|
||||
# Some systems may not have the realpath command.
|
||||
if ! command -v realpath &>/dev/null; then
|
||||
echo "未找到 realpath 命令"
|
||||
echo "请执行以下命令安装必要依赖"
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@
|
|||
"moduleResolution": "node",
|
||||
"module": "CommonJS",
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
// 这个普遍反馈会让代码变得啰嗦,暂定遵循原本 bot 的设置,关闭
|
||||
// This general feedback will make the code verbose, tentatively follow the original bot's settings, close
|
||||
"noImplicitReturns": false,
|
||||
"removeComments": false,
|
||||
"resolveJsonModule": true,
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ const calBasePreset = (preset: string) => {
|
|||
|
||||
export interface OtherConfig {
|
||||
/**
|
||||
* 用于修复semi的package.json导出的配置问题
|
||||
* Used to fix the configuration issue of semi's package.json export
|
||||
*/
|
||||
fixSemi: boolean;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ import tsconfigPaths from 'vite-tsconfig-paths';
|
|||
export const defaultVitestConfig: UserConfig = {
|
||||
plugins: [tsconfigPaths()],
|
||||
resolve: {
|
||||
// 优先识别 main,如果没有配置 main,则识别 module
|
||||
// Priority to identify main, if main is not configured, identify the module
|
||||
mainFields: ['main', 'module', 'exports'],
|
||||
},
|
||||
server: {
|
||||
|
|
@ -38,14 +38,14 @@ export const defaultVitestConfig: UserConfig = {
|
|||
},
|
||||
},
|
||||
sequence: {
|
||||
// vitest 2.0之后,所有钩子默认串行运行
|
||||
// After vitest 2.0, all hooks run serially by default
|
||||
hooks: 'parallel',
|
||||
},
|
||||
globals: true,
|
||||
mockReset: false,
|
||||
silent: process.env.CI === 'true',
|
||||
coverage: {
|
||||
// 逐步对各包开启
|
||||
// Gradually open each package
|
||||
all: false,
|
||||
include: ['src/**/*.ts', 'src/**/*.tsx'],
|
||||
exclude: coverageConfigDefaults.exclude,
|
||||
|
|
|
|||
|
|
@ -1,16 +1,16 @@
|
|||
[
|
||||
// 可使用 @vitest/coverage-v8 替代
|
||||
// Can be replaced by @vitest/coverage-v8
|
||||
["@vitest/coverage-c8", null, "请使用 @vitest/coverage-v8"],
|
||||
"husky",
|
||||
"lint-staged",
|
||||
"jest",
|
||||
["jsdom", null, "请使用 happy-dom 代替"],
|
||||
// TODO: 等待完全修复后开启@tanjizhen
|
||||
// TODO: Open @tanjizhen after waiting for full repair
|
||||
// "@oceanos/logger",
|
||||
["inquirer", null, "请使用 @inquirer/prompts 代替"],
|
||||
["pdfjs-dist", null, "请使用 @coze-arch/pdfjs-shadow 代替"],
|
||||
// todo: should turn on this
|
||||
// ["valtio", null, "请使用 zustand"],
|
||||
// ["jotai", null, "请使用 zustand"]
|
||||
// ["Valtio", null, "Please use zustand"],
|
||||
// ["Jotai", null, "Please use zustand"]
|
||||
["@flow-web/md-box", null, "请使用 @coze-arch/bot-md-box-adapter 代替"]
|
||||
]
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ export const flowPreset = {
|
|||
'@coze-arch/tsx-no-leaked-render': 'warn',
|
||||
'@coze-arch/no-pkg-dir-import': 'error',
|
||||
'@coze-arch/no-duplicated-deps': 'error',
|
||||
// 不允许超过 4 层的相对应用
|
||||
// Relative applications with more than 4 layers are not allowed
|
||||
'@coze-arch/no-deep-relative-import': [
|
||||
'error',
|
||||
{
|
||||
|
|
@ -56,7 +56,7 @@ export const flowPreset = {
|
|||
},
|
||||
],
|
||||
'@coze-arch/package-require-author': 'error',
|
||||
// 函数代码行不要超过 150
|
||||
// Function code lines should not exceed 150.
|
||||
'@coze-arch/max-line-per-function': [
|
||||
'error',
|
||||
{
|
||||
|
|
@ -73,11 +73,11 @@ export const flowPreset = {
|
|||
files: ['package.json'],
|
||||
processor: '@coze-arch/json-processor',
|
||||
rules: {
|
||||
// TODO: 需要重构为直接解析json,否则全局规则都会对processor处理后的文件`package.js`生效.
|
||||
// TODO: It needs to be refactored to parse json directly, otherwise the global rules will take effect on the file'package.js' processed by the processor.
|
||||
//https://github.com/eslint/json
|
||||
'@coze-arch/package-require-author': 'error',
|
||||
'@coze-arch/package-disallow-deps': 'error',
|
||||
// 关闭prettier规则,因为该规则lint package.js存在bug
|
||||
// Close the prettier rule because there is a bug in the rule lint package.js
|
||||
'prettier/prettier': 'off',
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ const getStaticStringValue = node => {
|
|||
*
|
||||
* @param node
|
||||
* @returns
|
||||
* 为什么需要这个判断,对于下面这种函数
|
||||
* Why is this judgment necessary for a function such as
|
||||
* ```
|
||||
* var obj1 = {
|
||||
* set
|
||||
|
|
@ -46,9 +46,9 @@ const getStaticStringValue = node => {
|
|||
* }
|
||||
* }
|
||||
*```
|
||||
* 如果不采用下面这个判断,函数判断将得到3,实际应该为5. 类似的还有
|
||||
* If you don't use the following judgment, the function judgment will get 3, which should actually be 5. Similarly, there are
|
||||
* ```
|
||||
* //如果不采用下面这个判断,函数判断将得到3,实际应该为8
|
||||
* //If the following judgment is not used, the function judgment will get 3, which should actually be 8ing judgment, the function judgment will get 3, which should actually be 8.
|
||||
* class A {
|
||||
static
|
||||
[
|
||||
|
|
@ -85,14 +85,14 @@ const isEmbedded = node => {
|
|||
*
|
||||
* @param node
|
||||
* @returns function name
|
||||
* Q:为什么不直接用 node.id.value获取函数名称 ?
|
||||
* A:这种方式对于 传统的函数写法没问题,但是对于
|
||||
* Q: Why not get the function name directly with node.id?
|
||||
* A: This method is fine for traditional function writing, but for
|
||||
* const tips = {
|
||||
* fun: () => {}
|
||||
* };
|
||||
* 或者
|
||||
* or
|
||||
* const fun2 = () => {}
|
||||
* 方式书写函数得到的名称为null,所以采取下面这种方式获取,
|
||||
* The name of the function written in the following way is null, so it is obtained in the following way.
|
||||
*
|
||||
*/
|
||||
|
||||
|
|
@ -192,7 +192,7 @@ const getStaticPropertyName = node => {
|
|||
case 'VariableDeclarator':
|
||||
prop = node.id;
|
||||
break;
|
||||
//TODO: CallExpression 场景较为复杂,目前应该没有完全覆盖
|
||||
//TODO: The CallExpression scenario is more complex and should not be fully covered at present
|
||||
case 'CallExpression':
|
||||
prop = node.callee;
|
||||
break;
|
||||
|
|
@ -240,7 +240,7 @@ export const maxLinePerFunctionRule: Rule.RuleModule = {
|
|||
function checkFunctionLength(funcNode) {
|
||||
const node = isEmbedded(funcNode) ? funcNode.parent : funcNode;
|
||||
|
||||
// 针对函数声明,函数表达式,箭头函数,函数定义四种类型
|
||||
// Four types of function declarations, function expressions, arrow functions, and function definitions
|
||||
if (
|
||||
node.type === 'FunctionDeclaration' ||
|
||||
node.type === 'FunctionExpression' ||
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ export const noDuplicatedDepsRule: Rule.RuleModule = {
|
|||
if (!properties) {
|
||||
return;
|
||||
}
|
||||
// 对比 dependencies 与 devDependencies 之间是否存在重复依赖
|
||||
// Compare dependencies with devDependencies for duplicate dependencies
|
||||
const dependencies = properties.find(
|
||||
p => p.key.value === 'dependencies',
|
||||
);
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ export const noPkgDirImport: Rule.RuleModule = {
|
|||
const modulePath = resolve(importPath, context);
|
||||
|
||||
if (!modulePath) {
|
||||
// 解析不到的情况,暂不处理
|
||||
// If it cannot be resolved, it will not be dealt with for the time being.
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -56,15 +56,15 @@ export const noPkgDirImport: Rule.RuleModule = {
|
|||
return;
|
||||
}
|
||||
|
||||
// 本地link会解析到node_modules目录,需要拿到pkg name再次解析。
|
||||
// The local link will resolve to the node_modules directory, and you need to get the pkg name to resolve it again.
|
||||
const moduleRealPath = resolve(pkg.name, context);
|
||||
|
||||
if (
|
||||
// 包名称就是引用路径
|
||||
// The package name is the reference path
|
||||
pkg.name === importPath ||
|
||||
// 解析到其他包,如@type
|
||||
// Parse to other packages, such as @type
|
||||
!importPath.startsWith(pkg.name) ||
|
||||
// 解析到自己包的文件
|
||||
// Parse to the file of your own package
|
||||
currentPkgPath === importPkgPath ||
|
||||
!moduleRealPath ||
|
||||
moduleRealPath.includes('node_modules')
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ vi.mock('eslint-module-utils/readPkgUp', () => ({
|
|||
const validCases = [
|
||||
{
|
||||
code: 'import "xxx"',
|
||||
modulePath: undefined, // modulePath 为 空
|
||||
modulePath: undefined, // modulePath is empty
|
||||
moduleRealPath: undefined,
|
||||
importPkgPath: 'path/to/import/pkg',
|
||||
currentPkgPath: 'path/to/current/pkg',
|
||||
|
|
@ -48,7 +48,7 @@ const validCases = [
|
|||
importPkgPath: 'path/to/import/pkg',
|
||||
currentPkgPath: 'path/to/current/pkg',
|
||||
pkg: {
|
||||
name: 'some/pkg', // 包名称与引用路径相同
|
||||
name: 'some/pkg', // The package name is the same as the reference path
|
||||
exports: {},
|
||||
},
|
||||
},
|
||||
|
|
@ -59,7 +59,7 @@ const validCases = [
|
|||
importPkgPath: 'path/to/import/pkg',
|
||||
currentPkgPath: 'path/to/current/pkg',
|
||||
pkg: {
|
||||
name: undefined, // 解析到不规范配置的package.json
|
||||
name: undefined, // Parse to the non-canonical package.json
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
@ -69,7 +69,7 @@ const validCases = [
|
|||
importPkgPath: 'path/to/import/pkg',
|
||||
currentPkgPath: 'path/to/current/pkg',
|
||||
pkg: {
|
||||
name: '@types/pkg', // 解析到类型包
|
||||
name: '@types/pkg', // Parse to type package
|
||||
exports: {},
|
||||
},
|
||||
},
|
||||
|
|
@ -77,7 +77,7 @@ const validCases = [
|
|||
code: "import pkg from 'pkg';",
|
||||
modulePath: 'path/to/module',
|
||||
moduleRealPath: 'path/to/module',
|
||||
importPkgPath: 'path/to/same/pkg', // 相同路径
|
||||
importPkgPath: 'path/to/same/pkg', // same path
|
||||
currentPkgPath: 'path/to/same/pkg',
|
||||
pkg: {
|
||||
name: '@types/pkg',
|
||||
|
|
@ -98,7 +98,7 @@ const validCases = [
|
|||
{
|
||||
code: "import pkg from 'pkg';",
|
||||
modulePath: 'path/to/module',
|
||||
moduleRealPath: 'path/to/node_modules/pkg', // 解析到node_modules
|
||||
moduleRealPath: 'path/to/node_modules/pkg', // Parse to node_modules
|
||||
importPkgPath: 'path/to/import/pkg',
|
||||
currentPkgPath: 'path/to/current/pkg',
|
||||
pkg: {
|
||||
|
|
@ -134,7 +134,7 @@ const validCases = [
|
|||
if (!c.modulePath) {
|
||||
return {
|
||||
code: c.code,
|
||||
// TODO: 避免eslint duplication检测。可能需要改为其他方式
|
||||
// TODO: Avoid eslint duplication. It may need to be changed to another way
|
||||
settings: c,
|
||||
};
|
||||
}
|
||||
|
|
@ -167,7 +167,7 @@ const invalidCases = [
|
|||
currentPkgPath: 'path/to/current/pkg',
|
||||
pkg: {
|
||||
name: 'pkg',
|
||||
exports: undefined, // 为空
|
||||
exports: undefined, // empty
|
||||
},
|
||||
messageId: 'noExportsCfg',
|
||||
},
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ export const disallowDepRule: Rule.RuleModule = {
|
|||
return;
|
||||
}
|
||||
const [, blockVersion, tips] = definition;
|
||||
// 没有提供 version 参数,判定为不允许所有版本号
|
||||
// No version parameter is provided, and it is determined that all version numbers are not allowed
|
||||
if (typeof blockVersion !== 'string' || blockVersion.length <= 0) {
|
||||
context.report({
|
||||
node,
|
||||
|
|
|
|||
|
|
@ -20,12 +20,12 @@ import reactPlugin from 'eslint-plugin-react';
|
|||
|
||||
const originRule = reactPlugin.rules['jsx-no-leaked-render'];
|
||||
|
||||
// 扩展react/jsx-no-leaked-render。增加判断 「&&」 表达式左边为 boolean 、 null 、 undefined TS类型,则不报错。
|
||||
// Expand the react/jsx-no-leaked-render. If the left side of the "& &" expression is boolean, null, undefined TS type, no error will be reported.
|
||||
export const tsxNoLeakedRender = ruleComposer.filterReports(
|
||||
originRule,
|
||||
problem => {
|
||||
const { parent } = problem.node;
|
||||
// 如果表达式是用于jsx属性,则不需要修复。 如 <Comp prop={ { foo: 1 } && obj } />
|
||||
// If the expression is used for jsx properties, it does not need to be fixed. Such as < Comp prop = {{foo: 1} & & obj}/>
|
||||
if (
|
||||
parent?.type === AST_NODE_TYPES.JSXExpressionContainer &&
|
||||
parent?.parent?.type === AST_NODE_TYPES.JSXAttribute
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ ruleTester.run('prefer-shallow', preferShallow, {
|
|||
'new Foo()',
|
||||
'useShallowedFooStore()',
|
||||
'useFooStore((s) => s.value)',
|
||||
'useFooStore(selector)', // 暂时豁免
|
||||
'useFooStore(selector)', // Temporary exemption
|
||||
'useShallowFooStore(() => ({}))',
|
||||
'useFooStore(useShallow(() => ({})))',
|
||||
'useFooStore(useShallow(() => ([])))',
|
||||
|
|
|
|||
|
|
@ -32,8 +32,8 @@ struct UserDeleteDataMap {
|
|||
We
|
||||
*/
|
||||
enum AvatarMetaType {
|
||||
UNKNOWN = 0, // 没有数据, 错误数据或者系统错误降级
|
||||
RANDOM = 1, // 在修改 or 创建时,用户未指定 name 或者选中推荐的文字时,程序随机选择的头像
|
||||
UNKNOWN = 0, // No data, incorrect data, or system error downgrade
|
||||
RANDOM = 1, // When modifying or creating, the user does not specify a name or select the recommended text, the program randomly selects the avatar
|
||||
}
|
||||
`;
|
||||
|
||||
|
|
|
|||
|
|
@ -46,8 +46,8 @@ enum Gender {
|
|||
}
|
||||
|
||||
// const map<Gender, string> genderMap = {
|
||||
// Gender.Male: '男性',
|
||||
// Gender.Female: '女性',
|
||||
// Gender. Male: 'Male',
|
||||
// Gender. Female: 'Female',
|
||||
// }
|
||||
|
||||
union FuncRequest {
|
||||
|
|
|
|||
|
|
@ -686,7 +686,7 @@ function convertFieldDefinition(
|
|||
if (!isProto3) {
|
||||
requiredness = optional ? 'optional' : 'required';
|
||||
} else if (rule === 'required') {
|
||||
// TODO: 处理 optional 的情况,需要修改 proto-parser
|
||||
// TODO: Handle optional cases, need to modify proto-parser
|
||||
requiredness = 'required';
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ function requiredWithoutCache(src, onError?) {
|
|||
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
||||
const { Module } = require('module');
|
||||
try {
|
||||
// disable 了 require 的缓存,这样可以改变了 mock 数据后,无需重启服务。
|
||||
// Disable the required cache so that you can change the mock data without restarting the service.
|
||||
const originCache = Module._cache;
|
||||
Module._cache = {};
|
||||
// eslint-disable-next-line security/detect-non-literal-require, @typescript-eslint/no-require-imports
|
||||
|
|
|
|||
|
|
@ -186,7 +186,7 @@ export class FilterTypesPlugin {
|
|||
} else if (isIdentifier(fieldType)) {
|
||||
const statement = getStatementById(fieldType, current);
|
||||
if (isEnumDefinition(statement)) {
|
||||
// 强制转位 number
|
||||
// Forced indexing number
|
||||
// @ts-expect-error fixme late
|
||||
fieldType.type = SyntaxType.I32Keyword;
|
||||
let namespace = current.unifyNamespace;
|
||||
|
|
|
|||
|
|
@ -55,15 +55,15 @@ export class MockPlugin implements IPlugin {
|
|||
if (context) {
|
||||
const { fieldDefinition } = context;
|
||||
const fieldName = fieldDefinition.name.value;
|
||||
// 各类 ID
|
||||
// various types of ID
|
||||
if (fieldName.toLocaleUpperCase().endsWith('ID')) {
|
||||
value = String(faker.number.int());
|
||||
}
|
||||
// email 处理
|
||||
// Email processing
|
||||
if (fieldName.includes('Email')) {
|
||||
value = `${faker.person.lastName()}@foo.com`;
|
||||
}
|
||||
// 直接映射值
|
||||
// direct mapping value
|
||||
value = StrMapper[fieldName] || value;
|
||||
}
|
||||
ctx.output = t.stringLiteral(value);
|
||||
|
|
@ -76,20 +76,20 @@ export class MockPlugin implements IPlugin {
|
|||
const { fieldDefinition } = context;
|
||||
const fieldName = fieldDefinition.name.value;
|
||||
const formatName = fieldName.toLocaleUpperCase();
|
||||
// 各类 ID
|
||||
// various types of ID
|
||||
if (formatName.endsWith('ID')) {
|
||||
value = faker.number.int();
|
||||
}
|
||||
// 时间戳
|
||||
// timestamp
|
||||
if (formatName.endsWith('TIME') || formatName.includes('TIMESTAMP')) {
|
||||
value = dayjs(faker.date.anytime()).valueOf();
|
||||
}
|
||||
// 类型状态
|
||||
// type state
|
||||
if (formatName.endsWith('STATUS') || formatName.includes('TYPE')) {
|
||||
value = faker.number.int({ min: 0, max: 1 });
|
||||
}
|
||||
|
||||
// 直接映射值
|
||||
// direct mapping value
|
||||
const mapVal = NumMapper[fieldName];
|
||||
value = typeof mapVal !== 'undefined' ? mapVal : value;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,27 +17,27 @@
|
|||
import { type IPlugin } from '@coze-arch/idl2ts-generator';
|
||||
|
||||
export interface ApiConfig {
|
||||
// idl 入口
|
||||
// IDL entrance
|
||||
entries: Record<string, string>;
|
||||
// idl 根目录
|
||||
// IDL root directory
|
||||
idlRoot: string;
|
||||
// 服务别名
|
||||
// 自定义 api 方法
|
||||
// service alias
|
||||
// Custom API method
|
||||
commonCodePath: string;
|
||||
// api 产物目录
|
||||
// API Product Catalog
|
||||
output: string;
|
||||
// 仓库信息设置
|
||||
// Warehouse information settings
|
||||
repository?: {
|
||||
// 仓库地址
|
||||
// Warehouse address
|
||||
url: string;
|
||||
// clone 到本地的位置
|
||||
// Clone to local location
|
||||
dest: string;
|
||||
};
|
||||
// 插件
|
||||
// plugin
|
||||
plugins?: IPlugin[];
|
||||
// 聚合导出的文件名
|
||||
// aggregate exported filename
|
||||
aggregationExport?: string;
|
||||
// 格式化文件
|
||||
// Format file
|
||||
formatter: (name: string, content: string) => string;
|
||||
idlFetchConfig?: {
|
||||
source: string;
|
||||
|
|
@ -48,6 +48,6 @@ export interface ApiConfig {
|
|||
}
|
||||
|
||||
export interface ApiTypeConfig extends ApiConfig {
|
||||
// 需要过滤的方法
|
||||
// Methods that require filtering
|
||||
filters: Record<string, string[]>;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -163,7 +163,7 @@ export class ClientGenerator {
|
|||
|
||||
private processIdlAst(ast: IParseResultItem) {
|
||||
try {
|
||||
// 新的解析器貌似不是按原来位置排序的,这里要重新排序
|
||||
// The new parser doesn't seem to be sorted by the original position, so it needs to be reordered here.
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
ast.statements.sort((a, b) => a.loc!.start.line - b.loc!.start.line);
|
||||
} catch (error) {
|
||||
|
|
|
|||
|
|
@ -139,14 +139,14 @@ export class AdapterPlugin implements IPlugin {
|
|||
getAnnotation(f.annotations, 'api.converter') === 'atoi_comp_empty'
|
||||
) {
|
||||
if (isInt(f.fieldType)) {
|
||||
// 类型转换为 string
|
||||
// Type conversion to string
|
||||
f.fieldType.type = SyntaxType.StringKeyword;
|
||||
}
|
||||
}
|
||||
// api.converter 对 int 以及 map 类型生效
|
||||
// Api.converter works for int and map types
|
||||
if (getAnnotation(f.annotations, 'api.converter') === 'itoa') {
|
||||
if (isInt(f.fieldType)) {
|
||||
// 类型转换为 string
|
||||
// Type conversion to string
|
||||
f.fieldType.type = SyntaxType.StringKeyword;
|
||||
}
|
||||
if (isMapType(f.fieldType)) {
|
||||
|
|
@ -156,7 +156,7 @@ export class AdapterPlugin implements IPlugin {
|
|||
}
|
||||
}
|
||||
}
|
||||
// item_converter 对 list 类型生效
|
||||
// item_converter for list types
|
||||
if (
|
||||
['atoi_comp_empty', 'itoa'].includes(
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
|
|
@ -168,24 +168,24 @@ export class AdapterPlugin implements IPlugin {
|
|||
}
|
||||
}
|
||||
|
||||
// 收集 decode encode 注解处理
|
||||
// Collection decoding encoding annotation processing
|
||||
if (getTypeFromDynamicJsonAnnotation(f.annotations)) {
|
||||
decodeEncodeFields.push(f.name.value);
|
||||
}
|
||||
// api.json 注解处理
|
||||
// api.json annotation processing
|
||||
const jsonAnnotation = getAnnotation(f.annotations, 'api.json');
|
||||
if (jsonAnnotation) {
|
||||
f.extensionConfig = f.extensionConfig || {};
|
||||
f.extensionConfig.key = jsonAnnotation;
|
||||
}
|
||||
// api.json_string 注解处理
|
||||
// API. json_string annotation handling
|
||||
const jsonStrAnnotation = getAnnotation(
|
||||
f.annotations,
|
||||
'api.json_string',
|
||||
);
|
||||
if (jsonStrAnnotation) {
|
||||
if (isInt(f.fieldType)) {
|
||||
// 类型转换为 string
|
||||
// Type conversion to string
|
||||
f.fieldType.type = SyntaxType.StringKeyword;
|
||||
f.extensionConfig = f.extensionConfig || {};
|
||||
f.extensionConfig.key = jsonStrAnnotation;
|
||||
|
|
|
|||
|
|
@ -403,7 +403,7 @@ export class ClientPlugin implements IPlugin {
|
|||
});
|
||||
const enumAst = t.tsEnumDeclaration(t.identifier(name.value), enumArr);
|
||||
|
||||
// 从后向前删除枚举项,避免索引变化影响
|
||||
// Delete enumeration items from back to front to avoid the impact of index changes
|
||||
enumItemIndexArray
|
||||
.sort((a, b) => b - a)
|
||||
.forEach(index => {
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ import { type Contexts, HOOK } from '../context';
|
|||
|
||||
const MAGIC_COMMENT_KEY = '\n*@magic-comment';
|
||||
|
||||
// 忽略 struct 中的字段
|
||||
// Ignore fields in struct
|
||||
export class CommentFormatPlugin {
|
||||
apply(p: Program<Contexts>) {
|
||||
p.register(after('PARSE_ENTRY'), ctx => {
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ interface IPops {
|
|||
filter: Filter;
|
||||
}
|
||||
|
||||
// 忽略 struct 中的字段
|
||||
// Ignore fields in struct
|
||||
export class IgnoreStructFiledPlugin {
|
||||
private filter: Filter;
|
||||
constructor({ filter }: IPops) {
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ export class MetaPlugin implements IPlugin {
|
|||
ctx => {
|
||||
const node = ctx.node as ServiceDefinition;
|
||||
node.functions.forEach(fun => {
|
||||
// 过滤非泛化接口
|
||||
// Filtering non-generalized interfaces
|
||||
if (!fun.extensionConfig?.method) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -103,7 +103,7 @@ export class MetaPlugin implements IPlugin {
|
|||
schemaRoot: getSchemaRootByPath(ast.idlPath, this.options.idlRoot),
|
||||
service,
|
||||
} as IMeta;
|
||||
// 不是 json 时,需要加上 serializer 标识
|
||||
// When not json, you need to add the serializer flag.
|
||||
if (extensionConfig?.serializer && extensionConfig?.serializer !== 'json') {
|
||||
res.serializer = extensionConfig?.serializer;
|
||||
}
|
||||
|
|
@ -117,7 +117,7 @@ export class MetaPlugin implements IPlugin {
|
|||
if (isStructDefinition(statement)) {
|
||||
const wholeBody = statement.fields.find(isFullBody);
|
||||
if (wholeBody) {
|
||||
// 处理 api.body="." 以及 api.full_body=''
|
||||
// Handle api.body = "." and api.full_body = "
|
||||
return `${id.value}['${getFieldsAlias(wholeBody)}']`;
|
||||
} else {
|
||||
return id.value;
|
||||
|
|
@ -184,7 +184,7 @@ export class MetaPlugin implements IPlugin {
|
|||
}
|
||||
});
|
||||
}
|
||||
// 如果没有指定,根据method默认指定为query 或者 body
|
||||
// If not specified, it is specified as query or body by default according to method.
|
||||
if (!specificPositionFiled.has(alias)) {
|
||||
const filedMapping = mapping[defaultPosition];
|
||||
mapping[defaultPosition] = filedMapping
|
||||
|
|
|
|||
|
|
@ -110,7 +110,7 @@ export class MockTransformerPlugin implements IPlugin {
|
|||
nextOrder[name] = index;
|
||||
}
|
||||
});
|
||||
// 按照 mock 文件中的顺序优先排序
|
||||
// Prioritize in order in the mock file
|
||||
const getOrder = (name: string) =>
|
||||
typeof mockVarOrder[name] !== 'undefined'
|
||||
? mockVarOrder[name]
|
||||
|
|
@ -210,7 +210,7 @@ export class MockTransformerPlugin implements IPlugin {
|
|||
if (isStructDefinition(statement)) {
|
||||
const wholeBody = statement.fields.find(isFullBody);
|
||||
if (wholeBody) {
|
||||
// 处理 api.body="."
|
||||
// Processing api.body = "."
|
||||
const { annotations } = wholeBody;
|
||||
if (hasDynamicJsonAnnotation(annotations)) {
|
||||
return '{}';
|
||||
|
|
@ -273,7 +273,7 @@ export class MockTransformerPlugin implements IPlugin {
|
|||
if (!fieldNames.has(fieldName)) {
|
||||
return;
|
||||
}
|
||||
// 没有的,需要重新生成
|
||||
// No, it needs to be regenerated.
|
||||
newPros.push(
|
||||
t.objectProperty(
|
||||
fieldName.includes('-')
|
||||
|
|
@ -351,11 +351,11 @@ export class MockTransformerPlugin implements IPlugin {
|
|||
const { valueType } = fieldType;
|
||||
output = t.arrayExpression([this.processValue(valueType)]);
|
||||
} else if (isSetType(fieldType)) {
|
||||
// set 处理成array校验
|
||||
// Set to array validation
|
||||
const { valueType } = fieldType;
|
||||
output = t.arrayExpression([this.processValue(valueType)]);
|
||||
} else if (isIdentifier(fieldType)) {
|
||||
// 引用类型
|
||||
// reference type
|
||||
const { refName, namespace } = parseIdFiledType(fieldType);
|
||||
if (!namespace) {
|
||||
output = t.callExpression(t.identifier(refName), []);
|
||||
|
|
@ -375,7 +375,7 @@ export class MockTransformerPlugin implements IPlugin {
|
|||
throw new Error(`can not process fieldType : ${fieldType.type}`);
|
||||
}
|
||||
private processConst(constVal: ConstValue) {
|
||||
// 暂时统一处理成0
|
||||
// Temporarily unified processing to 0
|
||||
if (isStringLiteral(constVal)) {
|
||||
return t.stringLiteral(constVal.value);
|
||||
}
|
||||
|
|
@ -410,11 +410,11 @@ export class MockTransformerPlugin implements IPlugin {
|
|||
const comment = { type: 'CommentLine', value: commentValues } as any;
|
||||
const target = this.findTarget(name.value, ctx);
|
||||
if (target) {
|
||||
// 需要更新注释
|
||||
// Comments need to be updated
|
||||
// target.trailingComments = [comment];
|
||||
return;
|
||||
}
|
||||
// 枚举类型统一处理成常量
|
||||
// Enumeration types are uniformly processed into constants
|
||||
const builder = template(`var ${name.value}= () => %%value%% `);
|
||||
const node = builder({
|
||||
value: t.numericLiteral(values[0] || 0),
|
||||
|
|
@ -437,7 +437,7 @@ export class MockTransformerPlugin implements IPlugin {
|
|||
// const variableDeclaration = t.addComment(
|
||||
// ,
|
||||
// 'leading',
|
||||
// '暂时对const默认处理为0,如有需要请自行重新赋值'
|
||||
// 'Temporarily, the default processing for const is 0, please reassign it yourself if necessary '
|
||||
// );
|
||||
return node;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ import { type Options } from '../types';
|
|||
import { type Contexts, HOOK } from '../context';
|
||||
|
||||
/**
|
||||
* 提供统一 api 入口
|
||||
* Provide unified API entry
|
||||
*/
|
||||
export class PkgEntryPlugin implements IPlugin {
|
||||
private options: Options;
|
||||
|
|
@ -52,7 +52,7 @@ export class PkgEntryPlugin implements IPlugin {
|
|||
);
|
||||
this.funcs.set(
|
||||
relativePath,
|
||||
// 只支持单 service
|
||||
// Only single service supported
|
||||
meta[0].service,
|
||||
);
|
||||
return ctx;
|
||||
|
|
|
|||
|
|
@ -223,7 +223,7 @@ export class SchemaPlugin implements IPlugin {
|
|||
};
|
||||
return schema;
|
||||
} else if (isSetType(fieldType)) {
|
||||
// set 处理成array校验
|
||||
// Set to array validation
|
||||
const { valueType } = fieldType;
|
||||
const schema: ListType = {
|
||||
type: 'array',
|
||||
|
|
@ -231,7 +231,7 @@ export class SchemaPlugin implements IPlugin {
|
|||
};
|
||||
return schema;
|
||||
} else if (isIdentifier(fieldType)) {
|
||||
// 引用类型
|
||||
// reference type
|
||||
const { refName, namespace } = parseIdFiledType(fieldType);
|
||||
if (!namespace) {
|
||||
const schema: RefType = { $ref: `#/definitions/${refName}` };
|
||||
|
|
@ -249,7 +249,7 @@ export class SchemaPlugin implements IPlugin {
|
|||
throw new Error(`can not process fieldType : ${fieldType.type}`);
|
||||
}
|
||||
private processConst(constVal: ConstValue) {
|
||||
// 暂时统一处理成0
|
||||
// Temporarily unified processing to 0
|
||||
const schema = {} as ConstType;
|
||||
if (isStringLiteral(constVal)) {
|
||||
schema.const = constVal.value;
|
||||
|
|
|
|||
|
|
@ -29,11 +29,11 @@ export interface Options {
|
|||
genMock: boolean;
|
||||
genClient: boolean;
|
||||
entryName?: string;
|
||||
// createAPI 所在文件路径
|
||||
// createAPI file path
|
||||
commonCodePath?: string;
|
||||
// decode encode 会丢失类型,这里提供一种方式,业务手动补充上对应的类型
|
||||
// Decoding encoding will lose the type, here provides a way to manually add the corresponding type
|
||||
patchTypesOutput?: string;
|
||||
// patchTypesOutput 的别名,patch type 需要使用额外的 pkg 组织时需要提供
|
||||
// PatchTypesOutput alias, patch type needs to be provided when using additional pkg organization
|
||||
patchTypesAliasOutput?: string;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -42,11 +42,11 @@ export interface IMeta {
|
|||
type Fields = string[];
|
||||
|
||||
export interface IHttpRpcMapping {
|
||||
path?: Fields; // path参数
|
||||
query?: Fields; // query参数
|
||||
body?: Fields; // body 参数
|
||||
header?: Fields; // header 参数
|
||||
status_code?: Fields; // http状态码
|
||||
path?: Fields; // path parameter
|
||||
query?: Fields; // query parameters
|
||||
body?: Fields; // Body parameters
|
||||
header?: Fields; // header parameter
|
||||
status_code?: Fields; // HTTP status code
|
||||
cookie?: Fields; // cookie
|
||||
entire_body?: Fields;
|
||||
raw_body?: Fields;
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ export function formatCode(code: string, root = '.') {
|
|||
printWidth: 120,
|
||||
singleQuote: true,
|
||||
};
|
||||
const file = path.resolve(process.cwd(), root, './for-prettier-bug'); // 这里一定要加多一级目录
|
||||
const file = path.resolve(process.cwd(), root, './for-prettier-bug'); // Be sure to add an extra level catalog here.
|
||||
const config = prettier.resolveConfig(file, { editorconfig: true });
|
||||
return prettier.format(code, {
|
||||
...(config || defaultConfig),
|
||||
|
|
@ -166,7 +166,7 @@ export function parseId(id: string) {
|
|||
|
||||
export function uniformNs(ns: string) {
|
||||
if (ReservedKeyWord.includes(ns)) {
|
||||
// 命中保留字,处理为下划线开头
|
||||
// Hit the reserved word, treated as an underscore
|
||||
return `_${ns}`;
|
||||
}
|
||||
return ns.replace(/\./g, '_');
|
||||
|
|
@ -182,7 +182,7 @@ export function getValuesFromEnum(params: h.EnumDefinition) {
|
|||
if (h.isIntegerLiteral(initializer.value)) {
|
||||
currentVal = Number(initializer.value.value);
|
||||
} else if (h.isHexLiteral(initializer.value)) {
|
||||
// 16进制
|
||||
// hexadecimal
|
||||
currentVal = Number(initializer.value.value);
|
||||
}
|
||||
enumArr.push(currentVal);
|
||||
|
|
@ -322,8 +322,8 @@ export function hasDynamicJsonAnnotation(annotations?: h.Annotations) {
|
|||
}
|
||||
|
||||
/**
|
||||
* 从 api.(request|response).converter 中解析出前端与网关之间的真实类型,
|
||||
* 能搞出这两个注解来,这个协议着实恶心😭
|
||||
* Parse the real type between the front end and the gateway from api. (request | response).converter.
|
||||
* To be able to come up with these two annotations, this protocol is disgusting😭
|
||||
* @param annotations
|
||||
* @returns
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ export class Program<C extends Ctxs = any> {
|
|||
} = {};
|
||||
|
||||
/**
|
||||
* 加载插件
|
||||
* Load plugin
|
||||
* @param plugins
|
||||
*/
|
||||
loadPlugins(plugins: IPlugin[]) {
|
||||
|
|
@ -51,10 +51,10 @@ export class Program<C extends Ctxs = any> {
|
|||
}
|
||||
}
|
||||
/**
|
||||
* 注册钩子
|
||||
* @param event 事件名称
|
||||
* @param handler 钩子
|
||||
* @param priority 优先级,数值越小,优先级越高
|
||||
* registration hook
|
||||
* @param event name
|
||||
* @param handler hook
|
||||
* @Param priority, the smaller the value, the higher the priority
|
||||
*/
|
||||
register<
|
||||
K extends keyof C,
|
||||
|
|
@ -87,7 +87,7 @@ export class Program<C extends Ctxs = any> {
|
|||
}
|
||||
}
|
||||
/**
|
||||
* 触发事件
|
||||
* trigger event
|
||||
* @param event
|
||||
* @param args
|
||||
* @returns
|
||||
|
|
|
|||
|
|
@ -20,20 +20,20 @@ import type { IMeta, CustomAPIMeta } from './types';
|
|||
export interface ApiLike<T, K, O = unknown, B extends boolean = false> {
|
||||
(req: T, option?: O extends object ? IOptions & O : IOptions): Promise<K>;
|
||||
meta: IMeta;
|
||||
/** fork 一份实例,该实例具有可中止请求的能力 */
|
||||
/** Fork an instance that has the ability to abort requests */
|
||||
withAbort: () => CancelAbleApi<T, K, O, B>;
|
||||
}
|
||||
|
||||
export interface CancelAbleApi<T, K, O = unknown, B extends boolean = false>
|
||||
extends ApiLike<T, K, O, B> {
|
||||
// 中止请求
|
||||
// abort request
|
||||
abort: () => void;
|
||||
// 是否是取消
|
||||
// Is it cancelled?
|
||||
isAborted: () => boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* 自定义构建 api 方法
|
||||
* Custom build API method
|
||||
* @param meta
|
||||
* @param cancelable
|
||||
* @param useCustom
|
||||
|
|
@ -56,7 +56,7 @@ export function createAPI<T extends {}, K, O = unknown, B extends boolean = fals
|
|||
|
||||
option = { ...(option || {}), ...customOption };
|
||||
|
||||
// 这里可以使用传进来的 req 作为默认映射,减少需要在 customAPI 中,需要手动绑定的情况
|
||||
// Here, you can use the incoming req as the default mapping to reduce the need for manual binding in the customAPI
|
||||
if (useCustom) {
|
||||
const mappingKeys: string[] = Object.keys(meta.reqMapping)
|
||||
.map(key => meta.reqMapping[key])
|
||||
|
|
@ -98,12 +98,12 @@ export function createAPI<T extends {}, K, O = unknown, B extends boolean = fals
|
|||
|
||||
function abort() {
|
||||
/**
|
||||
* 这里加上 pending 状态的原因是,abortController.signal 的状态值只受控于 abortController.abort() 方法;
|
||||
* 不管请求是否完成或者异常,只要调用 abortController.abort(), abortController.signal.aborted 必定为 true,
|
||||
* 这样不好判断请求是否真 aborted;
|
||||
* The reason for adding the pending state here is that the state value of abortController.signal is only controlled by the abortController.abort () method;
|
||||
* No matter whether the request is completed or abnormal, as long as abortController.abort () is called, abortController.signal.aborted must be true.
|
||||
* This makes it difficult to determine whether the request is really aborted.
|
||||
*
|
||||
* 这里改为,只有在请求 pending 的情况下,可执行 abort(),
|
||||
* isAborted === true 时,请求异常必定是因为手动 abort 导致的
|
||||
* This is changed to abort () only if the request is pending.
|
||||
* When isAborted === true, the request exception must be caused by manual abort
|
||||
*/
|
||||
if (pending === true && cancelable && abortController) {
|
||||
abortController.abort();
|
||||
|
|
@ -128,7 +128,7 @@ export function createAPI<T extends {}, K, O = unknown, B extends boolean = fals
|
|||
}
|
||||
|
||||
/**
|
||||
* 一些非泛化的接口,可以使用改方法构建,方便统一管理接口
|
||||
* Some non-generalized interfaces can be built using modified methods to facilitate unified management of interfaces
|
||||
* @param customAPIMeta
|
||||
* @param cancelable
|
||||
* @returns
|
||||
|
|
|
|||
|
|
@ -30,11 +30,11 @@ export interface IMeta {
|
|||
type Fields = string[];
|
||||
|
||||
export interface IHttpRpcMapping {
|
||||
path?: Fields; // path参数
|
||||
query?: Fields; // query参数
|
||||
body?: Fields; // body 参数
|
||||
header?: Fields; // header 参数
|
||||
status_code?: Fields; // http状态码
|
||||
path?: Fields; // path parameter
|
||||
query?: Fields; // query parameters
|
||||
body?: Fields; // Body parameters
|
||||
header?: Fields; // header parameter
|
||||
status_code?: Fields; // HTTP status code
|
||||
cookie?: Fields; // cookie
|
||||
entire_body?: Fields;
|
||||
raw_body?: Fields;
|
||||
|
|
|
|||
|
|
@ -27,22 +27,22 @@ export interface ServiceConfig {
|
|||
} & Omit<IdlConfig, 'clientFactory'>;
|
||||
}
|
||||
export interface IdlConfig {
|
||||
// client 工厂方法,要求返回一个 fetchClient 函数,使用 meta 总的信息,可实现灵活的 client 配置
|
||||
// The client factory method requires a fetchClient function to be returned, which uses the meta total information to achieve flexible client configuration
|
||||
clientFactory?: (
|
||||
meta: IMeta,
|
||||
) => (uri: string, init: RequestInit, opt: any) => any;
|
||||
// uri 前缀,如果 client 中设置了,这里可以不设置
|
||||
// URI prefix, if set in client, you can leave it unset here
|
||||
uriPrefix?: string;
|
||||
getParams?: (key: string) => string;
|
||||
// 服务级别的配置
|
||||
// Service level configuration
|
||||
services?: ServiceConfig;
|
||||
// 开发时,如果本地校验失败,这里可回调,通常是弹 toast
|
||||
// During development, if the local verification fails, it can be called back here, usually by playing toast.
|
||||
onVerifyReqError?: (message: string, ctx: any) => void;
|
||||
}
|
||||
|
||||
export interface IOptions {
|
||||
config?: IdlConfig;
|
||||
// 透传 request options 的选项
|
||||
// Passthrough request options
|
||||
requestOptions?: Record<string, any>;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
|
@ -52,7 +52,7 @@ export interface PathPrams<T> {
|
|||
}
|
||||
|
||||
export function getConfig(service: string, method: string): IdlConfig {
|
||||
// 手动注册的配置优先级比全局变量高
|
||||
// Manually registered configuration takes precedence over global variables
|
||||
let config: IdlConfig | undefined = configCenter.getConfig(service);
|
||||
if (!config) {
|
||||
config = {};
|
||||
|
|
@ -137,7 +137,7 @@ export function normalizeRequest(
|
|||
);
|
||||
const { uriPrefix = '', clientFactory } = config;
|
||||
if (!clientFactory) {
|
||||
// todo 这里考虑给个默认的 client,防止某些公共 package 在一些异常情况下使用
|
||||
// Todo here considers giving a default client to prevent some public packages from being used in some abnormal cases
|
||||
throw new Error('Lack of clientFactory config');
|
||||
}
|
||||
let uri = uriPrefix + apiUri;
|
||||
|
|
@ -149,11 +149,11 @@ export function normalizeRequest(
|
|||
: 'application/json';
|
||||
if (option?.requestOptions?.headers) {
|
||||
headers = { ...headers, ...option.requestOptions.headers };
|
||||
// 合并了 header,可删除
|
||||
// Merged headers, can be deleted
|
||||
delete option.requestOptions.headers;
|
||||
}
|
||||
if (meta.reqMapping.query && meta.reqMapping.query.length > 0) {
|
||||
// 这里默认 skipNulls,网关后端需要忽略 null
|
||||
// The default here is skipNulls, and the gateway backend needs to ignore null.
|
||||
uri = `${uri}?${qs.stringify(getValue(req, meta.reqMapping.query), {
|
||||
skipNulls: true,
|
||||
arrayFormat: 'comma',
|
||||
|
|
@ -168,7 +168,7 @@ export function normalizeRequest(
|
|||
|
||||
if (meta.reqMapping.entire_body && meta.reqMapping.entire_body.length > 0) {
|
||||
if (meta.reqMapping.entire_body.length === 1) {
|
||||
// 默认处理为 json ,如有其他场景需要支持,后需要再支持
|
||||
// The default processing is json. If there are other scenarios that need to be supported, they need to be supported later.
|
||||
requestOption.body = req[meta.reqMapping.entire_body[0]];
|
||||
} else {
|
||||
throw new Error('idl invalid entire_body should be only one filed');
|
||||
|
|
@ -203,7 +203,7 @@ export function normalizeRequest(
|
|||
};
|
||||
}
|
||||
|
||||
// 旧版的 ferry 中,即使 idl 没有声明body,也需要加一个 空的 body
|
||||
// In the old version of ferry, even if idl does not declare body, you need to add an empty body.
|
||||
if (
|
||||
!requestOption.body &&
|
||||
['POST', 'PUT', 'PATCH'].includes(
|
||||
|
|
|
|||
|
|
@ -89,17 +89,17 @@ describe('PkgRootWebpackPlugin', () => {
|
|||
|
||||
new PkgRootWebpackPlugin(customOptions);
|
||||
|
||||
// 注意:Object.assign 中后面的对象会覆盖前面的对象,所以默认配置会覆盖用户配置
|
||||
// Note: Subsequent objects in Object.assign overwrite the preceding objects, so the default configuration overrides the user configuration
|
||||
expect(OriginPkgRootWebpackPlugin).toHaveBeenCalledWith({
|
||||
customProp: 'customValue',
|
||||
root: '@', // 被默认值覆盖
|
||||
root: '@', // Overwritten by default
|
||||
packagesDirs: [
|
||||
'packages/project1',
|
||||
'packages/project2',
|
||||
'apps/app1',
|
||||
'apps/app2',
|
||||
],
|
||||
excludeFolders: [], // 被默认值覆盖
|
||||
excludeFolders: [], // Overwritten by default
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -110,9 +110,9 @@ describe('PkgRootWebpackPlugin', () => {
|
|||
|
||||
new PkgRootWebpackPlugin(customOptions);
|
||||
|
||||
// Object.assign 的行为:后面的对象会覆盖前面的对象属性
|
||||
// Object.assign behavior: subsequent objects overwrite previous object properties
|
||||
expect(OriginPkgRootWebpackPlugin).toHaveBeenCalledWith({
|
||||
root: '@', // 被默认值覆盖
|
||||
root: '@', // Overwritten by default
|
||||
packagesDirs: [
|
||||
'packages/project1',
|
||||
'packages/project2',
|
||||
|
|
@ -139,7 +139,7 @@ describe('PkgRootWebpackPlugin', () => {
|
|||
});
|
||||
|
||||
it('验证所有导出都正确', () => {
|
||||
// 验证模块导出了正确的类和默认导出
|
||||
// Verify that the module exported the correct class and the default export
|
||||
expect(PkgRootWebpackPlugin).toBeDefined();
|
||||
expect(typeof PkgRootWebpackPlugin).toBe('function');
|
||||
});
|
||||
|
|
@ -147,7 +147,7 @@ describe('PkgRootWebpackPlugin', () => {
|
|||
it('应该正确处理 Rush 配置中的项目文件夹', () => {
|
||||
new PkgRootWebpackPlugin();
|
||||
|
||||
// 验证传递给父类的 packagesDirs 包含所有项目文件夹
|
||||
// Verify that the packagesDirs passed to the parent class contain all project folders
|
||||
const call = (OriginPkgRootWebpackPlugin as any).mock.calls[0];
|
||||
const options = call[0];
|
||||
|
||||
|
|
@ -160,10 +160,10 @@ describe('PkgRootWebpackPlugin', () => {
|
|||
});
|
||||
|
||||
it('测试插件基本功能正常工作', () => {
|
||||
// 这个测试验证插件能正常实例化并调用父类构造函数
|
||||
// This test verifies that the plugin can instantiate and call the parent class constructor normally
|
||||
new PkgRootWebpackPlugin();
|
||||
|
||||
// 验证确实调用了父类构造函数
|
||||
// Verify that the parent class constructor is indeed called
|
||||
expect(OriginPkgRootWebpackPlugin).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ class PkgRootWebpackPlugin extends pkg_root_webpack_plugin_origin_1.default {
|
|||
const mergedOptions = Object.assign({}, options || {}, {
|
||||
root: '@',
|
||||
packagesDirs: rushJsonPackagesDir,
|
||||
// 排除apps/*,减少处理时间
|
||||
// Exclude apps/* to reduce processing time
|
||||
excludeFolders: [],
|
||||
});
|
||||
super(mergedOptions);
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ class PkgRootWebpackPlugin extends OriginPkgRootWebpackPlugin {
|
|||
const mergedOptions = Object.assign({}, options || {}, {
|
||||
root: '@',
|
||||
packagesDirs: rushJsonPackagesDir,
|
||||
// 排除apps/*,减少处理时间
|
||||
// Exclude apps/* to reduce processing time
|
||||
excludeFolders: [],
|
||||
});
|
||||
super(mergedOptions);
|
||||
|
|
|
|||
|
|
@ -1,79 +1,79 @@
|
|||
# @coze-arch/monorepo-kits
|
||||
|
||||
## 功能概述
|
||||
/* Function Overview */
|
||||
|
||||
`@coze-arch/monorepo-kits` 是一个用于管理 monorepo 项目的工具包,提供了基于 Rush 框架的项目查找、依赖分析和配置管理功能。
|
||||
/* "@Coze-arch/monorepo-kits" is a toolkit for managing monorepo projects, providing project lookup, dependency analysis, and configuration management capabilities based on the Rush framework. */
|
||||
|
||||
## 主要功能模块
|
||||
/* Main Functional Modules */
|
||||
|
||||
### 1. 子包管理 (sub-packages.ts)
|
||||
/* ###1. Subpackage management (sub-packages.ts) */
|
||||
|
||||
#### lookupSubPackages(packageName: string): string[]
|
||||
- **功能**: 递归查找指定包的所有子依赖包
|
||||
- **特性**: 使用缓存机制避免重复计算
|
||||
- **返回**: 所有依赖包的名称数组(去重后)
|
||||
/* - ** Function **: Recursively find all child dependencies of the specified package */
|
||||
/* - ** Features **: Use caching mechanism to avoid double counting */
|
||||
/* - ** Returns **: Array of names of all dependent packages (after deduplicate) */
|
||||
|
||||
#### getPackageLocation(packageName: string): string
|
||||
- **功能**: 获取指定包的文件系统路径
|
||||
- **返回**: 包的项目文件夹路径
|
||||
/* - ** Function **: Get the file system path of the specified package */
|
||||
/* - ** return **: the project folder path of the package */
|
||||
|
||||
#### getPackageJson(packageName: string): RushConfigurationProject['packageJson']
|
||||
- **功能**: 获取指定包的 package.json 配置信息
|
||||
- **返回**: 包的 package.json 对象
|
||||
/* - ** Function **: Get the package.json configuration information of the specified package */
|
||||
/* - ** returns **: package's package.json object */
|
||||
|
||||
### 2. Rush 配置管理 (rush-config.ts)
|
||||
/* ###2. Rush configuration management (rush-config.ts) */
|
||||
|
||||
#### getRushConfiguration(): RushConfiguration
|
||||
- **功能**: 获取 Rush 配置实例
|
||||
- **特性**: 单例模式,首次调用时从默认位置加载配置,后续调用复用实例
|
||||
- **返回**: RushConfiguration 对象
|
||||
/* - ** Features **: Get Rush Configuration Instance */
|
||||
/* - ** Features **: Singleton mode, first call loads configuration from default location, subsequent calls reuse instance */
|
||||
/* - ** returns **: RushConfiguration object */
|
||||
|
||||
### 3. 项目查找 (lookup.ts)
|
||||
/* ###3. Project lookup (lookup.ts) */
|
||||
|
||||
#### lookupTo(to: string): string[]
|
||||
- **功能**: 查找指定包的直接依赖项
|
||||
- **参数**: 目标包名称
|
||||
- **返回**: 依赖包名称数组
|
||||
/* - ** Features **: Find direct dependencies of a specified package */
|
||||
/* - ** Parameter **: Target package name */
|
||||
/* - ** Returns **: Array of dependency package names */
|
||||
|
||||
#### lookupFrom(from: string): void
|
||||
- **功能**: 查找从指定包出发的相关信息(当前实现不完整)
|
||||
- **参数**: 源包名称
|
||||
/* - ** Features **: Find information about outgoing from a specified package (current implementation is incomplete) */
|
||||
/* - ** parameter **: source package name */
|
||||
|
||||
#### lookupOnly(packageName: string): RushConfigurationProject
|
||||
- **功能**: 查找并返回指定包的项目配置对象
|
||||
- **参数**: 包名称
|
||||
- **返回**: 完整的项目配置对象
|
||||
/* - ** Features **: Find and return the project configuration object of the specified package */
|
||||
/* - ** parameter **: package name */
|
||||
/* - ** Return **: complete project configuration object */
|
||||
|
||||
## 依赖关系
|
||||
/* ##dependencies */
|
||||
|
||||
- **主要依赖**: `@rushstack/rush-sdk@5.100.2`
|
||||
- **开发依赖**: 包含 ESLint、TypeScript、Vitest 等工具链
|
||||
/* - ** Major dependencies **: '@rushstack/rush-sdk@5.100.2' */
|
||||
/* - ** Development dependencies **: Includes ESLint, TypeScript, Vitest and other toolchains */
|
||||
|
||||
## 使用场景
|
||||
/* ##usage scenario */
|
||||
|
||||
1. **依赖分析**: 分析 monorepo 中包之间的依赖关系
|
||||
2. **路径解析**: 获取包在文件系统中的实际位置
|
||||
3. **配置查询**: 查询包的配置信息和元数据
|
||||
4. **自动化工具**: 为构建脚本、部署工具等提供 monorepo 项目信息
|
||||
/* 1. ** Dependency Analysis **: Analyze the dependencies between packages in Monorepo */
|
||||
/* 2. ** Path parsing **: Get the actual location of the package in the file system */
|
||||
/* 3. ** Configuration query **: Query the configuration information and metadata of the package */
|
||||
/* 4. ** Automation Tools **: Provide monorepo project information for build scripts, deployment tools, etc */
|
||||
|
||||
## 架构特点
|
||||
/* ##Architecture Features */
|
||||
|
||||
- **缓存优化**: 对递归依赖查找进行缓存,提高性能
|
||||
- **错误处理**: 包含完善的包不存在异常处理
|
||||
- **单例模式**: Rush 配置采用单例模式,避免重复加载
|
||||
- **类型安全**: 基于 TypeScript,提供完整的类型定义
|
||||
/* - ** Cache optimization **: Cache recursive dependency lookups to improve performance */
|
||||
/* - ** Error Handling **: Includes perfect package without exception handling */
|
||||
/* - ** Singleton mode **: Rush configuration adopts singleton mode to avoid repeated loading */
|
||||
/* Type safety: Based on TypeScript, complete type definition is provided */
|
||||
|
||||
## 代码结构
|
||||
/* ##Code structure */
|
||||
|
||||
```
|
||||
src/
|
||||
├── index.ts # 主入口文件,导出所有公共 API
|
||||
├── sub-packages.ts # 子包管理和依赖查找功能
|
||||
├── rush-config.ts # Rush 配置管理
|
||||
└── lookup.ts # 项目查找相关功能
|
||||
/* < unk > ─ index.ts #Main entry file, export all public APIs */
|
||||
/* < unk > ─ Sub-packages.ts #Subpackage management and dependency lookup function */
|
||||
/* 🥰 ─ rush-config.ts #Rush configuration management */
|
||||
/* 🥰 ─ ─ lookup.ts #Project lookup related functions */
|
||||
```
|
||||
|
||||
## API 导出
|
||||
/* ##API export */
|
||||
|
||||
```typescript
|
||||
export {
|
||||
|
|
@ -87,4 +87,4 @@ export { getRushConfiguration } from './rush-config';
|
|||
export { lookupTo, lookupFrom, lookupOnly } from './lookup';
|
||||
```
|
||||
|
||||
这个工具包为 monorepo 环境下的包管理、依赖分析和自动化工具开发提供了基础支持。
|
||||
/* This toolkit provides fundamental support for package management, dependency analysis, and automated tool development in Monorepo environments. */
|
||||
|
|
|
|||
|
|
@ -80,5 +80,5 @@ const logger = new Logger();
|
|||
|
||||
export { logger };
|
||||
|
||||
/** @deprecated 该使用方式已废弃,请使用`import { logger } from '@coze-arch/rush-logger' */
|
||||
/** @Deprecated This usage is deprecated, please use'import {logger} from '@code-arch/rush-logger' */
|
||||
export default logger;
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ import { I18n } from '@coze-arch/i18n';
|
|||
import { UIModal } from '@coze-arch/bot-semi';
|
||||
import { useResetLocationState } from '@coze-arch/bot-hooks';
|
||||
|
||||
// 三方授权失败,callback至发布页需要显式阻塞弹窗
|
||||
// Tripartite authorization failed, callback to the release page needs to explicitly block the pop-up window
|
||||
export const useAuthFail = () => {
|
||||
const { state } = useLocation();
|
||||
const { authFailMessage = '', authStatus } = (state ??
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ const DEFAULT_BOT_INFO: PublisherBotInfo = {
|
|||
prompt: '',
|
||||
};
|
||||
|
||||
// 获取plugin收费插件信息
|
||||
// Get plugin charging plugin information
|
||||
const getPricingRules: (
|
||||
pluginApiDetailMap?: Record<string | number, PluginAPIDetal>,
|
||||
) => Promise<PluginPricingRule[] | undefined> = async pluginApiDetailMap => {
|
||||
|
|
@ -58,7 +58,7 @@ const getPricingRules: (
|
|||
return pricing_rules;
|
||||
};
|
||||
|
||||
// 是否有plugin
|
||||
// Is there a plugin?
|
||||
const hasPluginApi: (
|
||||
pluginApiDetailMap?: Record<string | number, PluginAPIDetal>,
|
||||
) => boolean = pluginApiDetailMap =>
|
||||
|
|
@ -113,7 +113,7 @@ export const useGetPublisherInitInfo: () => {
|
|||
bot_option_data,
|
||||
} = botInfoResp?.data ?? {};
|
||||
|
||||
// 获取plugin扣费信息
|
||||
// Get plugin deduction information
|
||||
let pluginPricingRules: Array<PluginPricingRule> = [];
|
||||
if (
|
||||
hasPluginApi(bot_option_data?.plugin_api_detail_map) &&
|
||||
|
|
|
|||
|
|
@ -126,7 +126,7 @@ export const AgentPublishPage = () => {
|
|||
const publishBtn = (
|
||||
<UIButton
|
||||
theme="solid"
|
||||
//解决异步请求botInfo未返回时可以点击publish产生的错误
|
||||
//Resolve the error caused by clicking publish when the asynchronous request botInfo is not returned
|
||||
disabled={Boolean(publishDisabled) || !botInfo.name}
|
||||
loading={publishLoading}
|
||||
onClick={handlePublish}
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ import { PublishResultArea } from './component/publish-result-area';
|
|||
import styles from '../index.module.less';
|
||||
|
||||
interface PublishResultProps {
|
||||
// 隐藏Banner
|
||||
// Hidden Banner
|
||||
hiddenBanner?: boolean;
|
||||
publishResult?: PublishResultInfo;
|
||||
}
|
||||
|
|
@ -212,7 +212,7 @@ export const PublishResult = ({
|
|||
? `⚠️ ${I18n.t('publish_result_all_failed')}`
|
||||
: `🎉 ${I18n.t('publish_success')}`}
|
||||
</div>
|
||||
{/* 开源版暂不支持该功能 */}
|
||||
{/* The open-source version does not currently support this function */}
|
||||
{IS_OVERSEA && !publishResult?.monetizeConfigSuccess ? (
|
||||
<div className="mt-[12px] flex items-center gap-[8px] coz-fg-primary">
|
||||
<IconCozInfoCircleFill className="coz-fg-hglt-yellow" />
|
||||
|
|
@ -221,7 +221,7 @@ export const PublishResult = ({
|
|||
</span>
|
||||
</div>
|
||||
) : null}
|
||||
{/* 开源版暂不支持该功能 */}
|
||||
{/* The open-source version does not currently support this function */}
|
||||
{FLAGS['bot.studio.publish_management'] && !IS_OPEN_SOURCE ? (
|
||||
<div className="coz-fg-dim text-[12px]">
|
||||
{I18n.t('release_management_detail1', {
|
||||
|
|
|
|||
|
|
@ -100,8 +100,8 @@ export const PublishConnectorAction: React.FC<ActionColumnProps> = ({
|
|||
|
||||
const action = (() => {
|
||||
switch (record.bind_type) {
|
||||
case BindType.KvBind: //仅绑定
|
||||
case BindType.KvAuthBind: //绑定+授权,取消绑定后自动取消授权
|
||||
case BindType.KvBind: //bind only
|
||||
case BindType.KvAuthBind: //Bind + authorization, automatically cancel the authorization after unbinding
|
||||
return (
|
||||
<KvBindButton
|
||||
record={record}
|
||||
|
|
@ -181,7 +181,7 @@ export const ConfigStatusColumn: React.FC<ActionColumnProps> = props => {
|
|||
tagProps={{
|
||||
color,
|
||||
style: { margin: 0 },
|
||||
// 覆盖原来的orange-tag
|
||||
// Overwrite the original orange-tag.
|
||||
className: styles['common-tag'],
|
||||
}}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -96,7 +96,7 @@ export const StoreBind: React.FC<StoreBindProps> = ({
|
|||
setSourceConfig(true);
|
||||
} else {
|
||||
setSourceConfig(false);
|
||||
// 兜底逻辑:如果出错,或不在白名单中,则自动更改为“私有配置”发布
|
||||
// Fallback logic: if there is an error, or it is not in the whitelist, it is automatically changed to "private configuration" publishing
|
||||
handleSelect('open_source', BotSubmitStatus.Private);
|
||||
}
|
||||
},
|
||||
|
|
@ -107,7 +107,7 @@ export const StoreBind: React.FC<StoreBindProps> = ({
|
|||
async () => {
|
||||
const res = await ProductApi.PublicGetProductCategoryList(
|
||||
{
|
||||
// 代表含义:无商品也返回类型,即为全量的类型
|
||||
// Representative meaning: no goods also return the type, that is, the type of the full amount
|
||||
need_empty_category: true,
|
||||
entity_type: ProductEntityType.Bot,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ import { useEffect } from 'react';
|
|||
import { AuthStatus } from '@coze-arch/idl/developer_api';
|
||||
import { useResetLocationState } from '@coze-arch/bot-hooks';
|
||||
|
||||
// 三方授权成功,调用成功回调
|
||||
// The three-party authorization is successful, and the callback is successful.
|
||||
export const useAuthSuccess = (bindSuccess: (id: string) => void) => {
|
||||
const { state } = useLocation();
|
||||
const { oauth2, authStatus } = (state ?? history.state ?? {}) as Record<
|
||||
|
|
|
|||
|
|
@ -103,7 +103,7 @@ const getCheckboxProps = (record: PublishConnectorInfo, disabled: boolean) => {
|
|||
return {
|
||||
disabled: !!disableTip || disabled,
|
||||
id: record.id,
|
||||
// Offline状态没有tooltip
|
||||
// Offline status No tooltip
|
||||
children: disableTip ? (
|
||||
<Tooltip content={disableTip}>
|
||||
<span className={styles['disable-tooltip']} />
|
||||
|
|
@ -152,7 +152,7 @@ export const TableCollection = (props: PublishTableProps) => {
|
|||
[dataSourceForChannel, connectorBrandInfoMap],
|
||||
);
|
||||
|
||||
// 无全选按钮因此所有表格使用相同check配置
|
||||
// There is no select all button, so all tables use the same check configuration
|
||||
const baseConfigForChecker = {
|
||||
hidden: true,
|
||||
fixed: 'left' as const,
|
||||
|
|
@ -212,9 +212,9 @@ export const TableCollection = (props: PublishTableProps) => {
|
|||
: [record.id, ...ids],
|
||||
);
|
||||
}
|
||||
}, // 点击行选中
|
||||
onMouseEnter: () => onMouseEnter(record), // 鼠标移入行
|
||||
onMouseLeave: () => onMouseLeave(record), // 鼠标移出行
|
||||
}, // Click on the line to select
|
||||
onMouseEnter: () => onMouseEnter(record), // mouseover
|
||||
onMouseLeave: () => onMouseLeave(record), // mouse movement
|
||||
});
|
||||
const tableCommonProps = {
|
||||
className: classNames(styles['publish-table']),
|
||||
|
|
@ -285,7 +285,7 @@ function TableTittleExtra({
|
|||
platforms: PublishConnectorInfo[];
|
||||
botInfo: PublisherBotInfo;
|
||||
}) {
|
||||
// 付费墙
|
||||
// paywall
|
||||
const isAvailable = useBenefitAvailable({
|
||||
scene: PremiumPaywallScene.API,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ import { I18n } from '@coze-arch/i18n';
|
|||
import { Typography } from '@coze-arch/coze-design';
|
||||
import { type PluginPricingRule } from '@coze-arch/bot-api/plugin_develop';
|
||||
|
||||
// 发布页提示
|
||||
// release page tip
|
||||
export const PluginPricingInfo: FC<{
|
||||
pluginPricingRules?: Array<PluginPricingRule>;
|
||||
}> = ({ pluginPricingRules }) => {
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ export function SingleAgentModelView(props: SingleAgentModelViewProps) {
|
|||
<SingleAgentModelViewBase
|
||||
{...props}
|
||||
triggerRender={m => (
|
||||
// 模型临期时强制完整展示临期提示
|
||||
// Forced full display of Advent prompts during model Advent
|
||||
<Collapsible
|
||||
itemKey={itemKey}
|
||||
fullContent={
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
const DOMAIN_REGEXP = /^([0-9a-zA-Z-]{1,}\.)+([a-zA-Z]{2,})$/;
|
||||
|
||||
export function isValidUrl(url: string): boolean {
|
||||
|
|
@ -21,7 +21,7 @@ export function isValidUrl(url: string): boolean {
|
|||
// cp-disable-next-line
|
||||
const urlObject = new URL(`https://${url}`);
|
||||
return DOMAIN_REGEXP.test(urlObject.hostname);
|
||||
// eslint-disable-next-line @coze-arch/use-error-in-catch -- 根据函数功能无需 throw error
|
||||
// eslint-disable-next-line @coze-arch/use-error-in-catch -- no need to throw error according to function function
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,8 +35,8 @@ const getDefaultState = (): DraftBotDataSetStoreState => ({
|
|||
datasetsMap: {},
|
||||
});
|
||||
|
||||
// 目前 work_info 里的 dataset 只包含了很少量的元信息,
|
||||
// 为了方便判断引入的 dataset 类型(用于分组、模型能力检查等等),这里统一缓存当下使用的 dataset
|
||||
// At present, the dataset in the work_info contains only a small amount of meta information.
|
||||
// In order to facilitate the determination of the type of dataset introduced (for grouping, model capability checking, etc.), the dataset currently in use is cached here
|
||||
export const createDraftBotDatasetsStore = () =>
|
||||
create<DraftBotDataSetStoreState & DraftBotDataSetStoreAction>()(
|
||||
devtools(
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ import { create } from 'zustand';
|
|||
import { produce } from 'immer';
|
||||
|
||||
export interface FreeGrabModalHierarchyState {
|
||||
// modal 的 key list
|
||||
// Modal key list
|
||||
modalHierarchyList: string[];
|
||||
}
|
||||
|
||||
|
|
@ -31,7 +31,7 @@ export interface FreeGrabModalHierarchyAction {
|
|||
}
|
||||
|
||||
/**
|
||||
* 可自由拖拽的弹窗之间的层级关系
|
||||
* Hierarchical relationship between pop-ups that can be dragged and dropped freely
|
||||
*/
|
||||
export const createFreeGrabModalHierarchyStore = () =>
|
||||
create<FreeGrabModalHierarchyState & FreeGrabModalHierarchyAction>()(
|
||||
|
|
|
|||
|
|
@ -24,15 +24,15 @@ import { type ModelPresetValues } from './type';
|
|||
import { getModelPresetValues } from './helpers/get-model-preset-values';
|
||||
|
||||
export interface ModelState {
|
||||
// 当前环境所有合法的模型列表
|
||||
// List of all valid models in the current environment
|
||||
onlineModelList: Model[];
|
||||
/* 不属于当前环境的特殊模型 key === modelId
|
||||
* 例如: 在 cn-inhouse 选择 GPT 模型, 然后切换到 cn-release, 当前 bot 模型列表 = 正常模型列表 + 1个特殊模型(GPT)
|
||||
* MultiAgent 模式下, 每个 Agent 模型列表 = 正常模型列表 + 1个特殊模型(可能存在)
|
||||
* 从特殊模型切换到正常模型后, 不被允许切换回特殊模型
|
||||
/* Special models that do not belong to the current environment key === modelId
|
||||
* For example: select the GPT model in cn-inhouse, then switch to cn-release, the current bot model list = normal model list + 1 special model (GPT)
|
||||
* In MultiAgent mode, each Agent model list = normal model list + 1 special model (may exist)
|
||||
* After switching from the special model to the normal model, it is not allowed to switch back to the special model
|
||||
*/
|
||||
offlineModelMap: Record<string, Model>;
|
||||
// 纯计算属性, 由 specialModel 和 baseModel 计算而来 key === modelId
|
||||
// Pure computational properties, calculated from specialModel and baseModel key === modelId
|
||||
// key === modelId
|
||||
modelPresetValuesMap: Record<string, ModelPresetValues>;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ export interface OnboardingDirtyLogicCompatibilityAction {
|
|||
}
|
||||
|
||||
/**
|
||||
* 用来处理 bot 编辑页 onboarding 的复杂、脏业务逻辑
|
||||
* Complex, dirty business logic for handling bot edit page onboarding
|
||||
*/
|
||||
export const createOnboardingDirtyLogicCompatibilityStore = () =>
|
||||
create<
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ export type TGetModelCapabilityConfig = (params: {
|
|||
getModelById: (id: string) => Model | undefined;
|
||||
}) => ModelCapabilityConfig;
|
||||
|
||||
// 模型能力配置的 fallback,没有配置的能力按支持处理
|
||||
// Fallback of model capability configuration, capability without configuration is handled as supported
|
||||
export const defaultModelCapConfig = Object.values(ModelFuncConfigType).reduce(
|
||||
(res, type) => ({
|
||||
...res,
|
||||
|
|
@ -56,7 +56,7 @@ const mergeModelCapabilityConfig = (
|
|||
target
|
||||
? Object.entries(target).reduce<ModelCapabilityConfig>(
|
||||
(merged, [key, status]) => {
|
||||
// 未配置的能力视为完全支持
|
||||
// Unconfigured capabilities are considered fully supported
|
||||
const [preStatus, preName] = merged[
|
||||
key as unknown as ModelFuncConfigType
|
||||
] ?? [ModelFuncConfigStatus.FullSupport, []];
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ export function convertModelValueType(
|
|||
return Number(value);
|
||||
}
|
||||
|
||||
// 理论上不走这里
|
||||
// Theoretically not going here
|
||||
primitiveExhaustiveCheck(type);
|
||||
return value;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,13 +22,13 @@ import {
|
|||
} from '../src/services/type';
|
||||
import { BotInputLengthService, botInputLengthService } from '../src/services';
|
||||
|
||||
// 模拟 SuggestedQuestionsShowMode 枚举
|
||||
// Analog SuggestedQuestionsShowMode Enumeration
|
||||
enum SuggestedQuestionsShowMode {
|
||||
Random = 0,
|
||||
All = 1,
|
||||
}
|
||||
|
||||
// 模拟配置
|
||||
// simulation configuration
|
||||
const mockConfig: BotInputLengthConfig = {
|
||||
botName: 10,
|
||||
botDescription: 100,
|
||||
|
|
@ -39,16 +39,16 @@ const mockConfig: BotInputLengthConfig = {
|
|||
projectDescription: 100,
|
||||
};
|
||||
|
||||
// 模拟获取配置的函数
|
||||
// Function to simulate acquisition configuration
|
||||
const mockGetConfig = vi.fn().mockReturnValue(mockConfig);
|
||||
|
||||
describe('BotInputLengthService', () => {
|
||||
let service: BotInputLengthService;
|
||||
|
||||
beforeEach(() => {
|
||||
// 重置模拟
|
||||
// Reset simulation
|
||||
vi.clearAllMocks();
|
||||
// 创建服务实例
|
||||
// Create a service instance
|
||||
service = new BotInputLengthService(mockGetConfig);
|
||||
});
|
||||
|
||||
|
|
@ -62,23 +62,23 @@ describe('BotInputLengthService', () => {
|
|||
expect(service.getInputLengthLimit('projectName')).toBe(10);
|
||||
expect(service.getInputLengthLimit('projectDescription')).toBe(100);
|
||||
|
||||
// 验证配置获取函数被调用
|
||||
// Verify that the configuration get function is called
|
||||
expect(mockGetConfig).toHaveBeenCalledTimes(7);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getValueLength', () => {
|
||||
it('应该返回字符串的字形簇数量', () => {
|
||||
// 普通字符串
|
||||
// Normal string
|
||||
expect(service.getValueLength('hello')).toBe(5);
|
||||
|
||||
// 包含表情符号的字符串(表情符号算作一个字形簇)
|
||||
// A string containing the emoji (the emoji counts as a glyph cluster)
|
||||
expect(service.getValueLength('hi😊')).toBe(3);
|
||||
|
||||
// 包含组合字符的字符串
|
||||
// A string containing combined characters
|
||||
expect(service.getValueLength('café')).toBe(4);
|
||||
|
||||
// 空字符串
|
||||
// empty string
|
||||
expect(service.getValueLength('')).toBe(0);
|
||||
|
||||
// undefined
|
||||
|
|
@ -88,12 +88,12 @@ describe('BotInputLengthService', () => {
|
|||
|
||||
describe('sliceStringByMaxLength', () => {
|
||||
it('应该根据字段限制截取字符串', () => {
|
||||
// 字符串长度小于限制
|
||||
// String length less than limit
|
||||
expect(
|
||||
service.sliceStringByMaxLength({ value: 'hello', field: 'botName' }),
|
||||
).toBe('hello');
|
||||
|
||||
// 字符串长度等于限制
|
||||
// String length equals limit
|
||||
expect(
|
||||
service.sliceStringByMaxLength({
|
||||
value: '1234567890',
|
||||
|
|
@ -101,7 +101,7 @@ describe('BotInputLengthService', () => {
|
|||
}),
|
||||
).toBe('1234567890');
|
||||
|
||||
// 字符串长度大于限制
|
||||
// String length is greater than limit
|
||||
expect(
|
||||
service.sliceStringByMaxLength({
|
||||
value: '12345678901234567890',
|
||||
|
|
@ -109,7 +109,7 @@ describe('BotInputLengthService', () => {
|
|||
}),
|
||||
).toBe('1234567890');
|
||||
|
||||
// 包含表情符号的字符串
|
||||
// A string containing emoji
|
||||
expect(
|
||||
service.sliceStringByMaxLength({
|
||||
value: 'hello😊world',
|
||||
|
|
@ -117,7 +117,7 @@ describe('BotInputLengthService', () => {
|
|||
}),
|
||||
).toBe('hello😊worl');
|
||||
|
||||
// 验证配置获取函数被调用
|
||||
// Verify that the configuration get function is called
|
||||
expect(mockGetConfig).toHaveBeenCalledTimes(4);
|
||||
});
|
||||
});
|
||||
|
|
@ -147,13 +147,13 @@ describe('BotInputLengthService', () => {
|
|||
|
||||
const result = service.sliceWorkInfoOnboardingByMaxLength(workInfo);
|
||||
|
||||
// 验证开场白被截取
|
||||
// Verify that the opening statement was intercepted
|
||||
expect(result.prologue).toBe(
|
||||
'This is a very long prologue that exceeds the limi',
|
||||
);
|
||||
expect(result.prologue.length).toBeLessThanOrEqual(50);
|
||||
|
||||
// 验证建议问题被截取
|
||||
// Validation suggestion problem intercepted
|
||||
expect(result.suggested_questions[0]?.content).toBe(
|
||||
'This is a very long ',
|
||||
);
|
||||
|
|
@ -175,7 +175,7 @@ describe('BotInputLengthService', () => {
|
|||
expect(result.suggested_questions[2]?.id).toBe('3');
|
||||
expect(result.suggested_questions[2]?.highlight).toBe(false);
|
||||
|
||||
// 验证显示模式保持不变
|
||||
// Verify that the display mode remains unchanged
|
||||
expect(result.suggested_questions_show_mode).toBe(
|
||||
SuggestedQuestionsShowMode.All,
|
||||
);
|
||||
|
|
@ -199,10 +199,10 @@ describe('BotInputLengthService', () => {
|
|||
});
|
||||
});
|
||||
|
||||
// 测试导出的单例
|
||||
// Test Exported Singletons
|
||||
describe('botInputLengthService', () => {
|
||||
it('应该导出一个 BotInputLengthService 的实例', () => {
|
||||
// 验证导出的单例是 BotInputLengthService 的实例
|
||||
// Verify that the exported singleton is an instance of BotInputLengthService
|
||||
expect(botInputLengthService).toBeInstanceOf(BotInputLengthService);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -17,19 +17,19 @@
|
|||
import { type SuggestedQuestionsShowMode } from '@coze-arch/bot-api/playground_api';
|
||||
|
||||
export interface BotInputLengthConfig {
|
||||
/** Agent 名称的长度 */
|
||||
/** Length of Agent Name */
|
||||
botName: number;
|
||||
/** Agent 描述的长度 */
|
||||
/** Length of Agent Description */
|
||||
botDescription: number;
|
||||
/** Agent 开场白的长度 */
|
||||
/** Length of Agent's opening statement */
|
||||
onboarding: number;
|
||||
/** Agent 单条开场白建议的长度 */
|
||||
/** Agent, the length of a single opening line suggestion */
|
||||
onboardingSuggestion: number;
|
||||
/** 用户问题建议自定义 prompt 长度 */
|
||||
/** User question Suggested custom prompt length */
|
||||
suggestionPrompt: number;
|
||||
/** Project 名称的长度 */
|
||||
/** Length of Project Name */
|
||||
projectName: number;
|
||||
/** Project 描述的长度 */
|
||||
/** Project Description Length */
|
||||
projectDescription: number;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -52,8 +52,8 @@ vi.mock('@coze-arch/bot-tea', () => ({
|
|||
},
|
||||
ParamsTypeDefine: {},
|
||||
PluginMockDataGenerateMode: {
|
||||
MANUAL: 0, // 手动创建
|
||||
RANDOM: 1, // 随机生成
|
||||
MANUAL: 0, // create manually
|
||||
RANDOM: 1, // random generation
|
||||
LLM: 2,
|
||||
},
|
||||
}));
|
||||
|
|
@ -61,21 +61,21 @@ vi.mock('@coze-arch/bot-tea', () => ({
|
|||
vi.mock('@coze-arch/bot-hooks', () => ({
|
||||
SceneType: {
|
||||
BOT__VIEW__WORKFLOW: 'botViewWorkflow',
|
||||
/** bot 详情页查看 workflow,或新建 workflow 但未发布,点击返回 */
|
||||
/** View the workflow on the bot details page, or create a new workflow but not published, click Return */
|
||||
WORKFLOW__BACK__BOT: 'workflowBackBot',
|
||||
/** bot 详情页创建 workflow,在 workflow 发布后返回 */
|
||||
/** The bot details page creates a workflow and returns it after the workflow is published */
|
||||
WORKFLOW_PUBLISHED__BACK__BOT: 'workflowPublishedBackBot',
|
||||
/** bot 详情页进入 mock data 页面 */
|
||||
/** Bot details page Enter the mock data page */
|
||||
BOT__TO__PLUGIN_MOCK_DATA: 'botToPluginMockData',
|
||||
/** workflow 详情页进入 mock data 页面 */
|
||||
/** Workflow details page Enter the mock data page */
|
||||
WORKFLOW__TO__PLUGIN_MOCK_DATA: 'workflowToPluginMockData',
|
||||
/** mock set 页进入 mock data 页面 */
|
||||
/** Mock set page Enter the mock data page */
|
||||
PLUGIN_MOCK_SET__TO__PLUGIN_MOCK_DATA: 'pluginMockSetToPluginMockData',
|
||||
/** bot 详情页进入 knowledge 页面 */
|
||||
/** Bot details page Enter the knowledge page */
|
||||
BOT__VIEW__KNOWLEDGE: 'botViewKnowledge',
|
||||
/** knowledge 页面点击退出返回 bot 详情页(未点击添加) */
|
||||
/** Knowledge page Click Exit to return to bot details page (not clicked Add) */
|
||||
KNOWLEDGE__BACK__BOT: 'knowledgeBackBot',
|
||||
/** knowledge 页面点击返回 bot 详情页,并添加到 bot */
|
||||
/** Knowledge page Click to return to bot details page and add to bot */
|
||||
KNOWLEDGE__ADD_TO__BOT: 'knowledgeAddToBot',
|
||||
},
|
||||
usePageJumpService: vi.fn().mockReturnValue({
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// 引入我们的被测方法
|
||||
// Introducing our test method
|
||||
|
||||
import { describe, expect, it, vi } from 'vitest';
|
||||
|
||||
|
|
@ -23,39 +23,39 @@ import { getEnv } from '@/util/get-env';
|
|||
describe('getEnv function', () => {
|
||||
it('should return "cn-boe" when not in production', () => {
|
||||
vi.stubGlobal('IS_PROD', undefined);
|
||||
// 不设置IS_PROD,默认为非生产环境
|
||||
// Do not set IS_PROD, default to non-production environment
|
||||
const env = getEnv();
|
||||
expect(env).toBe('cn-boe');
|
||||
});
|
||||
|
||||
it('should return "cn-release" when in production, not overseas, and is release version', () => {
|
||||
vi.stubGlobal('IS_PROD', true); // 设置为生产环境
|
||||
vi.stubGlobal('IS_OVERSEA', false); // 不是海外
|
||||
vi.stubGlobal('IS_RELEASE_VERSION', true); // 是发布版本
|
||||
vi.stubGlobal('IS_PROD', true); // Set to production environment
|
||||
vi.stubGlobal('IS_OVERSEA', false); // Not overseas.
|
||||
vi.stubGlobal('IS_RELEASE_VERSION', true); // Is the release version
|
||||
const env = getEnv();
|
||||
expect(env).toBe('cn-release');
|
||||
});
|
||||
|
||||
it('should return "cn-inhouse" when in production, not overseas, and is not release version', () => {
|
||||
vi.stubGlobal('IS_PROD', true); // 设置为生产环境
|
||||
vi.stubGlobal('IS_OVERSEA', false); // 不是海外
|
||||
vi.stubGlobal('IS_RELEASE_VERSION', false); // 不是发布版本
|
||||
vi.stubGlobal('IS_PROD', true); // Set to production environment
|
||||
vi.stubGlobal('IS_OVERSEA', false); // Not overseas.
|
||||
vi.stubGlobal('IS_RELEASE_VERSION', false); // Not the release version
|
||||
const env = getEnv();
|
||||
expect(env).toBe('cn-inhouse');
|
||||
});
|
||||
|
||||
it('should return "oversea-release" when in production, overseas, and is release version', () => {
|
||||
vi.stubGlobal('IS_PROD', true); // 设置为生产环境
|
||||
vi.stubGlobal('IS_OVERSEA', true); // 是海外
|
||||
vi.stubGlobal('IS_RELEASE_VERSION', true); // 是发布版本
|
||||
vi.stubGlobal('IS_PROD', true); // Set to production environment
|
||||
vi.stubGlobal('IS_OVERSEA', true); // Is overseas
|
||||
vi.stubGlobal('IS_RELEASE_VERSION', true); // Is the release version
|
||||
const env = getEnv();
|
||||
expect(env).toBe('oversea-release');
|
||||
});
|
||||
|
||||
it('should return "oversea-inhouse" when in production, overseas, and is not release version', () => {
|
||||
vi.stubGlobal('IS_PROD', true); // 设置为生产环境
|
||||
vi.stubGlobal('IS_OVERSEA', true); // 是海外
|
||||
vi.stubGlobal('IS_RELEASE_VERSION', false); // 不是发布版本
|
||||
vi.stubGlobal('IS_PROD', true); // Set to production environment
|
||||
vi.stubGlobal('IS_OVERSEA', true); // Is overseas
|
||||
vi.stubGlobal('IS_RELEASE_VERSION', false); // Not the release version
|
||||
const env = getEnv();
|
||||
expect(env).toBe('oversea-inhouse');
|
||||
});
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ export const PluginModal: React.FC<PluginModalProps> = ({
|
|||
return openMode === OpenModeType.OnlyOnceAdd ? [] : pluginApis;
|
||||
};
|
||||
const { sider, filter, content } = usePluginModalParts({
|
||||
// 如果是仅添加一次,清空默认选中
|
||||
// If it is added only once, clear the default selection.
|
||||
pluginApiList: getPluginApiList(),
|
||||
onPluginApiListChange: updateSkillPluginApis,
|
||||
openMode,
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ export const usePluginApisModal = (props?: PluginModalModeProps) => {
|
|||
const _initQuery = isNumber(params) ? undefined : params?.initQuery;
|
||||
setVisible(true);
|
||||
setInitQuery(_initQuery);
|
||||
// 0 也有效
|
||||
// 0 is also valid
|
||||
if (isNumber(openType)) {
|
||||
setType(openType);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,17 +54,17 @@ export interface ToolDetailPageProps
|
|||
onDebugSuccessCallback?: () => void;
|
||||
}
|
||||
|
||||
// 页面-编辑插件API
|
||||
// Page - Edit Plugin API
|
||||
export const ToolDetailPage: FC<ToolDetailPageProps> = ({
|
||||
toolID,
|
||||
onDebugSuccessCallback,
|
||||
renderDescComponent,
|
||||
renderParamsComponent,
|
||||
}) => {
|
||||
//捕获错误信息,跳转统一落地页
|
||||
//Capture error messages and jump to the unified landing page
|
||||
const capture = useErrorHandler();
|
||||
const [editVersion, setEditVersion] = useState<number>();
|
||||
//插件-API详情
|
||||
//Plugin-API Details
|
||||
const [apiInfo, setApiInfo] = useState<PluginAPIInfo>();
|
||||
const [debugApiInfo, setDebugApiInfo] = useState<PluginAPIInfo>();
|
||||
const [loading, setLoading] = useState<boolean>(true);
|
||||
|
|
@ -104,7 +104,7 @@ export const ToolDetailPage: FC<ToolDetailPageProps> = ({
|
|||
});
|
||||
};
|
||||
|
||||
// 重置 request 参数
|
||||
// Reset request parameters
|
||||
const resetRequestParams = (data: PluginAPIInfo) => {
|
||||
const requestParams = cloneDeep(data.request_params as APIParameter[]);
|
||||
if (
|
||||
|
|
@ -120,7 +120,7 @@ export const ToolDetailPage: FC<ToolDetailPageProps> = ({
|
|||
return requestParams;
|
||||
};
|
||||
|
||||
// 设置接口信息(回显和置空)
|
||||
// Set interface information (echo and empty)
|
||||
const handleInit = async (useloading = false) => {
|
||||
setApiInfo({
|
||||
...apiInfo,
|
||||
|
|
@ -140,12 +140,12 @@ export const ToolDetailPage: FC<ToolDetailPageProps> = ({
|
|||
|
||||
if (api_info.length > 0) {
|
||||
const apiInfoTemp = api_info.length > 0 ? api_info[0] : {};
|
||||
// debug 的数据 如果有 example 需要回显 入参数据额外处理
|
||||
// Debug data, if there is an example, the imported parameter data needs to be echoed for additional processing
|
||||
setDebugApiInfo({
|
||||
...apiInfoTemp,
|
||||
request_params: resetRequestParams(apiInfoTemp),
|
||||
});
|
||||
// 给对象增加层级标识
|
||||
// Adding hierarchical identifiers to objects
|
||||
addDepthAndValue(apiInfoTemp.request_params);
|
||||
addDepthAndValue(apiInfoTemp.response_params);
|
||||
setApiInfo(apiInfoTemp);
|
||||
|
|
@ -170,7 +170,7 @@ export const ToolDetailPage: FC<ToolDetailPageProps> = ({
|
|||
useloading && setLoading(false);
|
||||
};
|
||||
|
||||
// 1.基本信息
|
||||
// 1. Basic information
|
||||
const {
|
||||
isBaseInfoDisabled,
|
||||
header: baseInfoHeader,
|
||||
|
|
@ -190,7 +190,7 @@ export const ToolDetailPage: FC<ToolDetailPageProps> = ({
|
|||
renderDescComponent,
|
||||
});
|
||||
|
||||
// 2 更多设置
|
||||
// 2 more settings
|
||||
const {
|
||||
isBaseMoreDisabled,
|
||||
header: baseMoreHeader,
|
||||
|
|
@ -211,7 +211,7 @@ export const ToolDetailPage: FC<ToolDetailPageProps> = ({
|
|||
onSuccess: handleSuccess,
|
||||
});
|
||||
|
||||
// 3.设置 request
|
||||
// 3. Set request
|
||||
const {
|
||||
isRequestParamsDisabled,
|
||||
itemKey: requestItemKey,
|
||||
|
|
@ -233,7 +233,7 @@ export const ToolDetailPage: FC<ToolDetailPageProps> = ({
|
|||
renderParamsComponent,
|
||||
});
|
||||
|
||||
// 4.设置 response
|
||||
// 4. Set up the response
|
||||
const {
|
||||
isResponseParamsDisabled,
|
||||
itemKey: responseItemKey,
|
||||
|
|
@ -298,7 +298,7 @@ export const ToolDetailPage: FC<ToolDetailPageProps> = ({
|
|||
};
|
||||
}, []);
|
||||
|
||||
// 预览状态解锁,如果有一步为编辑态,则不解锁
|
||||
// The preview state is unlocked. If there is an edit state, it will not be unlocked.
|
||||
useUpdateEffect(() => {
|
||||
if (
|
||||
!isBaseInfoDisabled ||
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ const ToolHeader: FC<ToolHeaderProps> = ({
|
|||
unlockPlugin();
|
||||
};
|
||||
|
||||
// 管理模拟集
|
||||
// management simulation set
|
||||
const handleManageMockset = () => {
|
||||
resourceNavigate.mocksetList?.(tool_id);
|
||||
};
|
||||
|
|
@ -119,7 +119,7 @@ const ToolHeader: FC<ToolHeaderProps> = ({
|
|||
/>
|
||||
<span className={s.title}>{I18n.t('plugin_edit_tool_title')}</span>
|
||||
<OauthButtonAction />
|
||||
{/* 即将支持,敬请期待 */}
|
||||
{/* Support soon, so stay tuned. */}
|
||||
{FLAGS['bot.devops.plugin_mockset'] ? (
|
||||
<Tooltip
|
||||
style={{ display: mocksetDisabled ? 'block' : 'none' }}
|
||||
|
|
|
|||
|
|
@ -54,12 +54,12 @@ export const useContentBaseMore = ({
|
|||
editVersion,
|
||||
onSuccess,
|
||||
}: UseContentBaseInfoProps) => {
|
||||
// 是否显示安全检查失败信息
|
||||
// Is the security check failure message displayed?
|
||||
const [showSecurityCheckFailedMsg, setShowSecurityCheckFailedMsg] =
|
||||
useState(false);
|
||||
const [isBaseMoreDisabled, setIsBaseMoreDisabled] = useState(true);
|
||||
|
||||
// 基本信息
|
||||
// Basic information
|
||||
const { baseInfoNode, submitBaseInfo } = useBaseMore({
|
||||
pluginId: plugin_id || '',
|
||||
pluginMeta: pluginInfo?.meta_info || {},
|
||||
|
|
@ -101,7 +101,7 @@ export const useContentBaseMore = ({
|
|||
onClick={async e => {
|
||||
e.stopPropagation();
|
||||
const status = await submitBaseInfo();
|
||||
// 更新成功后进入下一步
|
||||
// After the update is successful, proceed to the next step
|
||||
if (status) {
|
||||
handleInit();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,12 +48,12 @@ export const useContentBaseInfo = ({
|
|||
editVersion,
|
||||
renderDescComponent,
|
||||
}: UseContentBaseInfoProps) => {
|
||||
// 是否显示安全检查失败信息
|
||||
// Is the security check failure message displayed?
|
||||
const [showSecurityCheckFailedMsg, setShowSecurityCheckFailedMsg] =
|
||||
useState(false);
|
||||
const [isBaseInfoDisabled, setIsBaseInfoDisabled] = useState(true);
|
||||
|
||||
// 基本信息
|
||||
// Basic information
|
||||
const { baseInfoNode, submitBaseInfo } = useBaseInfo({
|
||||
pluginId: plugin_id || '',
|
||||
apiId: tool_id,
|
||||
|
|
@ -93,7 +93,7 @@ export const useContentBaseInfo = ({
|
|||
onClick={async e => {
|
||||
e.stopPropagation();
|
||||
const status = await submitBaseInfo();
|
||||
// 更新成功后进入下一步
|
||||
// After the update is successful, proceed to the next step
|
||||
if (status) {
|
||||
handleInit();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ export const useContentDebug = ({
|
|||
debugApiInfo && tool_id ? (
|
||||
<Debug
|
||||
pluginType={pluginInfo?.plugin_type}
|
||||
disabled={false} // 是否可调试
|
||||
disabled={false} // Is it debuggable?
|
||||
setDebugStatus={setDebugStatus}
|
||||
pluginId={String(plugin_id)}
|
||||
apiId={String(tool_id)}
|
||||
|
|
@ -113,7 +113,7 @@ export const useContentDebug = ({
|
|||
>
|
||||
<Debug
|
||||
pluginType={pluginInfo?.plugin_type}
|
||||
disabled={false} // 是否可调试
|
||||
disabled={false} // Is it debuggable?
|
||||
setDebugStatus={setDebugStatus}
|
||||
pluginId={String(plugin_id)}
|
||||
apiId={String(tool_id)}
|
||||
|
|
|
|||
|
|
@ -58,11 +58,11 @@ export const useContentRequest = ({
|
|||
onSuccess,
|
||||
renderParamsComponent,
|
||||
}: UseContentRequestProps) => {
|
||||
// 是否显示安全检查失败信息
|
||||
// Is the security check failure message displayed?
|
||||
const [showSecurityCheckFailedMsg, setShowSecurityCheckFailedMsg] =
|
||||
useState(false);
|
||||
const [isRequestParamsDisabled, setIsRequestParamsDisabled] = useState(true);
|
||||
// 设置请求参数
|
||||
// Set request parameters
|
||||
const { requestParamsNode, submitRequestParams, nlTool } = useRequestParams({
|
||||
apiInfo,
|
||||
pluginId: plugin_id || '',
|
||||
|
|
@ -107,7 +107,7 @@ export const useContentRequest = ({
|
|||
onClick={async e => {
|
||||
e.stopPropagation();
|
||||
const status = await submitRequestParams();
|
||||
// 更新成功后进入下一步
|
||||
// After the update is successful, proceed to the next step
|
||||
if (status) {
|
||||
handleInit();
|
||||
setIsRequestParamsDisabled(true);
|
||||
|
|
|
|||
|
|
@ -66,12 +66,12 @@ export const useContentResponse = ({
|
|||
onSuccess,
|
||||
renderParamsComponent,
|
||||
}: UseContentResponseProps) => {
|
||||
// 是否显示安全检查失败信息
|
||||
// Is the security check failure message displayed?
|
||||
const [showSecurityCheckFailedMsg, setShowSecurityCheckFailedMsg] =
|
||||
useState(false);
|
||||
const [isResponseParamsDisabled, setIsResponseParamsDisabled] =
|
||||
useState(true);
|
||||
// 第三步,设置相应参数的hooks组件
|
||||
// The third step is to set the corresponding parameters of the hooks component
|
||||
const { responseParamsNode, submitResponseParams, extra } = useResponseParams(
|
||||
{
|
||||
apiInfo,
|
||||
|
|
@ -94,7 +94,7 @@ export const useContentResponse = ({
|
|||
},
|
||||
);
|
||||
|
||||
// 处理 debug 时 example数据先显示后隐藏的问题
|
||||
// When dealing with debugging, the example data is displayed first and then hidden
|
||||
useEffect(() => {
|
||||
if (!isResponseParamsDisabled) {
|
||||
setDebugApiInfo({
|
||||
|
|
@ -133,7 +133,7 @@ export const useContentResponse = ({
|
|||
onClick={async e => {
|
||||
e.stopPropagation();
|
||||
const status = await submitResponseParams();
|
||||
// 更新成功后进入下一步
|
||||
// After the update is successful, proceed to the next step
|
||||
if (status) {
|
||||
handleInit();
|
||||
setIsResponseParamsDisabled(true);
|
||||
|
|
|
|||
|
|
@ -78,8 +78,8 @@ const useAuthForApiTool = () => {
|
|||
|
||||
return {
|
||||
canEdit,
|
||||
needAuth, // 需要 auth 授权
|
||||
isHasAuth, // 是否完成了授权
|
||||
needAuth, // Requires auth authorization
|
||||
isHasAuth, // Has the authorization been completed?
|
||||
doCancelOauth,
|
||||
isUpdateLoading,
|
||||
doOauth,
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@
|
|||
& svg {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
/* stylelint-disable-next-line declaration-no-important -- 覆盖icon颜色 */
|
||||
/* stylelint-disable-next-line declaration-no-important -- Override icon color */
|
||||
color: var(--semi-color-text-2) !important;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -66,9 +66,9 @@ enum PageSource {
|
|||
}
|
||||
|
||||
enum PageMode {
|
||||
/** 整页 UI类似全覆盖浮层 */
|
||||
/** Full page UI similar to full coverage floating layer */
|
||||
FULL_PAGE = 'full_page',
|
||||
/** 嵌入(左侧有菜单栏) */
|
||||
/** Embed (with menu bar on the left) */
|
||||
EMBED = 'embed',
|
||||
}
|
||||
|
||||
|
|
@ -87,16 +87,16 @@ const MockSetDetail: FC<{
|
|||
[],
|
||||
);
|
||||
const routeResponse = usePageJumpResponse(PageType.PLUGIN_MOCK_DATA);
|
||||
// API 详情
|
||||
// API Details
|
||||
const [apiInfo, setApiInfo] = useState<PluginAPIInfo>({
|
||||
name: routeResponse?.toolName,
|
||||
});
|
||||
// mock set 详情
|
||||
// Mock set details
|
||||
const [mockSetInfo, setMockSetInfo] = useState<MockSet>({
|
||||
id: mocksetID,
|
||||
name: routeResponse?.mockSetName,
|
||||
});
|
||||
// API 对应 schema
|
||||
// API correspondence schema
|
||||
const [toolSchema, setToolSchema] = useState<string>('');
|
||||
const [perm, setPerm] = useState<{
|
||||
readOnly: boolean;
|
||||
|
|
@ -109,9 +109,9 @@ const MockSetDetail: FC<{
|
|||
const listRef = useRef<MockDataListActions>(null);
|
||||
const contentEleRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
// 页面展示模式
|
||||
// page display mode
|
||||
const pageMode = params.hideMenu ? PageMode.FULL_PAGE : PageMode.EMBED;
|
||||
// 页面来源
|
||||
// page source
|
||||
const fromSource = routeResponse?.fromSource
|
||||
? (routeResponse.fromSource as PageSource)
|
||||
: PageSource.FROM_MOCK_SET;
|
||||
|
|
@ -142,7 +142,7 @@ const MockSetDetail: FC<{
|
|||
[toolID, pluginID],
|
||||
);
|
||||
|
||||
// 获取当前 tool 信息
|
||||
// Get current tool information
|
||||
const getPluginToolInfo = async () => {
|
||||
try {
|
||||
const { api_info = [] } = await PluginDevelopApi.GetPluginAPIs(
|
||||
|
|
@ -164,7 +164,7 @@ const MockSetDetail: FC<{
|
|||
}
|
||||
};
|
||||
|
||||
// 获取当前 mock set 信息
|
||||
// Get current mock set information
|
||||
const getMockSetInfo = async () => {
|
||||
if (!mocksetID) {
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ import { getDisplayCols } from './get-col';
|
|||
import styles from './index.module.less';
|
||||
|
||||
interface ListParams {
|
||||
pageNo?: number; // 用于前端计算数量
|
||||
pageNo?: number; // Quantity for front-end computing
|
||||
pageSize?: number;
|
||||
pageToken?: string;
|
||||
order?: {
|
||||
|
|
@ -80,13 +80,13 @@ const TOOL_NOT_FOUND_CODE = '600303108';
|
|||
const MockSetList: FC<{ toolID: string }> = ({ toolID }) => {
|
||||
const resourceNavigate = usePluginNavigate();
|
||||
|
||||
// user信息
|
||||
// User information
|
||||
const userInfo = userStoreService.useUserInfo();
|
||||
|
||||
// 路由信息
|
||||
// routing information
|
||||
|
||||
const [params, setParams] = useState<ListParams>({
|
||||
//请求参数
|
||||
//request parameters
|
||||
pageSize: PAGE_SIZE,
|
||||
pageNo: 1,
|
||||
});
|
||||
|
|
@ -101,11 +101,11 @@ const MockSetList: FC<{ toolID: string }> = ({ toolID }) => {
|
|||
})),
|
||||
);
|
||||
|
||||
// space信息
|
||||
// Space information
|
||||
const space = useSpace(spaceID);
|
||||
const isPersonal = space?.space_type === SpaceType.Personal;
|
||||
|
||||
// API 详情
|
||||
// API Details
|
||||
const [apiInfo, setApiInfo] = useState<PluginAPIInfo>();
|
||||
|
||||
const [showCreateModal, setShowCreateModal] = useState(false);
|
||||
|
|
@ -118,7 +118,7 @@ const MockSetList: FC<{ toolID: string }> = ({ toolID }) => {
|
|||
|
||||
const [editDisabled, setEditDisabled] = useState(false);
|
||||
|
||||
// 后端需要的mock上下文信息
|
||||
// The mock context information required by the backend
|
||||
const ctxInfo = {
|
||||
bizCtx: {
|
||||
trafficScene: TrafficScene.Undefined,
|
||||
|
|
@ -216,7 +216,7 @@ const MockSetList: FC<{ toolID: string }> = ({ toolID }) => {
|
|||
}
|
||||
};
|
||||
|
||||
// 获取当前tool信息
|
||||
// Get current tool information
|
||||
const getPluginToolInfo = async () => {
|
||||
try {
|
||||
const { api_info = [] } = await PluginDevelopApi.GetPluginAPIs({
|
||||
|
|
@ -351,13 +351,13 @@ const MockSetList: FC<{ toolID: string }> = ({ toolID }) => {
|
|||
if (!editDisabled) {
|
||||
handleEdit(record);
|
||||
}
|
||||
}, // 点击行
|
||||
}, // Click line
|
||||
}),
|
||||
onChange: e => {
|
||||
if (e.sorter?.sortOrder) {
|
||||
tableRef.current?.reset();
|
||||
|
||||
//时间排序
|
||||
//chronological sorting
|
||||
setParams(p => ({
|
||||
...p,
|
||||
pageSize: PAGE_SIZE,
|
||||
|
|
@ -410,7 +410,7 @@ const MockSetList: FC<{ toolID: string }> = ({ toolID }) => {
|
|||
></MockSetEditModal>
|
||||
) : null}
|
||||
{
|
||||
// 删除弹窗
|
||||
// Delete pop-up window
|
||||
deleteMockSet ? (
|
||||
<MockSetDeleteModal
|
||||
visible={!!deleteMockSet}
|
||||
|
|
|
|||
|
|
@ -35,8 +35,8 @@ interface UseCreateToolProps {
|
|||
plugin_id: string;
|
||||
onClickWrapper?: (fn: () => void) => () => Promise<void>;
|
||||
/**
|
||||
* 点击创建工具按钮前的回调函数
|
||||
* @returns {boolean | void} 返回false时将阻止后续动作
|
||||
* The callback function before clicking the Create Tool button
|
||||
* @Returns {boolean | void} returns false to block subsequent actions
|
||||
*/
|
||||
onBeforeClick?: () => void;
|
||||
disabled: boolean;
|
||||
|
|
@ -151,7 +151,7 @@ export const useCreateTool = ({
|
|||
};
|
||||
|
||||
/**
|
||||
* @description 创建工具
|
||||
* @description creation tool
|
||||
*/
|
||||
export const CreateTool: FC<CreateToolProps> = props => {
|
||||
const { content } = useCreateTool({
|
||||
|
|
|
|||
|
|
@ -155,7 +155,7 @@ const PluginDetailPage = ({
|
|||
);
|
||||
|
||||
const [params, setParams] = useState<GetPluginAPIsRequest>({
|
||||
//请求参数
|
||||
//request parameters
|
||||
page: 1,
|
||||
size: 10,
|
||||
plugin_id: pluginID,
|
||||
|
|
@ -236,7 +236,7 @@ const PluginDetailPage = ({
|
|||
|
||||
const dataSource = data?.api_info;
|
||||
|
||||
/** 不再提示 */
|
||||
/** no longer prompt */
|
||||
const noTips = async () => {
|
||||
const res = await PluginDevelopApi.NoUpdatedPrompt({
|
||||
plugin_id: pluginID,
|
||||
|
|
@ -248,7 +248,7 @@ const PluginDetailPage = ({
|
|||
|
||||
const checkPublish = async () => {
|
||||
if (!pluginInfo?.published) {
|
||||
//未发布过点击直接发布
|
||||
//It has not been published. Click to publish directly.
|
||||
setPublishPopShow(true);
|
||||
return;
|
||||
}
|
||||
|
|
@ -264,7 +264,7 @@ const PluginDetailPage = ({
|
|||
setPublishPopData(res);
|
||||
setShowPublishCheckPop(true);
|
||||
} else {
|
||||
//没有修改api直接发布
|
||||
//Publish directly without modifying the api
|
||||
setPublishPopShow(true);
|
||||
}
|
||||
};
|
||||
|
|
@ -308,14 +308,14 @@ const PluginDetailPage = ({
|
|||
onStatusChange?.('error');
|
||||
}
|
||||
}, [initSuccessed]);
|
||||
// 区分ide的跳转
|
||||
// Differentiate IDE jumps
|
||||
const handleIdeJump = (
|
||||
initialAction = InitialAction.DEFAULT,
|
||||
toolId = '',
|
||||
) => {
|
||||
// ide 逻辑
|
||||
// IDE logic
|
||||
if (isCloudIDEPlugin) {
|
||||
// 改变路由地址 返回的时候会清掉
|
||||
// Change the routing address and it will be cleared when returning.
|
||||
preloadIDE?.handleShowIde({ initialAction, toolId });
|
||||
} else if (toolId) {
|
||||
resourceNavigate.tool?.(toolId);
|
||||
|
|
@ -337,7 +337,7 @@ const PluginDetailPage = ({
|
|||
canEdit ? { mode: 'preview' } : {},
|
||||
);
|
||||
}
|
||||
}, // 点击行
|
||||
}, // Click line
|
||||
});
|
||||
|
||||
const { exampleNode, openExample } = useEditExample({
|
||||
|
|
@ -445,7 +445,7 @@ const PluginDetailPage = ({
|
|||
) : null}
|
||||
|
||||
<Layout.Content className={s['layout-content']}>
|
||||
{/* 已发布且有更新展示 */}
|
||||
{/* Published and updated */}
|
||||
{pluginInfo?.status &&
|
||||
pluginInfo?.published &&
|
||||
canEdit &&
|
||||
|
|
@ -470,7 +470,7 @@ const PluginDetailPage = ({
|
|||
}
|
||||
/>
|
||||
) : null}
|
||||
{/* plugin简介 */}
|
||||
{/* Plugin Introduction */}
|
||||
{pluginInfo ? (
|
||||
<PluginHeader
|
||||
pluginInfo={pluginInfo}
|
||||
|
|
@ -502,7 +502,7 @@ const PluginDetailPage = ({
|
|||
onBeforeClick={() => {
|
||||
setShowDropDownItem(undefined);
|
||||
if (isCloudIDEPlugin) {
|
||||
// 改变路由地址 返回的时候会清掉
|
||||
// Change the routing address and it will be cleared when returning.
|
||||
preloadIDE?.handleShowIde({
|
||||
initialAction: InitialAction.CREATE_TOOL,
|
||||
toolId: '',
|
||||
|
|
@ -529,7 +529,7 @@ const PluginDetailPage = ({
|
|||
{I18n.t('import')}
|
||||
</Button>
|
||||
) : null}
|
||||
{/* ! 发布按钮 */}
|
||||
{/* ! Post button */}
|
||||
{isRenderIDEPublishButton ? (
|
||||
<Tooltip
|
||||
position="left"
|
||||
|
|
@ -598,7 +598,7 @@ const PluginDetailPage = ({
|
|||
}
|
||||
/>
|
||||
) : null}
|
||||
{/* 工具列表表格 */}
|
||||
{/* Tool List Form */}
|
||||
{!!dataSource?.length && (
|
||||
<div className="mb-[24px] mt-[36px] text-[18px] weight-[600]">
|
||||
{I18n.t('plugin_api_list_table_name')}
|
||||
|
|
@ -615,7 +615,7 @@ const PluginDetailPage = ({
|
|||
onRow,
|
||||
onChange: e => {
|
||||
if (e.sorter?.sortOrder) {
|
||||
//时间排序
|
||||
//chronological sorting
|
||||
setParams(p => ({
|
||||
...p,
|
||||
page: 1,
|
||||
|
|
@ -634,7 +634,7 @@ const PluginDetailPage = ({
|
|||
btnText: canEdit ? createToolText : undefined,
|
||||
btnOnClick: () => {
|
||||
if (isCloudIDEPlugin) {
|
||||
// 改变路由地址 返回的时候会清掉
|
||||
// Change the routing address and it will be cleared when returning.
|
||||
preloadIDE?.handleShowIde({
|
||||
initialAction: InitialAction.CREATE_TOOL,
|
||||
toolId: '',
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ export interface PluginModalContentProps extends PluginModalModeProps {
|
|||
setQuery: (value: Partial<PluginQuery>, refreshPage?: boolean) => void;
|
||||
}
|
||||
export type PluginModalContentListItem = PluginInfoForPlayground & {
|
||||
// 当前数据属于列表的第几页
|
||||
// The current data belongs to the page of the list
|
||||
belong_page?: number;
|
||||
};
|
||||
|
||||
|
|
@ -99,7 +99,7 @@ export const PluginModalContent: FC<PluginModalContentProps> = ({
|
|||
onCopyPluginCallback,
|
||||
clickProjectPluginCallback,
|
||||
}) => {
|
||||
// 状态hook
|
||||
// Status hook
|
||||
const {
|
||||
type,
|
||||
mineActive,
|
||||
|
|
@ -112,9 +112,9 @@ export const PluginModalContent: FC<PluginModalContentProps> = ({
|
|||
pluginType,
|
||||
} = query;
|
||||
const id = useSpaceStore(store => store.space.id);
|
||||
// scroll的container
|
||||
// Scroll container
|
||||
const scrollContainerRef = useRef<HTMLDivElement | null>(null);
|
||||
// 当前active的key
|
||||
// Currently active key
|
||||
const [activeKey, setActivekey] = useState<string | string[] | undefined>([]);
|
||||
const refInfiniteScroll = useRef<InfiniteListRef>(null);
|
||||
const {
|
||||
|
|
@ -140,10 +140,10 @@ export const PluginModalContent: FC<PluginModalContentProps> = ({
|
|||
nodes: state.nodes,
|
||||
})),
|
||||
);
|
||||
// 首次effect不执行,这个是切换状态的effect
|
||||
// The first effect is not executed, this is the effect of switching the state
|
||||
useUpdateEffect(() => {
|
||||
scroll2Top(); // 当筛选项改变时,回到顶部
|
||||
// 只要是query中非page改变,就执行此effect
|
||||
scroll2Top(); // When the filter item changes, return to the top
|
||||
// Perform this effect whenever a non-page change is made in the query
|
||||
}, []);
|
||||
return (
|
||||
<UICompositionModalMain>
|
||||
|
|
|
|||
|
|
@ -53,24 +53,24 @@ export interface UsePluginModalPartsProp extends PluginModalModeProps {
|
|||
}
|
||||
|
||||
/**
|
||||
* 获取初始化类型
|
||||
* @param from 来源
|
||||
* @param spaceType 空间类型
|
||||
* @returns 初始化类型
|
||||
* Get initialization type
|
||||
* @Param from source
|
||||
* @param spaceType
|
||||
* @Returns initialization type
|
||||
*/
|
||||
const getInitType = (from?: From, spaceType?: SpaceType) => {
|
||||
// 项目workflow引用插件,默认选中项目插件
|
||||
// Project workflow reference plug-in, the project plug-in is selected by default
|
||||
if (from === From.ProjectWorkflow) {
|
||||
return '';
|
||||
}
|
||||
if (from !== From.ProjectIde || !spaceType || !from) {
|
||||
return '';
|
||||
}
|
||||
// projectIDE下,并且是个人空间,选中Mine
|
||||
// Under projectIDE, and it is personal space, select Mine.
|
||||
if (spaceType === SpaceType.Personal) {
|
||||
return PluginFilterType.Mine;
|
||||
}
|
||||
// projectIDE下,并且是团队空间,选中Team
|
||||
// Under projectIDE, and is a team space, select Team
|
||||
if (spaceType === SpaceType.Team && from === From.ProjectIde) {
|
||||
return PluginFilterType.Team;
|
||||
}
|
||||
|
|
@ -94,7 +94,7 @@ export const usePluginModalParts = ({
|
|||
hideCreateBtn,
|
||||
initQuery,
|
||||
}: UsePluginModalPartsProp) => {
|
||||
// 获取devId
|
||||
// Get devId
|
||||
const userInfo = userStoreService.useUserInfo();
|
||||
const spaceType = useSpaceStore(store => store.space.space_type);
|
||||
const [query, setQuery] = useState<PluginQuery>({
|
||||
|
|
@ -103,14 +103,14 @@ export const usePluginModalParts = ({
|
|||
devId: userInfo?.user_id_str || '',
|
||||
search: '',
|
||||
page: DEFAULT_PAGE,
|
||||
// 项目IDE插件仅展示我的插件
|
||||
// Project IDE plugins only show my plugins
|
||||
type: initQuery?.type ?? getInitType(from, spaceType),
|
||||
orderBy: OrderBy.CreateTime,
|
||||
orderByPublic: SortType.Heat,
|
||||
orderByFavorite: SortType.Newest,
|
||||
mineActive: MineActiveEnum.All,
|
||||
isOfficial: initQuery?.isOfficial ?? undefined,
|
||||
// project workflow添加插件,只展示云插件
|
||||
// Add plugins to project workflow, only show cloud plugins
|
||||
pluginType:
|
||||
from === From.ProjectWorkflow ? PluginType.CLoudPlugin : undefined,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -85,11 +85,11 @@ export const PluginModalSider: FC<PluginModalSiderProp> = ({
|
|||
maxLength={MAX_SEARCH_LENGTH}
|
||||
onSearch={search => {
|
||||
if (!search) {
|
||||
// 如果search清空了,那么立即更新query
|
||||
// If the search is empty, update the query immediately
|
||||
cancel();
|
||||
updateSearchQuery(search);
|
||||
} else {
|
||||
// 如果search有值,那么防抖更新
|
||||
// If search has a value, then anti-shake update
|
||||
debounceChangeSearch(search);
|
||||
}
|
||||
}}
|
||||
|
|
@ -102,7 +102,7 @@ export const PluginModalSider: FC<PluginModalSiderProp> = ({
|
|||
className={s.addbtn}
|
||||
theme="solid"
|
||||
onClick={() => {
|
||||
// TODO: 其他场景应该也统一创建方式,如果创建成功回调存在,则打开插件modal,否则打开新tab
|
||||
// TODO: Other scenes should also be created in a unified way. If the creation success callback exists, open the plugin modal, otherwise open a new tab.
|
||||
if (
|
||||
onCreateSuccess &&
|
||||
(from === From.ProjectIde || from === From.ProjectWorkflow)
|
||||
|
|
|
|||
|
|
@ -169,7 +169,7 @@ export function useInfiniteScrollCacheLoad<
|
|||
] = true;
|
||||
});
|
||||
|
||||
//数据去重
|
||||
//Data deduplicated
|
||||
const uniqList = (list || []).filter(item => {
|
||||
const pluginId = (item as unknown as { pluginInfo: { id: string } })
|
||||
?.pluginInfo?.id;
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue