chore: replace all cn comments of fe to en version by volc api (#320)

This commit is contained in:
tecvan
2025-07-31 10:32:15 +08:00
committed by GitHub
parent 716ec0cba8
commit 71f6245a01
2960 changed files with 15545 additions and 15545 deletions

View File

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

View File

@@ -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) &&

View File

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

View File

@@ -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', {

View File

@@ -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'],
}}
/>

View File

@@ -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,
},

View File

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

View File

@@ -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,
});

View File

@@ -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 }) => {

View File

@@ -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={

View File

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

View File

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

View File

@@ -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>()(

View File

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

View File

@@ -37,7 +37,7 @@ export interface OnboardingDirtyLogicCompatibilityAction {
}
/**
* 用来处理 bot 编辑页 onboarding 的复杂、脏业务逻辑
* Complex, dirty business logic for handling bot edit page onboarding
*/
export const createOnboardingDirtyLogicCompatibilityStore = () =>
create<

View File

@@ -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, []];

View File

@@ -41,7 +41,7 @@ export function convertModelValueType(
return Number(value);
}
// 理论上不走这里
// Theoretically not going here
primitiveExhaustiveCheck(type);
return value;
}

View File

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

View File

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

View File

@@ -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({

View File

@@ -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');
});

View File

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

View File

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

View File

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

View File

@@ -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' }}

View File

@@ -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();
}

View File

@@ -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();
}

View File

@@ -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)}

View File

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

View File

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

View File

@@ -78,8 +78,8 @@ const useAuthForApiTool = () => {
return {
canEdit,
needAuth, // 需要 auth 授权
isHasAuth, // 是否完成了授权
needAuth, // Requires auth authorization
isHasAuth, // Has the authorization been completed?
doCancelOauth,
isUpdateLoading,
doOauth,

View File

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

View File

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

View File

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

View File

@@ -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({

View File

@@ -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: '',

View File

@@ -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);
// scrollcontainer
// Scroll container
const scrollContainerRef = useRef<HTMLDivElement | null>(null);
// 当前activekey
// 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>

View File

@@ -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,
});

View File

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

View File

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

View File

@@ -61,9 +61,9 @@ export const CreateCodePluginModal: React.FC<CreatePluginProps> = props => {
const [openApi, setOpenApi] = useState<string | undefined>();
useEffect(() => {
/** 每次打开重置弹窗数据 */
/** Reset pop-up data every time you open it */
if (visible) {
//格式化json
//Format json
const desc = JSON.stringify(
safeJSONParse(editInfo?.code_info?.plugin_desc),
null,

View File

@@ -114,7 +114,7 @@ export const CreateFormPluginModal: FC<CreatePluginFormProps> = props => {
return;
}
if (visible) {
// 显示后滚动条滑动到最上边
// Scroll bar after display to top
const modalContent = document.querySelector(
'.create-plugin-modal-content .semi-modal-body',
);
@@ -122,7 +122,7 @@ export const CreateFormPluginModal: FC<CreatePluginFormProps> = props => {
modalContent.scrollTop = 0;
}
} else {
// 隐藏后重置表单
// Reset form after hiding
formApi?.current?.reset();
}
}, [visible]);

View File

@@ -167,7 +167,7 @@ export const FileUpload = ({ onUpload, disabled }: FileUploadProps) => {
onChange={({ fileList: list }) => {
setFileList(list);
if (!list.length) {
// 清空content
// Clear content
onUpload();
}
}}

View File

@@ -121,7 +121,7 @@ export const ImportPluginModalContent: React.FC<
__disableErrorToast: true,
});
// 解析string
// Parse string
const result = parsePluginInfo({
aiPlugin: ai_plugin,
openAPI: openapi,

View File

@@ -146,17 +146,17 @@ const HeaderList = ({
value?: commonParamSchema[];
onChange?: (val?: commonParamSchema[]) => void;
}) => {
/** 添加header */
/** Add header */
// @ts-expect-error -- linter-disable-autofix
const addHeader = data => {
const h = [...headerList];
h.push(data.name ? data : { name: '', value: '' });
setHeaderList?.(h);
};
/** 删除header */
/** Delete header */
// @ts-expect-error -- linter-disable-autofix
const deleteHeader = index => {
// 若为最后一个header则只清空内容不删除
// If it is the last header, only empty the content, not delete it
const filterList = cloneDeep(headerList);
filterList.splice(index, 1);
setHeaderList?.(filterList);
@@ -401,7 +401,7 @@ export const ServiceField = ({ disabled }: PluginInfoFormFieldProps) => {
);
};
// extItems 动态下发
// extItems dynamic delivery
export const ExtItems = ({
disabled,
extItems,
@@ -410,7 +410,7 @@ export const ExtItems = ({
const formValues = formApi.getValues();
return (
<>
{/* 服务端动态返回授权项 */}
{/* Server level dynamic return authorization */}
{extItems?.map(item => (
<>
{disabled ? (

View File

@@ -77,8 +77,8 @@ const INITIAL_FORM_VALUES = {
};
/**
文件导入plugin确认信息弹窗目前和普通创建导入很像调用接口不一样
目前感觉这个确认形式不太友好,后续不太确定优化形态,所以新建单独文件处理,以防污染bot-form-edit
File import plugin confirmation information pop-up window, currently very similar to ordinary creation and import, the call interface is different.
At present, I feel that this confirmation form is not very friendly, and I am not sure about the optimization form in the future, so a new separate file is created to prevent contamination of bot-form-edit.
*/
// eslint-disable-next-line complexity
@@ -93,7 +93,7 @@ export const PluginInfoConfirm: React.FC<PluginInfoConfirmProps> = props => {
} = props;
const [authOption, setAuthOption] = useState<AuthOption[]>([]);
// 合规审核结果
// Compliance audit results
const [isValidCheckResult, setIsValidCheckResult] = useState(true);
const [extItems, setExtItems] = useState<OauthTccOpt[]>([]);
@@ -121,7 +121,7 @@ export const PluginInfoConfirm: React.FC<PluginInfoConfirmProps> = props => {
useEffect(() => {
if (importInfo) {
//更新插件
//update plugin
setExtItems(
findAuthTypeItem(
authOption,
@@ -279,7 +279,7 @@ export const PluginInfoConfirm: React.FC<PluginInfoConfirmProps> = props => {
>
{({ values }) => (
<>
{/* 插件头像 */}
{/* plugin avatar */}
<PictureUpload
noLabel
disabled={disabled}
@@ -288,13 +288,13 @@ export const PluginInfoConfirm: React.FC<PluginInfoConfirmProps> = props => {
iconType={IconType.Plugin}
fileBizType={FileBizType.BIZ_PLUGIN_ICON}
/>
{/* 插件名称/插件描述/插件URL */}
{/* Plugin Name/Plugin Description/Plugin URL */}
<PluginNameField disabled={disabled} />
<PluginDescField disabled={disabled} />
<PluginUrlField disabled={true} />
{/* 插件Header */}
{/* Plugin Header */}
<HeaderListField disabled={disabled} />
{/* 授权方式 */}
{/* Authorization method */}
<AuthTypeField
disabled={disabled}
authOption={authOption}
@@ -304,12 +304,12 @@ export const PluginInfoConfirm: React.FC<PluginInfoConfirmProps> = props => {
);
}}
/>
{/* 授权方式-Service */}
{/* Authorization method-Service */}
{values.auth_type.at(-1) === 1 && (
<ServiceField disabled={disabled} />
)}
<ExtItems disabled={disabled} extItems={extItems} />
{/* 协议 */}
{/* agreement */}
{!disabled && (
<Space spacing={8} className={s['footer-draft']}>
<IconInfoCircle

View File

@@ -31,7 +31,7 @@ export const formRuleList = {
message: I18n.t('create_plugin_modal_nameerror'),
}
: {
pattern: /^[\w\s\u4e00-\u9fa5]+$/u, //
pattern: /^[\w\s\u4e00-\u9fa5]+$/u, // Increased domestic support for Chinese
message: I18n.t('create_plugin_modal_nameerror_cn'),
},
],
@@ -95,7 +95,7 @@ export interface AuthOption {
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- any
[key: string]: any;
}
/** 递归寻找auth选项下的输入项 */
/** Recursively find the input under the auth option */
// @ts-expect-error -- linter-disable-autofix
export const findAuthTypeItem = (data: AuthOption[], targetKey = 0) => {
for (const item of data) {

View File

@@ -120,7 +120,7 @@ export async function getContent(file: Blob, onProgress): Promise<string> {
}
export function isValidURL(str?: string): boolean {
// 缩略版
// abbreviated version
try {
const objExp = new RegExp(
'^(https?:\\/\\/)?' + // protocol
@@ -137,7 +137,7 @@ export function isValidURL(str?: string): boolean {
}
export async function customService(url: string) {
// 这里需要自定义请求需要引入axios
// Custom requests are required here, and axios needs to be introduced.
const axiosInstance = axios.create({ responseType: 'text' });
const response = await axiosInstance.get(url);

View File

@@ -249,8 +249,8 @@ describe('useMockSetInSettingModalController', () => {
await waitForNextUpdate();
expect(result.current.isEnabled).toBeFalsy(); // 初始状态应该是不启用
expect(result.current.mockSetData).toEqual([]); // 初始mockSetData应该是空数组
expect(result.current.isEnabled).toBeFalsy(); // The initial state should be not enabled
expect(result.current.mockSetData).toEqual([]); // The initial mockSetData should be an empty array
});
it('should act export action', async () => {
@@ -260,25 +260,25 @@ describe('useMockSetInSettingModalController', () => {
await waitForNextUpdate();
expect(result.current.isEnabled).toBeTruthy(); // 有选中的mock数据的前提下会自动启用
expect(result.current.mockSetData.length).toEqual(7); // mockSetData 数据是 7
expect(result.current.isEnabled).toBeTruthy(); // If there is selected mock data, it will be automatically enabled
expect(result.current.mockSetData.length).toEqual(7); // mockSetData is 7.
act(() => result.current.doSetCreateModal(true));
expect(result.current.showCreateModal).toBeTruthy(); // 打开创建modal
expect(result.current.showCreateModal).toBeTruthy(); // Open Create modal
act(() => result.current.doHandleView({ id: 'record-id' })); // 点击查看
act(() => result.current.doHandleView({ id: 'record-id' })); // Click to view
act(() => result.current.doEnabled()); // 关闭
expect(result.current.isEnabled).toBeFalsy(); // 禁用
act(() => result.current.doEnabled()); // close
expect(result.current.isEnabled).toBeFalsy(); // disable
act(() => result.current.doSetDeleteId('record-id')); // 删除
act(() => result.current.doSetDeleteId('record-id')); // delete
expect(result.current.deleteRenderTitle).toBe(
'Translated: delete_the_mockset {}',
); // 删除后应该显示删除的title
); // The deleted title should be displayed after deletion.
act(() => result.current.doConfirmDelete()); // 确认删除
act(() => result.current.doConfirmDelete()); // Confirm deletion
act(() => result.current.doChangeMock({ id: 'change-mock' })); // 修改mock
expect(result.current.selectedMockSet).toStrictEqual({ id: 'change-mock' }); // 修改mock后应该显示新的mock
act(() => result.current.doChangeMock({ id: 'change-mock' })); // Modify mock
expect(result.current.selectedMockSet).toStrictEqual({ id: 'change-mock' }); // After modifying the mock, the new mock should be displayed.
});
});

View File

@@ -92,7 +92,7 @@ describe('useSaveMockData', () => {
const { result } = renderHook(() =>
useSaveMockData({
mockSetId: undefined, // 测试没有mockSetId的情况
mockSetId: undefined, // Test without mockSetId
basicParams: {
environment: 'environment',
workspace_id: 'workspace_id',

View File

@@ -53,8 +53,8 @@ vi.mock('@coze-arch/bot-tea', () => ({
},
ParamsTypeDefine: {},
PluginMockDataGenerateMode: {
MANUAL: 0, // 手动创建
RANDOM: 1, // 随机生成
MANUAL: 0, // create manually
RANDOM: 1, // random generation
LLM: 2,
},
}));
@@ -62,21 +62,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({

View File

@@ -23,7 +23,7 @@ export const REAL_DATA_MOCKSET = {
name: I18n.t('real_data'),
};
// 初始化仅有real_data
// Initialization only real_data
export const MOCK_OPTION_LIST = [REAL_DATA_MOCKSET];
export const POLLING_INTERVAL = 10000;

View File

@@ -146,7 +146,7 @@ export const useInitialGetEnabledMockSet = ({
}
};
// 取消
// cancel
const cancel = () => {
pollingTurnRef.current = undefined;
cancelReq.current?.();

View File

@@ -94,11 +94,11 @@
line-height: 16px;
}
/** 创建框 **/
/** Create box **/
.mock-creation-modal {
:global {
.semi-modal-content .semi-modal-body {
/** 保证内部 tooltip 不被遮盖 **/
/** Make sure the internal tooltip is not covered **/
overflow: unset
}
@@ -114,7 +114,7 @@
}
div.mock-creation-modal-editor {
/** 兼容 modal 在小窗口下 body 高度不生效的问题 */
/** Compatible modal body height does not take effect in small windows */
height: calc(100vh - 316px);
max-height: 500px;
}

View File

@@ -46,7 +46,7 @@ interface MockDataCardProps {
bizCtx: infra.BizCtx;
}
/** mock data 展示卡片 */
/** Mock data display card */
export function MockDataCard({
mock,
readOnly,

View File

@@ -55,18 +55,18 @@ import { useSaveMockData } from '../hook/use-save-mock-data';
import s from './index.module.less';
export enum CreationMode {
/** 弹窗形式 */
/** pop-up window */
MODAL = 'modal',
/** 嵌入页面 */
/** embed page */
CARD = 'card',
}
interface MockDataCreateCardProps {
mode: CreationMode;
mockInfo?: MockDataInfo;
// mode 为 modal 时生效
// Effective when modal mode
visible?: boolean;
// mode 为 modal 时生效
// Effective when modal mode
onCancel?: () => void;
onSuccess: (data?: mockset.MockRule[]) => void;
bizCtx: infra.BizCtx;
@@ -76,7 +76,7 @@ interface MockDataCreateCardProps {
};
}
/** 创建or编辑 mock data - */
/** Create or edit mock data - */
export function MockDataCreateCard({
mode,
mockInfo,
@@ -96,7 +96,7 @@ export function MockDataCreateCard({
useTransSchema(schema);
const { mock_set_id, tool_id } = useParams<DynamicParams>();
// space信息
// Space information
const spaceType = useSpaceStore(store => store.space.space_type);
const isPersonal = spaceType === SpaceType.Personal;

View File

@@ -91,7 +91,7 @@ export const MockDataList = forwardRef(
const [deleteModalVisible, setDeleteModalVisible] =
useState<boolean>(false);
const [deleting, setDeleting] = useState<boolean>(false);
// 当前选中状态
// Currently selected
const [currentSelect, setCurrentSelect] = useState<
MockDataInfo | undefined
>();
@@ -99,7 +99,7 @@ export const MockDataList = forwardRef(
const routeResponse = usePageJumpResponse(PageType.PLUGIN_MOCK_DATA);
const { mock_set_id, space_id, tool_id } = useParams<DynamicParams>();
// space信息
// Space information
const spaceType = useSpaceStore(store => store.space.space_type);
const isPersonal = spaceType === SpaceType.Personal;
@@ -113,7 +113,7 @@ export const MockDataList = forwardRef(
setDeleteModalVisible(true);
};
// 获取当前 mock set 下的 mock data
// Get the mock data under the current mock set
const getMockData = async (needScrollToTop?: boolean) => {
try {
setLoading(true);
@@ -181,11 +181,11 @@ export const MockDataList = forwardRef(
}
};
// 前端更新
// frontend update
const updateList = (data: MockRule, action: RuleActions) => {
let len = 0;
if (action === RuleActions.CREATE) {
// 创建场景直接 force update
// Create scenes to force updates directly
getMockData(true);
} else if (action === RuleActions.DELETE) {
len = mockDataList.length - 1;
@@ -228,7 +228,7 @@ export const MockDataList = forwardRef(
useEffect(() => {
if (routeResponse?.generationMode) {
// 清除跳转参数
// Clear jump parameters
const state = {
...history.state,
usr: { ...(history.state.usr || {}), generationMode: undefined },

View File

@@ -42,12 +42,12 @@ export function MockSetPageBreadcrumb({
}: MockSetPageBreadcrumbProps) {
const routeResponse = usePageJumpResponse(PageType.PLUGIN_MOCK_DATA);
// 插件详情
// plugin details
const [pluginInfo, setPluginInfo] = useState<PluginMetaInfo>({
name: routeResponse?.pluginName,
});
// 获取当前 plugin 信息
// Get current plugin information
const getPluginInfo = async () => {
try {
const res = await DeveloperApi.GetPluginInfo(

View File

@@ -162,7 +162,7 @@ const MockSetSelectComp = (
const bizCtx: BizCtx = {
...bizSceneCtx,
connectorUID: uid,
connectorID: CONNECTOR_ID, // 业务线为Coze
connectorID: CONNECTOR_ID, // Business line for Coze
};
const { jump } = usePageJumpService();
@@ -449,7 +449,7 @@ const MockSetSelectComp = (
content={getTooltipInfo()}
visible={disabled && focused}
position="left"
style={{ display: disabled ? 'block' : 'none' }} // visible disabled不生效
style={{ display: disabled ? 'block' : 'none' }} // Visible disabled not effective
>
<div
style={style}

View File

@@ -71,7 +71,7 @@ export const MockSetDeleteModal = ({
} = mockSetInfo || {};
const [mockSetRefCount, setMockSetRefCount] = useState(-1);
// space信息
// Space information
const spaceType = useSpaceStore(s => s.space.space_type);
const isPersonal = spaceType === SpaceType.Personal;

View File

@@ -31,7 +31,7 @@ export enum BranchType {
type BranchInfo = Record<
string,
| {
// 纵向连接线
// Longitudinal cable
v: BranchType[];
isLast: boolean;
}
@@ -42,7 +42,7 @@ export function useGenTreeBranch(mockData?: MockDataWithStatus) {
const [branchInfo, setBranchInfo] = useState<BranchInfo>({});
const [pruned, setPruned] = useState<MockDataWithStatus>();
// 裁剪树枝
// Cut branches
// @ts-expect-error -- linter-disable-autofix
const pruning = (data?: MockDataWithStatus) => {
if (!data?.children) {

View File

@@ -89,7 +89,7 @@ const useMockSetInSettingModalController = ({
() => ({
...bizSceneCtx,
connectorUID: uid,
connectorID: CONNECTOR_ID, // 业务线为Coze
connectorID: CONNECTOR_ID, // Business line for Coze
}),
[bizSceneCtx, uid, CONNECTOR_ID],
);

View File

@@ -123,7 +123,7 @@ export function useSaveMockData({
}
if (successRes.length === 0) {
// 仅全部失败时认为失败,此时需要 toast 提示
// Only if all fail, it is considered a failure, and a toast prompt is required at this time.
Toast.error({
content: withSlardarIdButton(
failRes[0]?.error?.message || I18n.t('error'),

View File

@@ -30,7 +30,7 @@ import {
import { getMergedDataWithStatus } from '../util/utils';
/** 缓存最新一个解析结果 */
/** cache the latest parsing result */
const cache: {
schema: string;
result: MockDataWithStatus | undefined;
@@ -92,7 +92,7 @@ export function useTransSchema(schema?: string, currentMock?: string) {
}
}, [result, currentMock]);
// 特殊字段需要单独处理response_for_model 不能为空字符串
// Special fields need to be handled separately: response_for_model cannot be an empty string
const testValueValid = useCallback(
(value: string) => {
if (
@@ -118,17 +118,17 @@ export function useTransSchema(schema?: string, currentMock?: string) {
);
return {
// 由 schema 生成的结构话数据,值为初始值
// Structured data generated by schema with initial values
result,
// 合并模拟数据的结构话数据,全集
// Structural session data that merges simulated data, complete set
mergedResult,
// mergedResult 转换的 object
// mergedResult converted object
mergedResultExample,
// 格式化的数据
// formatted data
formattedResultExample,
// 是否兼容
// Is it compatible?
incompatible,
// 是否合并模拟数据
// Whether to merge analog data
isInit: currentMock === undefined,
testValueValid,
};

View File

@@ -34,23 +34,23 @@ export enum MockDataStatus {
export interface MockDataWithStatus {
/** key */
key: string;
/** 字段名称 */
/** field name */
label: string;
/** 字段值 */
/** field value */
realValue?: string | number | boolean;
/** 展示使用 */
/** display use */
displayValue?: string;
/** 描述 */
/** describe */
description?: string;
/** 是否必填 */
/** Is it required? */
isRequired: boolean;
/** 字段数据类型 */
/** field data type */
type: MockDataValueType;
/** for array */
childrenType?: MockDataValueType;
/** 字段状态 */
/** Field Status */
status: MockDataStatus;
/** 字段子节点 */
/** Field sub-node */
children?: MockDataWithStatus[];
}

View File

@@ -29,7 +29,7 @@ export function transUpperCase(str?: string) {
return str ? `${str.slice(0, 1).toUpperCase()}${str.slice(1)}` : '';
}
// 仅开发中使用
// Only used in development
export function sleep(t = 1000) {
return new Promise(r => {
setTimeout(() => {
@@ -46,7 +46,7 @@ export function safeJSONParse<T>(str: string, errCb?: () => T | undefined) {
}
}
// 根据 value 生成 displayValue
// Generate displayValue from value
function getTargetValue(
type: MockDataValueType,
value: string | number | boolean | undefined,
@@ -58,10 +58,10 @@ function getTargetValue(
});
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- plugin resp 的类型由用户定义,包含任何可能
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- The type of the plugin resp is user-defined and contains any possible
type PluginRespType = any;
// 合并 schema mock data
// Merge schema and mock data
export function getMergedDataWithStatus(
schemaData?: MockDataWithStatus,
currentMock?: string,
@@ -84,12 +84,12 @@ export function getMergedDataWithStatus(
? safeJSONParse<PluginRespType>(currentMock) || currentMock
: currentMock;
// mock 转换为 MockDataWithStatus 格式
// Convert mock to MockDataWithStatus format
const processedMock = transMockData2DataWithStatus(ROOT_KEY, mock, {
defaultStatus: MockDataStatus.REMOVED,
});
// 合并
// merge
const { merged, incompatible } = mergeDataWithStatus(
schemaData.children,
processedMock?.children,
@@ -105,7 +105,7 @@ export function getMergedDataWithStatus(
};
}
// 解析当前 realValue 所属于的 MockDataValueType
// Parse the MockDataValueType to which the current realValue belongs
function getMockDataType(currentMock: PluginRespType) {
let dataTypeName = typeof currentMock as MockDataValueType | undefined;
if (currentMock instanceof Array) {
@@ -118,7 +118,7 @@ function compareMockDataType(
mockDataType?: MockDataValueType,
initDataType?: MockDataValueType,
) {
// mock data 的类型是根据值识别出的,存在 Integer 类型被识别为 Number 的情况
// The type of mock data is recognized by value, and there are cases where the Integer type is recognized as Number.
if (mockDataType === MockDataValueType.NUMBER) {
return (
initDataType === MockDataValueType.NUMBER ||
@@ -129,7 +129,7 @@ function compareMockDataType(
}
}
// 转换 Object 格式到 DataWithStatus 格式
// Convert Object format to DataWithStatus format
export function transMockData2DataWithStatus(
label: string,
currentMock: PluginRespType,
@@ -262,8 +262,8 @@ function merge2DataList(
}
}
// 在合并 array 时,会出现 autoInitDataList(originData) 中只存在一个初始化数据,而 mockDataListWithStatus(appendData) 存在多个相同结构的数据
// 需要将 mockDataListWithStatus 中剩余的数据进行合入
// When combining arrays, it appears that only one initialization data exists in autoInitDataList (originData), while mockDataListWithStatus (appendData) has multiple data of the same structure
// The remaining data in the mockDataListWithStatus needs to be incorporated
if (appendData.length && isArrayType) {
const target = autoInitDataList[0];
appendData.forEach(item => {
@@ -285,7 +285,7 @@ function merge2DataList(
};
}
// 合并两个 MockDataWithStatus 数组,以 autoInitDataList 顺序优先
// Merge two MockDataWithStatus arrays, in autoInitDataList order first
export function mergeDataWithStatus(
autoInitDataList?: MockDataWithStatus[],
mockDataListWithStatus?: MockDataWithStatus[],
@@ -301,7 +301,7 @@ export function mergeDataWithStatus(
};
}
// 在合并 array 时,存在 mockDataListWithStatus 为空的情况,此时直接判断
// When merging the array, there is a situation where the mockDataListWithStatus is empty. At this time, it is directly judged
if (mockDataListWithStatus.length === 0 && isArrayType) {
return {
merged: [],

View File

@@ -31,7 +31,7 @@ interface RiskAction {
const initialStore: RiskStore = {
pluginRiskIsRead: true,
toolHiddenModeNewbieGuideIsRead: true,
// 支持扩展其它风险提示...
// Support for expanding other risk alerts...
};
export const useRiskWarningStore = create<RiskStore & RiskAction>()(

View File

@@ -93,6 +93,6 @@ describe('useParametersInSettingModalController', () => {
result.current.doUpdateParams();
});
expect(result.current.isUpdateLoading).toBe(false); // 假设更新完成后isUpdateLoading为false
expect(result.current.isUpdateLoading).toBe(false); // Assuming isUpdateLoading is false after the update is complete
});
});

View File

@@ -75,7 +75,7 @@ describe('findPathById', () => {
});
describe('addDepthAndValue', () => {
// 测试 1验证函数是否正常工作
// Test 1: Verify that the function is working properly
it('should add depth to each node in the tree', () => {
const tree = [{ id: 1, sub_parameters: [{ id: 2 }, { id: 3 }] }, { id: 4 }];
addDepthAndValue(tree);
@@ -85,14 +85,14 @@ describe('addDepthAndValue', () => {
expect(tree[1].deep).toEqual(1);
});
// 测试 2验证函数在空树情况下是否正常工作
// Test 2: Verify that the function works properly in the empty tree case
it('should not fail on empty trees', () => {
const tree: any[] = [];
addDepthAndValue(tree);
expect(tree).toEqual([]);
});
// 测试 3验证函数在只有一个节点的树情况下是否正常工作
// Test 3: Verify that the function works properly in a tree with only one node
it('should handle single-node trees', () => {
const tree = [{ id: 1 }];
addDepthAndValue(tree);
@@ -114,7 +114,7 @@ describe('handleDeepArr', () => {
const deepArr = [];
handleDeepArr(tree, deepArr);
// 断言
// assert
expect(deepArr).toEqual([1, 2, 3, 4, 5]);
});
});
@@ -130,7 +130,7 @@ describe('maxDeep', () => {
},
];
// 测试 tree1 的最大深度
// Test the maximum depth of tree1
expect(maxDeep(tree1)).toEqual(5);
});
@@ -138,10 +138,10 @@ describe('maxDeep', () => {
const tree2 = [];
const tree3 = [{ deep: 1 }];
// 测试空树的最大深度
// Test the maximum depth of an empty tree
expect(maxDeep(tree2)).toEqual(0);
// 测试只有一个节点的树的最大深度
// Test the maximum depth of a tree with only one node
expect(maxDeep(tree3)).toEqual(1);
});
});
@@ -174,9 +174,9 @@ describe('deleteNode', () => {
const result = deleteNode(data, targetKey);
// 断言删除成功
// Asserts successful deletion
expect(result).toBe(true);
// 断言目标节点已删除
// Asserts that the target node has been deleted
expect(data.find(node => node.id === targetKey)).toBeUndefined();
});
@@ -191,7 +191,7 @@ describe('deleteNode', () => {
const result = deleteNode(data, targetKey);
// 断言删除失败
// Assertion deletion failed
expect(result).toBe(false);
});
@@ -212,11 +212,11 @@ describe('deleteNode', () => {
const result = deleteNode(data, targetKey);
// 断言删除成功
// Asserts successful deletion
expect(result).toBe(true);
// 断言目标节点已删除
// Asserts that the target node has been deleted
expect(data.find(node => node.id === targetKey)).toBeUndefined();
// 断言子节点已删除
// Asserts that the sub-node has been deleted
expect(data[1].sub_parameters.length).toBe(0);
});
});
@@ -273,7 +273,7 @@ describe('deleteAllChildNode', () => {
});
describe('updateNodeById', () => {
// 创建测试数据
// Create test data
const data = [
{
id: '1',
@@ -291,10 +291,10 @@ describe('updateNodeById', () => {
const field = 'name';
const value = 'Updated Node';
// 调用被测试的函数
// Call the function under test
updateNodeById({ data, targetKey, field, value });
// 验证节点数据是否已更新
// Verify that the node data has been updated
expect(data[1].name).toEqual(value);
});
@@ -303,7 +303,7 @@ describe('updateNodeById', () => {
const field = 'name';
const value = 'Updated Node';
// 调用被测试的函数
// Call the function under test
updateNodeById({ data, targetKey, field, value });
expect(data[0].sub_parameters[1].name).toEqual(value);
});
@@ -351,7 +351,7 @@ describe('findTemplateNodeByPath', () => {
describe('transformTreeToObj', () => {
it('should convert a tree to an object', () => {
// 创建一个树结构的参数数组
// Create a tree-structured array of parameters
const tree = [
{
name: 'stringParam',
@@ -397,10 +397,10 @@ describe('transformTreeToObj', () => {
},
];
// 调用函数并将结果存储在变量 obj
// Call the function and store the result in the variable obj
const obj = transformTreeToObj(tree);
// 检查转换后的对象是否具有正确的属性和值
// Checking whether the converted object has the correct properties and values
expect(obj).toEqual({
stringParam: 'Hello, World!',
numberParam: 42,

View File

@@ -36,13 +36,13 @@ export const InfoPopover: React.FC<InfoPopoverProps> = props => {
className="!max-w-[320px]"
content={data?.map((item, index) => (
<Fragment key={`${item.type}${index}`}>
{/* 加粗标题 */}
{/* bold title */}
{item.type === 'title' ? (
<Typography.Text fontSize="14px" className="dark coz-fg-primary">
{item.text}
</Typography.Text>
) : null}
{/* 文本 */}
{/* Text */}
{item.type === 'text' ? (
<Typography.Paragraph
fontSize="12px"
@@ -51,9 +51,9 @@ export const InfoPopover: React.FC<InfoPopoverProps> = props => {
{item.text}
</Typography.Paragraph>
) : null}
{/* 换行 */}
{/* line feed */}
{item.type === 'br' ? <div className="h-[8px]" /> : null}
{/* 示例,边框内展示 */}
{/* Example, display inside the border */}
{item.type === 'demo' ? (
<div className="dark mt-[4px] p-[10px] border border-solid coz-stroke-primary">
<Typography.Paragraph

View File

@@ -96,7 +96,7 @@ export const useBaseInfo = ({
formRef.current?.formApi.setValue('desc', desc);
});
// 提交基础信息
// Submit basic information
const submitBaseInfo = async () => {
const status = await formRef.current?.formApi
.validate()

View File

@@ -110,7 +110,7 @@ export const useBaseMore = ({
baseInfo.api_extend?.auth_mode,
]);
// 提交基础信息
// Submit basic information
const submitBaseInfo = async () => {
const status = await formRef.current?.formApi
.validate()

View File

@@ -73,7 +73,7 @@ export const CascaderItem: FC<CProps> = ({
// @ts-expect-error -- linter-disable-autofix
const isObjectField = (record.deep ?? 0) > 1 && record.name !== ARRAYTAG;
// 通过check触发校验提交时
// Trigger validation via check (when committed)
useEffect(() => {
if (check === 0) {
return;
@@ -81,7 +81,7 @@ export const CascaderItem: FC<CProps> = ({
handleCheck(value);
}, [check]);
// 校验
// validation
const handleCheck = (val?: CascaderValueType) => {
const status = !val?.[0] ? 1 : 0;
setErrorStatus(status);

View File

@@ -92,7 +92,7 @@ export const FileUploadItem: FC<{
const { uploading, uri, url, name, type } = fileState;
/**
* 回显 只有一个url(string),需要兼容 => 不展示icon,url作为文件名
* Echo, only one url (string), need to be compatible = > do not show icon, url as file name
*/
const onlyUrlString = !!url && !uri;
const displayName = onlyUrlString ? value : name;
@@ -113,7 +113,7 @@ export const FileUploadItem: FC<{
if (uploading) {
return uploadButton;
} else if (onlyUrlString && type === FileTypeEnum.IMAGE) {
/** image不是即时上传的无法确认其为合法资源路径 */
/** The image is not uploaded immediately and cannot be confirmed as a legitimate resource path. */
icon = fileUnknownIcon;
} else if (!isImageString) {
// @ts-expect-error -- linter-disable-autofix

View File

@@ -26,16 +26,16 @@ import { FileTypeEnum } from '@coze-studio/file-kit/logic';
import { type APIParameterRecord } from './types/params';
export const childrenRecordName = 'sub_parameters'; // 子节点名称
export const ROWKEY = 'id'; // 唯一标识符
export const ARRAYTAG = '[Array Item]'; // 数组元素标识符
export const ROOTTAG = '[Root Item]'; // root为数组的标识符
export const childrenRecordName = 'sub_parameters'; // sub-node name
export const ROWKEY = 'id'; // unique device identifier
export const ARRAYTAG = '[Array Item]'; // Array element identifier
export const ROOTTAG = '[Root Item]'; // Root is the identifier of the array
export const STARTNODE = 0;
export const REQUESTNODE = 1;
export const RESPONSENODE = 2;
export const DEBUGNODE = 3;
export const ENDSTEP = 4;
// 传入方法options
// Incoming method options
export const parameterLocationOptions = [
{
label: 'Body',
@@ -57,8 +57,8 @@ export const parameterLocationOptions = [
export enum ParameterTypeExtend {
/**
* 扩展类型
* AssistParameterType 一一对应
* extension type
* One-to-one correspondence with AssistParameterType
*/
DEFAULT = 10001,
IMAGE,
@@ -93,7 +93,7 @@ interface ParameterTypeOption {
}
/**
* 未扩展File类型前的 基础类型,多处使用 需要保留 start
* The basic type before the unextended File type is used in many places, and start needs to be reserved.
*/
export const parameterTypeOptions: Array<ParameterTypeOption> = [
{
@@ -145,7 +145,7 @@ export const parameterTypeOptionsSub: Array<ParameterTypeOption> = [
},
];
/**
* 未扩展File类型前的 基础类型,多处使用 需要保留 end
* Unexpanded File type, base type, used in many places, need to keep end
*/
export const parameterTypeExtendMap: Record<
@@ -406,12 +406,12 @@ export const methodType: ExtInfoText[] = [
export enum ParamsFormErrorStatus {
NO_ERROR = 0,
NAME_EMPTY = 1,
// 中文
// Chinese
CHINESE = 2,
// 重复
// repeat
REPEAT = 3,
ASCII = 4,
// 未填写
// not filled in
DESC_EMPTY = 5,
}

View File

@@ -83,7 +83,7 @@ const ProcessContent: FC<PropsWithChildren> = ({ children }) => (
<div className={s['process-content']}>{children}</div>
);
/** stringify 缩进 */
/** Stringify indent */
const INDENTATION_SPACES = 2;
const LLMAndAPIContent: FC<{
toolMessageUnit: CheckParamsProps;

View File

@@ -36,7 +36,7 @@ import { type CheckParamsProps, STATUS } from '../types';
import s from '../index.module.less';
import ParamsForm from './params-form';
/** stringify 缩进 */
/** Stringify indent */
const INDENTATION_SPACES = 2;
const SLEEP_NUM = 100;
@@ -68,7 +68,7 @@ export const DebugParams: React.FC<{
const paramsFormRef = useRef<{ data: Array<APIParameter> }>(null);
const handleAction = async () => {
// 校验是否必填
// Verification is required
setCheck(check + 1);
await sleep(SLEEP_NUM);
const errorEle = document.getElementsByClassName('errorDebugClassTag');

View File

@@ -53,7 +53,7 @@ const InputItem = ({
}: InputItemProps): JSX.Element => {
const [value, setValue] = useState(val);
const [errorStatus, setErrorStatus] = useState(false);
// 通过check触发校验提交时
// Trigger validation via check (when committed)
useEffect(() => {
if (check === 0 || value === ARRAYTAG || value === ROOTTAG) {
return;

View File

@@ -128,7 +128,7 @@ const getParamsTitle = (isShowExampleTag: boolean, disabled: boolean) =>
)
);
// eslint-disable-next-line @coze-arch/max-line-per-function -- 已经在拆了
// eslint-disable-next-line @coze-arch/max-line-per-function -- already dismantling
const ParamsForm = (
props: ParamsFormProps,
ref: Ref<{ data: Array<APIParameter> } | null>,
@@ -160,7 +160,7 @@ const ParamsForm = (
}));
const [flag, setFlag] = useState<boolean>(false);
// 添加子节点
// Add sub-node
const addChildNode = (record: APIParameter) => {
if (!data) {
return;
@@ -168,7 +168,7 @@ const ParamsForm = (
let result: APIParameter & {
path?: Array<number>;
} = {};
// 1.查找路径
// 1. Find the path
findPathById({
data,
callback: (item: APIParameter, path: Array<number>) => {
@@ -178,16 +178,16 @@ const ParamsForm = (
},
});
// 2.拼接路径
// 2. Splicing path
const path = (result?.path || [])
.map((v: number) => [v, childrenRecordName])
.flat();
// newPath是模版的路径下面添加节点newNode可以直接从该路径引用
// newPath is the path of the template. The following node newNode can be directly referenced from this path
const newPath = findTemplateNodeByPath(resourceData, path);
// 3.添加节点
// 3. Add a node
const newData = cloneDeep(data);
if (Array.isArray(ObjectGet(newData, path))) {
// 这一步是为了根据newPath找到对应的根节点并且克隆一个新节点
// This step is to find the corresponding root node according to newPath and clone a new node
const newNode = cloneWithRandomKey(ObjectGet(resourceData, newPath)[0]);
ObjectSet(newData, path, [...ObjectGet(newData, path), newNode]);
}

View File

@@ -59,7 +59,7 @@ export const Debug: React.FC<{
debugExample?: DebugExample;
setDebugStatus?: (status: STATUS | undefined) => void;
setDebugExample?: (v: DebugExample) => void;
isViewExample?: boolean; // 查看 example 模式 标题不一样
isViewExample?: boolean; // Look at the example mode, the title is different
onSuccessCallback?: () => void;
}> = ({
disabled,
@@ -94,7 +94,7 @@ export const Debug: React.FC<{
setDebugStatus?.(innerStatus);
innerStatus === STATUS.PASS &&
setDebugExample?.({ req_example: request, resp_example: response });
// 调试成功后回调
// Callback after successful debugging
innerStatus === STATUS.PASS && onSuccessCallback?.();
};

View File

@@ -69,7 +69,7 @@ export const InputAndVariableItem = ({
onChange={val => {
onSourceChange?.(Number(val));
// 切换来源,清空默认值
// Switch source, clear default
onReferenceChange?.('');
onValueChange?.('');
}}

View File

@@ -59,7 +59,7 @@ const ParamTypeColRender: FC<ParamTypeProps> = ({
addChildNode,
enableFileType = false,
}) => {
// 删除全部子节点;
// Delete all sub-nodes;
const handleDeleteAllChildNode = (r: APIParameter) => {
const cloneData = cloneDeep(data);
const delStatus = deleteAllChildNode(cloneData, r[ROWKEY] as string);
@@ -86,7 +86,7 @@ const ParamTypeColRender: FC<ParamTypeProps> = ({
}
if (!isResponse) {
// 切换类型,重置default value
// Switch type, reset default value
if (record.global_default) {
updateNodeWithData({
record,
@@ -103,7 +103,7 @@ const ParamTypeColRender: FC<ParamTypeProps> = ({
value: [type, assistType ?? null],
};
// updateNodeWithData 会变更type类型保留原始的type
// updateNodeWithData will change the type type and keep the original type.
const recordType = record?.type;
if (type === ParameterType.Array) {

View File

@@ -89,7 +89,7 @@ const DefaultValueModal = ({
};
const handleSave = () => {
// 校验是否必填
// Verification is required
setCheck(check + 1);
const errorEle = document.getElementsByClassName('errorDebugClassTag');
if (errorEle.length > 0) {
@@ -153,8 +153,8 @@ export const DefaultValueInput = ({
data,
setData,
canReference = false,
defaultKey = 'global_default', //输入框的key
disableKey = 'global_disable', //开启按钮key
defaultKey = 'global_default', //Text box key
disableKey = 'global_disable', //Open button key
referenceOption,
}: DefaultValueInputProps) => {
// @ts-expect-error -- linter-disable-autofix
@@ -173,7 +173,7 @@ export const DefaultValueInput = ({
return <></>;
}
// 复杂类型暂不支持引用变量
// Complex types do not currently support reference variables
if (record.type === ParameterType.Array) {
return (
<div className={styles['modal-wrapper']}>

View File

@@ -60,14 +60,14 @@ export const InputItem = ({
useEffect(() => {
setValue(val);
}, [val]);
// 通过check触发校验提交时
// Trigger validation via check (when committed)
useEffect(() => {
if (check === 0 || value === ARRAYTAG || value === ROOTTAG) {
return;
}
handleCheck(value);
}, [check]);
// 校验
// validation
const handleCheck = (checkVal: string) => {
let status =
checkVal === ''
@@ -104,7 +104,7 @@ export const InputItem = ({
}
setErrorStatus(status);
};
// 过滤空格、限制输入长度
// Filter spaces, limit input length
const handleFilter = (v: string) => {
if (filterSpace) {
v = v.replace(/\s+/g, '');
@@ -122,7 +122,7 @@ export const InputItem = ({
item.type === ParameterType.Object,
)
: true;
// 每增加一层因为有展开icon宽度减少20
// Each additional layer decreases the width by 20 because of the expansion icon.
const vWidth = dynamicWidth
? `calc(100% - ${DEEP_INDENT_NUM * deep}px)`
: width;
@@ -175,7 +175,7 @@ export const InputItem = ({
}}
/>
<br />
{/* 参数名称设置动态列宽 */}
{/* Parameter name Set dynamic column width */}
{errorStatus !== 0 && dynamicWidth ? (
<div className={s['check-box']} style={{ width: tipWidth }}>
<span className={cl(s['form-check-tip'], 'errorClassTag', s.w110)}>
@@ -183,7 +183,7 @@ export const InputItem = ({
</span>
</div>
) : null}
{/* 非参数列表设置固定最大宽 */}
{/* Non-parametric list setting fixed maximum width */}
{errorStatus !== 0 && !dynamicWidth && (
<div className={s['check-box']} style={{ width: tipWidth }}>
<span
@@ -212,14 +212,14 @@ export const SelectItem = ({
const [value, setValue] = useState(!record?.type ? undefined : record?.type);
const [errorStatus, setErrorStatus] = useState<number>(0);
// 通过check触发校验提交时
// Trigger validation via check (when committed)
useEffect(() => {
if (check === 0) {
return;
}
handleCheck(value);
}, [check]);
// 校验
// validation
const handleCheck = (val: string | ParameterType | undefined) => {
const status = val === undefined ? 1 : 0;
setErrorStatus(status);

View File

@@ -13,9 +13,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* eslint-disable @coze-arch/max-line-per-function -- 历史逻辑 陆续在拆 */
/* eslint-disable max-lines -- 历史逻辑 陆续在拆 */
/* eslint-disable @coze-arch/max-line-per-function -- historical logic, dismantling one after another */
/* eslint-disable max-lines -- historical logic, dismantling one after another */
import { cloneDeep, flow, get as ObjectGet, set as ObjectSet } from 'lodash-es';
import { I18n } from '@coze-arch/i18n';
@@ -75,7 +75,7 @@ export interface ColumnsProps {
showSecurityCheckFailedMsg: boolean;
setShowSecurityCheckFailedMsg: (flag: boolean) => void;
/**
* 是否支持扩展的文件类型
* Whether extended file types are supported
*/
enableFileType?: boolean;
}
@@ -92,7 +92,7 @@ export const getColumns = ({
setShowSecurityCheckFailedMsg,
enableFileType = false,
}: ColumnsProps) => {
// 添加子节点
// Add sub-node
const addChildNode: AddChildNodeFn = ({
record,
isArray = false,
@@ -118,37 +118,37 @@ export const getColumns = ({
path?: Array<number>;
} = {};
// 1.查找路径
// 1. Find the path
findPathById({
data,
callback: (item: APIParameter, path: Array<number>) => {
if (item[ROWKEY] === record[ROWKEY]) {
result = { ...item, path };
// 修改复杂类型结构,需要重置数组的默认值
// Modifying complex type structures requires resetting the default values of the array
deleteArrayGlobalDefaultByPath(newData, path);
}
},
});
// 2.拼接路径
// 2. Splicing path
const path = (result?.path || [])
.map((v: number) => [v, childrenRecordName])
.flat();
// 如果是添加子节点,则更新父节点中的类型
// If adding a sub-node, update the type in the parent node
if (recordType) {
const typePath = cloneDeep(path);
typePath.pop();
typePath.push('type');
// type 为4/5切换节点的时候需要先删除子节点
// recordType 原节点的类型
// newData 新节点数据
// The type is 4/5. When switching nodes, you need to delete the sub-node first.
// recordType The type of the original node
// newData new node data
if (ObjectGet(newData, typePath) !== recordType) {
deleteAllChildNode(newData, record[ROWKEY] as string);
}
ObjectSet(newData, typePath, type);
}
// 3.添加节点
// 3. Add a node
if (Array.isArray(ObjectGet(newData, path))) {
ObjectSet(newData, path, [
...ObjectGet(newData, path),
@@ -167,7 +167,7 @@ export const getColumns = ({
}
setData(newData);
};
// 删除子节点
// Delete sub-node
const deleteChildNode = (record: APIParameter) => {
const cloneData = cloneDeep(data);
const delStatsu = deleteNode(cloneData, record[ROWKEY] as string);
@@ -281,7 +281,7 @@ export const getColumns = ({
),
key: 'desc',
render: (record: APIParameter) =>
// ,帮助用户/大模型更好地理解。
// To help users/large models better understand.
disabled ? (
<Typography.Text
component="div"
@@ -390,7 +390,7 @@ export const getColumns = ({
disabled={disabled}
defaultChecked={record.is_required}
onChange={e => {
// 必填 + 没有默认值 = 可见
// Required + no default = visible
if (e.target.checked && !record.global_default) {
updateNodeWithData({
record,
@@ -510,7 +510,7 @@ export const getColumns = ({
],
);
}
//出参场景,移除 required,增加 enabled 开关
//Exported parameter scene, remove required, add enabled switch
if (isResponse) {
const targetIndex = columns.findIndex(c => c.key === 'default');
@@ -549,14 +549,14 @@ export const getColumns = ({
});
}
return flow(
// 将 columns 以函数参数形式传入,而非直接传给组合函数(`flow(...)(columns)`)是为了利于类型推导
// The purpose of passing columns as function arguments rather than directly to the combinatorial function (flow (...) (columns)) is to facilitate type derivation
() => columns,
// 只读状态不展示后四项操作列
// Read-only status does not show the last four action columns
newColumns => {
const len = isResponse ? DISABLED_RES_SLICE : DISABLED_REQ_SLICE;
return disabled ? newColumns.slice(0, len) : newColumns;
},
// response不需要location字段
// Response does not require location field
newColumns =>
isResponse
? newColumns.filter(item => item.key !== 'location')

View File

@@ -105,8 +105,8 @@ export const useRequestParams = ({
}
setFormData(fd);
};
const [flag, setFlag] = useState<boolean>(false); // 为了更新视图
const [checkFlag, setCheckFlag] = useState<number>(0); // 全局校验用
const [flag, setFlag] = useState<boolean>(false); // To update the view
const [checkFlag, setCheckFlag] = useState<number>(0); // global validation
const columns = getColumns({
data,
flag,
@@ -192,13 +192,13 @@ export const useRequestParams = ({
style={{ minWidth: 1008, overflowY: 'auto' }}
>
<Table
// 最小宽度为了兼容多层级场景最大层级可支持超过50层
// 最小宽度 = 模块最小宽度 + (当前层级数 - 宽度变化起始层级) * (当前层级数 < 宽度变化起始层级 ? 小间隔数 : 大间隔数)
// Minimum width, in order to be compatible with multi-level scenarios, the maximum level can support more than 50 layers
// Minimum width = minimum width of module + (current level number - width change starting level) * (current level number < width change starting level? small interval number: large interval number)
style={{
minWidth: `calc(1008px + ${
(maxNum - STARTNUM) * (maxNum < CHANGENUM ? SMALLGAP : MAXZGAP)
}px)`,
}} // 从第4层开始每多一层增加19px
}} // From the 4th layer, add 19px to each additional layer.
pagination={false}
columns={columns}
dataSource={data}

View File

@@ -109,8 +109,8 @@ export const useResponseParams = ({
const [data, setFormData] = useState<Array<APIParameter>>(
responseParams || [],
);
const [flag, setFlag] = useState<boolean>(false); // 为了更新视图
const [checkFlag, setCheckFlag] = useState<number>(0); // 全局校验用
const [flag, setFlag] = useState<boolean>(false); // To update the view
const [checkFlag, setCheckFlag] = useState<number>(0); // global validation
const [inputModal, setInputModal] = useState<boolean>(false);
const [loading, setLoading] = useState<boolean>(false);
@@ -282,7 +282,7 @@ export const useResponseParams = ({
>
<Table
// eslint-disable-next-line @typescript-eslint/no-magic-numbers -- ui
style={{ minWidth: `calc(1008px + ${(maxNum - 6) * 20}px)` }} // 从第6层开始每多一层增加20px
style={{ minWidth: `calc(1008px + ${(maxNum - 6) * 20}px)` }} // From the 6th layer, add 20px to each additional layer.
pagination={false}
columns={columns}
dataSource={data}

View File

@@ -13,10 +13,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* eslint-disable complexity */
/* eslint-disable max-lines */
/* eslint-disable @typescript-eslint/no-explicit-any -- 一些历史any 改不动 */
/* eslint-disable @typescript-eslint/no-explicit-any -- some history can't be changed */
import { nanoid } from 'nanoid';
import { cloneDeep, has, isEmpty, isNumber, isObject } from 'lodash-es';
import {
@@ -28,7 +28,7 @@ import {
import { ARRAYTAG, ROWKEY, childrenRecordName } from './config';
// 遍历树返回目标id路径
// Traverse the tree and return the target ID path
export const findPathById = ({
data,
callback,
@@ -55,7 +55,7 @@ export const findPathById = ({
}
};
// 给每层对象增加层级深度标识
// Add layer depth markers to each layer of objects
export const addDepthAndValue = (
tree: any,
valKey: 'global_default' | 'local_default' = 'global_default',
@@ -64,28 +64,28 @@ export const addDepthAndValue = (
if (!Array.isArray(tree)) {
return;
}
// 遍历树中的每个节点
// Traverse each node in the tree
for (const node of tree) {
// 为当前节点添加深度标识符
// Add a depth identifier to the current node
node.deep = depth;
if (node[valKey]) {
node.value = node[valKey];
}
// 如果当前节点有子节点,则递归地为子节点添加深度标识符
// If the current node has a sub-node, add a depth identifier to the sub-node recursively
if (node[childrenRecordName]) {
addDepthAndValue(node[childrenRecordName], valKey, depth + 1);
}
}
};
// 将深度信息push到一个数组里最后取最大值
// Push the depth information into an array, and finally take the maximum value
export const handleDeepArr = (tree: any, deepArr: Array<number> = []) => {
if (!Array.isArray(tree)) {
return;
}
// 遍历树中的每个节点
// Traverse each node in the tree
for (const node of tree) {
// 为当前节点添加深度标识符
// Add a depth identifier to the current node
if (isNumber(node.deep)) {
deepArr.push(node.deep);
}
@@ -96,7 +96,7 @@ export const handleDeepArr = (tree: any, deepArr: Array<number> = []) => {
}
};
// 返回最大深度
// Return to maximum depth
export const maxDeep = (tree: any) => {
if (!Array.isArray(tree) || tree.length === 0) {
return 0;
@@ -112,7 +112,7 @@ interface DefaultNode {
deep?: number;
}
// 默认子节点
// Default sub-node
export const defaultNode = ({
isArray = false,
iscChildren = false,
@@ -128,7 +128,7 @@ export const defaultNode = ({
deep,
});
// 删除当前节点
// Delete the current node
export const deleteNode = (data: any, targetKey: string) => {
for (let i = 0; i < data.length; i++) {
if (data[i][ROWKEY] === targetKey) {
@@ -146,7 +146,7 @@ export const deleteNode = (data: any, targetKey: string) => {
return false;
};
// 删除全部子节点
// Delete all sub-nodes
export const deleteAllChildNode = (data: any, targetKey: string) => {
for (const item of data) {
if (item[ROWKEY] === targetKey) {
@@ -169,7 +169,7 @@ interface UpdateNodeById {
targetKey: string;
field: string;
value: any;
/** 数组的子节点是否需要继承父节点的字段值,当前只有可见性开关需要继承 */
/** Whether the sub-node of the array needs to inherit the field values of the parent node, currently only the visibility switch needs to inherit */
inherit?: boolean;
}
@@ -182,7 +182,7 @@ const updateNodeByVal = (data: any, field: any, val: any) => {
}
};
// 更新节点信息
// Update node information
export const updateNodeById = ({
data,
targetKey,
@@ -216,19 +216,19 @@ export const updateNodeById = ({
}
};
// 根据路径找对应模版值
// Find the corresponding template value according to the path
export const findTemplateNodeByPath = (
dsl: any,
path: Array<string | number>,
) => {
let node = cloneDeep(dsl);
const newPath = [...path]; //创建新的路径,避免修改原路径
const newPath = [...path]; //Create a new path to avoid modifying the original path
for (let i = 0; i < path.length; i++) {
// 如果存在节点,说明是源数据节点上增加子节点
// If there is a node, it means that a sub-node is added to the source data node.
if (node[path[i]]) {
node = node[path[i]];
} else {
// 如果不存在,说明是新增的节点增加子节点,这时需要将路径指向原始节点(第一个节点)
// If it doesn't exist, it means that the newly added node adds a sub-node. At this time, you need to point the path to the original node (the first node).
node = node[0];
newPath[i] = 0;
}
@@ -236,9 +236,9 @@ export const findTemplateNodeByPath = (
return newPath;
};
// 树转换成对象
// Converting trees to objects
export const transformTreeToObj = (tree: any, checkType = true): any =>
// 树的每一层级表示一个对象的属性集
// Each level of the tree represents a set of properties of an object
tree.reduce((acc: any, item: any) => {
let arrTemp = [];
@@ -278,8 +278,8 @@ export const transformTreeToObj = (tree: any, checkType = true): any =>
break;
case ParameterType.Array:
/**
* 如果是数组,需要过滤掉空的项(且数组的子项非objectarray
* 这里用temp接收过滤后的子项避免直接修改原数组因为原数组和页面数据绑定不能直接删除空项
* If it is an array, you need to filter out empty items (and the children of the array are not object and array).
* Here, use temp to receive the filtered sub-items to avoid directly modifying the original array (because the original array and page data are bound, empty items cannot be directly deleted)
*/
arrTemp = item.sub_parameters;
if (
@@ -296,21 +296,21 @@ export const transformTreeToObj = (tree: any, checkType = true): any =>
break;
}
acc[item.name] = arrTemp.map((subItem: any) => {
// boolean类型匹配字符串true/false
// Boolean type matching string true/false
if ([ParameterType.Bool].includes(subItem.type)) {
return checkType ? subItem.value === 'true' : subItem.value;
}
// 数字类型转为number
// Number type to number
if (
[ParameterType.Integer, ParameterType.Number].includes(subItem.type)
) {
return checkType ? Number(subItem.value) : subItem.value;
}
// 字符串类型直接返回(进到这里的已经是过滤完空值的数组)
// The string type is returned directly (the array entered here is already an array of filtered null values)
if ([ParameterType.String].includes(subItem.type)) {
return subItem.value;
}
// 如果是对象,递归遍历
// If it is an object, recursive traversal
if (subItem.type === ParameterType.Object) {
return transformTreeToObj(subItem.sub_parameters, checkType);
}
@@ -322,28 +322,28 @@ export const transformTreeToObj = (tree: any, checkType = true): any =>
return acc;
}, {});
// 克隆节点修改key及清空value
// Clone the node, modify the key and clear the value
export const cloneWithRandomKey = (obj: any) => {
// 创建新对象储存值
// Create a new object stored value
const clone: any = {};
// 遍历原对象的所有属性
// Iterate through all properties of the original object
for (const prop in obj) {
// 如果原对象的这个属性是一个对象,递归调用 cloneWithRandomKey 函数
// If this property of the original object is an object, recursively call the cloneWithRandomKey function
if (obj[prop]?.constructor === Object) {
clone[prop] = cloneWithRandomKey(obj[prop]);
} else {
// 否则,直接复制这个属性
// Otherwise, copy this property directly
clone[prop] = obj[prop];
}
}
// 如果这个对象有 sub_parameters 属性,需要遍历它
// If this object has sub_parameters properties, you need to iterate over it
if ('sub_parameters' in clone) {
clone.sub_parameters = clone.sub_parameters?.map(cloneWithRandomKey);
}
// 生成一个新的随机 key
// Generate a new random key
if (clone[ROWKEY]) {
clone[ROWKEY] = nanoid();
}
@@ -351,10 +351,10 @@ export const cloneWithRandomKey = (obj: any) => {
clone.value = null;
}
// 返回克隆的对象
// Returns the cloned object
return clone;
};
// 判断参数是否显示删除按钮 先判断是否是根节点,根节点允许删除
// To determine whether the parameter shows the delete button, first determine whether it is the root node, and the root node allows deletion.
export const handleIsShowDelete = (
data: any,
targetKey: string | undefined,
@@ -366,7 +366,7 @@ export const handleIsShowDelete = (
return isShowDelete(data, targetKey);
};
// 检查是否存在相同名称
// Check if the same name exists
export const checkSameName = (
data: Array<APIParameter>,
targetKey: string,
@@ -389,7 +389,7 @@ export const checkSameName = (
}
};
// 检查是否有array类型用来判断response是否需要操作列
// Check if there is an array type (used to determine whether the response requires an operation column)
export const checkHasArray = (data: unknown) => {
if (!Array.isArray(data)) {
return false;
@@ -401,7 +401,7 @@ export const checkHasArray = (data: unknown) => {
Array.isArray(item[childrenRecordName]) &&
item[childrenRecordName].length > 0
) {
// 调整 循环退出时机
// Adjustment, loop exit timing
if (checkHasArray(item[childrenRecordName])) {
return true;
}
@@ -410,7 +410,7 @@ export const checkHasArray = (data: unknown) => {
return false;
};
// 判断参数是否显示删除按钮object类型最后一个不允许删除
// Determine whether the parameter shows the delete button (the last one of the object type is not allowed to be deleted)
export const isShowDelete = (data: any, targetKey: string | undefined) => {
for (const item of data) {
if (item[ROWKEY] === targetKey) {
@@ -433,14 +433,14 @@ export const sleep = (time: number) =>
}, time);
});
// 该方法兼容chromeArchSafari浏览器及iPad增加兼容firefox
// This method is compatible with Chrome, Arch, Safari and iPad, and is compatible with Firefox.
export const scrollToErrorElement = (className: string) => {
const errorElement = document.querySelector(className);
if (errorElement) {
if (typeof (errorElement as any).scrollIntoViewIfNeeded === 'function') {
(errorElement as any).scrollIntoViewIfNeeded();
} else {
// 兼容性处理,如 Firefox
// Compatibility handling, such as Firefox
errorElement.scrollIntoView({
behavior: 'smooth',
block: 'start',
@@ -470,7 +470,7 @@ export const initParamsDefault = (
if (!obj[keyDefault]) {
obj[keyDefault] = '';
}
// bot非引用+必填+local默认值为空+不可见,是异常场景,需手动拨正
// bot non-reference + required + local default value is empty + invisible, it is an abnormal scene and needs to be manually dialed
const isUnusual =
obj.default_param_source === DefaultParamSource.Input &&
keyDefault === 'local_default' &&
@@ -529,7 +529,7 @@ export const transformArrayToTree = (array, template: Array<APIParameter>) => {
const createSubTree = (arrItem: any, tem: any) => {
let subTree: APIParameter & { value?: unknown } = {};
// 数组
// array
if (Array.isArray(arrItem)) {
subTree = {
...tem,
@@ -593,7 +593,7 @@ export const transformParamsToTree = (params: Array<APIParameter>) => {
result[i].sub_parameters = tree;
}
} else {
// 对象嵌数组有问题 被覆盖了 需要重置
// There is a problem with the object embedded array, it is overwritten and needs to be reset.
result[i].sub_parameters = transformParamsToTree(
result[i].sub_parameters || [],
);
@@ -601,7 +601,7 @@ export const transformParamsToTree = (params: Array<APIParameter>) => {
}
return result;
};
// data 额外加工 / 如果本身没有 global_default === undefined 就设置 global_disable 也是 undefined,最后将所有的 global_default 设置成 undefined
// Data extra processing/If there is no global_default === undefined, set global_disable is also undefined, and finally set all global_default to undefined
export const doRemoveDefaultFromResponseParams = (
data: APIParameter[],
hasRequired = false,

View File

@@ -33,7 +33,7 @@ export const typesConfig = {
boolean: ParameterType.Bool,
};
// tool 数据回显用
// Tool data recall
interface ExampleReqParamsType {
[key: string]: string | number | null | object | boolean;
}
@@ -59,7 +59,7 @@ export const setEditToolExampleValue = (
setDefault(requestParams, exampleReqParams);
};
// 重置 type is_required sub_parameters
// Resettype is_required sub_parameters
// @ts-expect-error -- linter-disable-autofix
export const resetWorkflowKey = currentTarget => {
if (Array.isArray(currentTarget)) {
@@ -125,7 +125,7 @@ export const resetStoreKey = currentTarget => {
currentTarget.local_disable = false;
currentTarget.location = undefined;
currentTarget.id = nanoid();
// store 那边是 sub_params 字段 个人 的是 sub_parameters
// The store over there is sub_params field, personal, sub_parameters
if (!('sub_parameters' in currentTarget)) {
currentTarget.sub_parameters = [];
}

View File

@@ -44,7 +44,7 @@ export const isQueryWithinOneWeek = (logId: string) => {
return false;
}
const oneWeekAgoTime = dayjs().subtract(1, 'week');
// 最近 6 天,从 0 点开始
// The last 6 days, starting from 0:00
return logIdTime.isAfter(oneWeekAgoTime, 'day');
};
@@ -128,8 +128,8 @@ const ActionBarWithMultiActions = () => {
};
/**
* 带有标题的footer
* 1、中间消息,用于展示Pluginworkflow的中间调用状态
* Footer with title
* 1. Intermediate message, used to display the intermediate call status of Plugin and workflow
*/
const ActionBarWithTitle = () => {
const { message } = useMessageBoxContext();

View File

@@ -20,10 +20,10 @@ import { type PluginBizContext } from './types/biz-context';
import { BizPlugin } from './plugin';
export const getDebugCommonPluginRegistry = (props: PluginBizContext) => {
// eslint-disable-next-line @typescript-eslint/naming-convention -- 插件命名大写开头符合预期
// eslint-disable-next-line @typescript-eslint/naming-convention -- Plugin names start with uppercase as expected
const BizPluginRegistry: PluginRegistryEntry<PluginBizContext> = {
/**
* 贯穿插件生命周期、组件的上下文
* Context of components throughout the plug-in lifecycle
*/
createPluginBizContext() {
return {
@@ -31,7 +31,7 @@ export const getDebugCommonPluginRegistry = (props: PluginBizContext) => {
};
},
/**
* 插件本体
* plug-in ontology
*/
Plugin: BizPlugin,
};

View File

@@ -26,19 +26,19 @@ import { bizLifeCycleServiceGenerator } from './services/life-cycle';
export class BizPlugin extends WriteableChatAreaPlugin<PluginBizContext> {
/**
* 插件类型
* PluginMode.Readonly = 只读模式
* PluginMode.Writeable = 可写模式
* plugin type
* PluginMode. Readonly = read-only mode
* PluginMode. Writeable = Writable Mode
*/
public pluginMode = PluginMode.Writeable;
/**
* 插件名称
* 请点 PluginName 里面去定义
* plugin name
* Please click PluginName to define it.
*/
public pluginName = PluginName.DebugCommon;
/**
* 生命周期服务
* lifecycle services
*/
public lifeCycleServices = createWriteableLifeCycleServices(
this,

View File

@@ -88,7 +88,7 @@ export const messageLifeCycleServiceGenerator: WriteableMessageLifeCycleServiceG
reportReceiveEvent(message);
// 如果是创建定时任务的消息的话,需要刷新任务列表
// If it is a message to create a scheduled task, you need to refresh the task list.
if (isCreateTaskMessage(message)) {
refreshTaskList();
}

View File

@@ -74,7 +74,7 @@ export const sendTeaEventOnBeforeSendMessage = (params: {
message_id: message.extra_info.local_message_id,
bot_id: botId,
};
// 原本逻辑就只在这三个场景 sendTea
// The original logic is only in these three scenes sendTea
if (from === 'inputAndSend') {
sendTeaEvent(EVENT_NAMES.click_send_message, {
from: 'type',
@@ -179,7 +179,7 @@ export const updateAgentBeforeSendMessage: (
const regeneratedMessageBotState = getBotState(message.extra_info.bot_state);
// regenerate 消息时 把 currentAgentId 设置为对应 userMessage 的 agentId
// When regenerating the message, set the currentAgentId to the agentId corresponding to the userMessage.
const fixedAgentId =
currentAgentID === useManuallySwitchAgentStore.getState().agentId
? currentAgentID

View File

@@ -23,7 +23,7 @@ import {
ChatBackgroundEventName,
} from '@coze-common/chat-area-plugin-chat-background';
// 处理聊天背景图在BotEditor与插件的通信
// Handling chat background covers communication with plugins in BotEditor
export const useBotEditorChatBackground = () => {
const backgroundInfo = useBotSkillStore(
state => state.backgroundImageInfoList?.[0],
@@ -31,7 +31,7 @@ export const useBotEditorChatBackground = () => {
const { ChatBackgroundPlugin } = createChatBackgroundPlugin();
useEffect(() => {
// 监听用户设置背景图,将更新的背景图信息传入插件
// Monitor the user to set the background cover and pass the updated background cover information to the plugin
chatBackgroundEvent.emit(
ChatBackgroundEventName.OnBackgroundChange,
backgroundInfo,

View File

@@ -107,7 +107,7 @@ export const CropperCover: React.FC<CropperCoverProps> = ({
<Tag
color="primary"
prefixIcon={null}
// 这里适配背景图色 颜色固定不改变
// The background cover color is suitable here, and the color is fixed and does not change.
className="!text-white !bg-[rgba(0,0,0,0.28)]"
>
{mode === 'pc'

View File

@@ -99,16 +99,16 @@ const CropperImg: React.FC<CropperProps> = ({
initialAspectRatio={size.width / size.height}
src={url}
style={{ height: size.height, width: size.width }}
background={false} // 是否在容器内显示网格背景
background={false} // Whether to display a grid background within the container
guides={false}
zoom={debouncedZoom}
ref={cropperRef}
dragMode="move" // 图片容器可移动
viewMode={0} // 定义cropper的视图模式0允许裁剪框可以延伸到图片容器之外
modal={false} // 是否在图片和裁剪框之间显示黑色蒙版
dragMode="move" // Image container removable
viewMode={0} // Define the view mode of the cropper, 0 allows the cropping box to extend beyond the image container
modal={false} // Whether to display a black mask between the image and the crop box
center={false}
cropBoxMovable={false} // 是否可以拖拽裁剪框 默认true
cropBoxResizable={false} // 默认true ,是否允许拖动 改变裁剪框大小
cropBoxMovable={false} // Whether you can drag and drop the crop box, the default is true.
cropBoxResizable={false} // Default true, whether to allow dragging, change the size of the crop box
highlight={false}
autoCropArea={1}
minCanvasHeight={size.height}

View File

@@ -36,7 +36,7 @@ import { DragUploadContent } from './drag-upload-content';
import CropperImg from './cropper';
export const checkHasFileOnDrag = (e: React.DragEvent<HTMLDivElement>) =>
// 判断的依据直接看 types 的类型解释就好了
// The basis for the judgment is to directly look at the type explanation of types
Boolean(e.dataTransfer?.types.includes('Files'));
export interface CropperUploadProps {
pictureValue?: Partial<FileItem>;
@@ -91,7 +91,7 @@ const CopperUpload: React.FC<CropperUploadProps> = ({
if (validateSize) {
onSuccess(file);
onChange?.(file);
// 手动上传后 需要把候选图的选中态清掉
// After uploading manually, you need to clear the selected state of the candidate image.
setGenerateBackgroundModalByImmer(state => {
state.selectedImage = {};
});

View File

@@ -82,7 +82,7 @@ export const BackgroundConfigContent: React.FC<
state.setGenerateBackgroundModalByImmer,
})),
);
// 初始化展示在拖拽框的图: AI生成成功的展示生成的 > 历史设置的背景图 > 空
// Initialize the display in the drag-and-drop box of the graph: AI-generated successful display generated > history settings background cover > empty
const initPicture = getInitBackground({
isGenerateSuccess,
originBackground: backgroundValue,
@@ -98,7 +98,7 @@ export const BackgroundConfigContent: React.FC<
const pictureUrl = pictureValue?.url;
useEffect(() => {
// 初始化逻辑: 初始化图 不是 选中的图,更新候选图选中态
// Initialization logic: Initialize the graph, not the selected graph, update the selected state of the candidate graph
if (initPicture.url !== selectedImageInfo?.tar_url) {
setGenerateBackgroundModalByImmer(state => {
state.selectedImage = {
@@ -112,7 +112,7 @@ export const BackgroundConfigContent: React.FC<
}, []);
useEffect(() => {
// 收到AI生图成功后更新当前展示在裁剪框的图片
// After receiving the AI generated picture successfully, update the picture currently displayed in the crop box.
if (selectedImageInfo) {
setPictureValue({
uri: selectedImageInfo?.tar_uri,

View File

@@ -75,9 +75,9 @@ describe('should compute position correctly', () => {
width: 20,
})),
};
// 使用 vi.spyOn 模拟 createRef 的行为
// Using vi.spyOn to simulate the behavior of createRef
const createRefSpy = vi.spyOn(React, 'createRef').mockReturnValue(cropperRef);
// 手动设置 cropperRef.current 的值
// Manually set the value of cropperRef.current
cropperRef.current = {
cropper: cropperMock,
};
@@ -97,7 +97,7 @@ describe('should compute position correctly', () => {
const result = computePosition(mode, cropperRef);
expect(result.left).toBe(0.03);
expect(result.right).toBe(0.92);
// 恢复 createRef 的原始行为
// Restore the original behavior of createRef
createRefSpy.mockRestore();
});

Some files were not shown because too many files have changed in this diff Show More