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

@@ -94,7 +94,7 @@ describe('AutosaveManager', () => {
manager.start();
expect(manager.observerList.length).toBe(1);
manager.start(); // 再次调用 start
manager.start(); // Call start again.
expect(manager.observerList.length).toBe(1);
});
@@ -188,7 +188,7 @@ describe('AutosaveManager', () => {
});
const observer = manager.getObserver('testKey');
// 确保所有异步操作完成
// Make sure all asynchronous operations are completed
await Promise.resolve();
expect(observer.lock).toBe(false);

View File

@@ -64,7 +64,7 @@ describe('AutosaveObserver', () => {
};
beforeEach(() => {
vi.useFakeTimers(); // 使用假定时器
vi.useFakeTimers(); // Use a hypothetical timer
observer = new AutosaveObserver({
store: mockStore,
@@ -74,7 +74,7 @@ describe('AutosaveObserver', () => {
afterEach(() => {
vi.resetAllMocks();
vi.useRealTimers(); // 恢复真实的定时器
vi.useRealTimers(); // Restore the real timer
});
it('should initialize and set initial values correctly', () => {
@@ -119,9 +119,9 @@ describe('AutosaveObserver', () => {
expect(observer.debouncedSaveFunc).toBeInstanceOf(Function);
vi.runAllTimers(); // 手动推进定时器时间以触发防抖函数
vi.runAllTimers(); // Manually advance the timer time to trigger the stabilization function
await vi.runAllTimersAsync(); // 确保所有异步操作完成
await vi.runAllTimersAsync(); // Make sure all asynchronous operations are completed
expect(saveRequest).toHaveBeenCalledWith(nextState, 'testKey', diffChange);
});

View File

@@ -56,7 +56,7 @@ export class AutosaveManager<StoreType, ScopeKey, ScopeStateType> {
}
/**
* 注册数据源和定义对应的 Observer 配置
* Register the data source and define the corresponding Observer configuration
* @param _config
*/
public register = (
@@ -80,7 +80,7 @@ export class AutosaveManager<StoreType, ScopeKey, ScopeStateType> {
};
/**
* 启动 Manager 模块
* Launch Manager Module
*/
public start = () => {
if (this.observerList.length > 0) {
@@ -96,7 +96,7 @@ export class AutosaveManager<StoreType, ScopeKey, ScopeStateType> {
};
/**
* 关闭 Manager 模块下的所有属性监听
* Turn off all property listeners under the Manager module
*/
public close = () => {
this.observerList.forEach(observer => observer.close());
@@ -104,7 +104,7 @@ export class AutosaveManager<StoreType, ScopeKey, ScopeStateType> {
};
/**
* 手动保存
* save manually
* @param params
*/
public manualSave = async (key: ScopeKey, params: ScopeStateType) => {
@@ -127,7 +127,7 @@ export class AutosaveManager<StoreType, ScopeKey, ScopeStateType> {
};
/**
* 回调过程中关闭自动保存
* Turn off autosave during a callback
* @param params
*/
public handleWithoutAutosave = async (params: {
@@ -145,7 +145,7 @@ export class AutosaveManager<StoreType, ScopeKey, ScopeStateType> {
};
/**
* 立即触发保存
* Trigger save immediately
* @param key
*/
public saveFlush = (key: ScopeKey) => {
@@ -154,7 +154,7 @@ export class AutosaveManager<StoreType, ScopeKey, ScopeStateType> {
};
/**
* 立即触发所有保存
* Trigger all saves immediately
* @param key
*/
public saveFlushAll = () => {
@@ -164,14 +164,14 @@ export class AutosaveManager<StoreType, ScopeKey, ScopeStateType> {
};
/**
* 获取目标 observer 配置
* Get target observer configuration
* @param key
*/
private getObserver = (key: ScopeKey) =>
this.observerList.find(i => i.config.key === key);
/**
* 获取目标配置项
* Get target configuration item
* @param key
*/
private getConfig = (key: ScopeKey) =>

View File

@@ -49,7 +49,7 @@ export class AutosaveObserver<StoreType, ScopeKey, ScopeStateType> {
this.lock = false;
this.config = config;
// 订阅字段初始化
// Subscription field initialization
this.initSubscribe();
}
@@ -65,7 +65,7 @@ export class AutosaveObserver<StoreType, ScopeKey, ScopeStateType> {
if (typeof this.config.selector === 'function') {
return this.config.selector;
} else {
// 使用createSelector创建可记忆化的选择器
// Create a memorable selector with createSelector
const { deps, transformer } = this.config.selector;
return createSelector(deps, transformer);
}
@@ -75,7 +75,7 @@ export class AutosaveObserver<StoreType, ScopeKey, ScopeStateType> {
console.log('nextState :>> ', nextState);
console.log('prevState :>> ', prevState);
// selector 返回的 state
// The state returned by the selector
this.nextState = nextState;
this.prevState = prevState;
@@ -110,12 +110,12 @@ export class AutosaveObserver<StoreType, ScopeKey, ScopeStateType> {
};
private parsedSaveFunc = async () => {
// 中间件-保存前
// Middleware - Before saving
const beforeSavePayload = await getPayloadByFormatter<ScopeStateType>(
this.nextState,
this.config?.middleware?.onBeforeSave,
);
// 生命周期-保存前
// Life cycle - before saving
await this.config?.eventCallBacks?.onBeforeSave?.({
key: this.config.key,
data: beforeSavePayload,
@@ -129,21 +129,21 @@ export class AutosaveObserver<StoreType, ScopeKey, ScopeStateType> {
this.diff,
);
// 中间件-保存后
// Middleware - after saving
const afterSavePayload = await getPayloadByFormatter<ScopeStateType>(
this.nextState,
this.config?.middleware?.onAfterSave,
);
console.log('afterSavePayload:>>', afterSavePayload);
// 生命周期-保存后
// Life cycle - after saving
await this.config?.eventCallBacks?.onAfterSave?.({
key: this.config.key,
data: afterSavePayload,
});
} catch (error) {
console.log('error:>>', error);
// 生命周期-异常
// Life Cycle - Abnormal
this.config?.eventCallBacks?.onError?.({
key: this.config.key,
error: error as Error,
@@ -152,7 +152,7 @@ export class AutosaveObserver<StoreType, ScopeKey, ScopeStateType> {
};
/**
* 取消订阅
* unsubscribe
*/
public close = () => {
this.debouncedSaveFunc?.flush();
@@ -161,10 +161,10 @@ export class AutosaveObserver<StoreType, ScopeKey, ScopeStateType> {
};
/**
* 获取状态变更带来的触发延时时间
* @param prevState selector 选择的 store 的内容
* @param diffChange 前后比对的diff
* @returns 延时时间
* Get the trigger delay time caused by the state change
* @param prevState selector to store content
* @param diffChange the diff before and after comparison
* @returns delay time
*/
private getTriggerDelayTime = (
prevState?: ScopeStateType,
@@ -232,7 +232,7 @@ export class AutosaveObserver<StoreType, ScopeKey, ScopeStateType> {
};
/**
* 获取变更与 trigger 声明配置对应的 key
* Gets the key that changes the configuration corresponding to the trigger declaration
* @param changePath diff path
* @returns path key
*/

View File

@@ -20,23 +20,23 @@ import { type StoreApi, type UseBoundStore } from 'zustand';
import type { Diff } from 'deep-diff';
/**
* 防抖延迟时间
* stabilization delay time
* @readonly
* @enum {number}
*/
export enum DebounceTime {
/** 用于需要立即响应的保存操作,如按钮或下拉选择等操作 */
/** For saving operations that require an immediate response, such as buttons or drop-down selections */
Immediate = 0,
/** 用于需要较短时间响应的保存操作,如拖拽等操作 */
/** For saving operations that require a short response time, such as dragging and dropping */
Medium = 500,
/** 适合于文本输入等操作 */
/** Suitable for operations such as text input */
Long = 1000,
}
/** trigger 配置声明时的函数形式,用于在运行时指定字段触发时机 */
/** Functional form when the trigger configuration is declared, used to specify when the field will trigger at runtime */
export type FunctionDebounceTime = () => DebounceTime;
/** trigger 配置声明时的数组形式,用于分别指定数组内容变化时的触发时机 */
/** The array form when the trigger configuration is declared, which is used to specify the trigger timing when the array content changes */
export interface ArrayDebounceTime {
arrayType: boolean;
action:
@@ -48,7 +48,7 @@ export interface ArrayDebounceTime {
};
}
/** trigger 配置声明时的对象形式,用于分别指定多字段触发时机 */
/** The object form when the trigger configuration declaration is used to specify the triggering time of multiple fields separately */
export interface ObjectDebounceTime {
default: DebounceTime;
[index: string]: DebounceTime | ArrayDebounceTime;
@@ -79,21 +79,21 @@ export type SelectorType<StoreType, ScopeStateType> =
};
export interface AutosaveObserverConfig<StoreType, ScopeKey, ScopeStateType> {
/** 被托管的数据字段的类型 */
/** The type of data field being hosted */
key: ScopeKey;
/** 防抖延迟时间 */
/** stabilization delay time */
debounce?: DebounceConfig;
/** store 需要被监听的属性选择器,支持配置依赖 */
/** Store property selectors that need to be listened to, support configuration dependencies */
selector: SelectorType<StoreType, ScopeStateType>;
/** 中间件 支持业务链式处理监听数据 */
/** Middleware, which supports business chain processing of monitoring data */
middleware?: MiddlewareHanderMap<ScopeStateType>;
/** 是否立即保存当前字段 */
/** Whether to save the current field immediately */
immediate?: boolean;
/** 保存的请求 */
/** saved request */
saveRequest: SaveRequest<ScopeStateType, ScopeKey>;
/** 被托管的数据取消订阅时进行的回调 */
/** Callbacks when hosted data is unsubscribed */
unobserver?: () => void;
/** 生命周期 */
/** Life Cycle */
eventCallBacks?: EventCallBacks<ScopeStateType, ScopeKey>;
}
@@ -108,28 +108,28 @@ export type SaveMiddlewareHander<ScopeStateType> = (
) => Promise<FlexibleState<ScopeStateType>> | FlexibleState<ScopeStateType>;
export interface MiddlewareHanderMap<ScopeStateType> {
/** 生命周期-检测变更后 */
/** Lifecycle - After detecting changes */
onBeforeSave?: SaveMiddlewareHander<ScopeStateType>;
/** 生命周期-成功保存后 */
/** Lifecycle - after successful saving */
onAfterSave?: SaveMiddlewareHander<ScopeStateType>;
}
export interface EventCallBacks<ScopeStateType, ScopeKey> {
/** 生命周期-检测变更后 */
/** Lifecycle - After detecting changes */
onBeforeSave?: (params: {
data: FlexibleState<ScopeStateType>;
key: ScopeKey;
}) => void | Promise<void>;
/** 生命周期-成功保存后 */
/** Lifecycle - after successful saving */
onAfterSave?: (params: {
data: FlexibleState<ScopeStateType>;
key: ScopeKey;
}) => void | Promise<void>;
/** 生命周期-异常 */
/** Life Cycle - Abnormal */
onError?: (params: { error: Error; key: ScopeKey }) => void;
}
// 比对出来的被变化的 key 的 path number 形式对应数组
// The path of the changed key compared, corresponding to the array in the form of number
export type PathType = string | number;
export interface UseStoreType<StoreType, ScopeStateType> {

View File

@@ -37,7 +37,7 @@ export function isObject(value: DebounceConfig): value is ObjectDebounceTime {
}
/**
* 获取保存接口调用时候需要的参数
* Get the parameters required to save the interface call
*/
export const getPayloadByFormatter = async <T>(
state: T,

View File

@@ -33,7 +33,7 @@ vi.mock('@coze-arch/logger', () => ({
getSlardarInstance: vi.fn(() => mockSlardarInstance),
}));
// 模拟依赖
// simulated dependency
vi.mock('copy-to-clipboard', () => ({
default: vi.fn(),
}));
@@ -105,19 +105,19 @@ describe('withSlardarIdButton', () => {
const button = screen.getByTestId('button');
fireEvent.click(button);
// 验证 slardar.config 被调用
// Verify that slardar.config is called
expect(getSlardarInstance).toHaveBeenCalled();
expect(mockSlardarInstance.config).toHaveBeenCalled();
// 验证 copy 被调用,且参数正确
// Verify that copy is called and that the parameters are correct
expect(copy).toHaveBeenCalledWith('test-session-id');
// 验证 Toast.success 被调用,且参数正确
// Verify that Toast.success is called and the parameters are correct
expect(Toast.success).toHaveBeenCalledWith('复制成功');
});
it('当 sessionId 为空时应该复制空字符串', () => {
// 模拟 sessionId undefined
// Emulate sessionId to undefined
vi.mocked(mockSlardarInstance.config).mockReturnValueOnce({
sessionId: undefined,
});

View File

@@ -19,7 +19,7 @@ import { describe, expect, it } from 'vitest';
import { getFileInfo } from '../src/util';
import { FileTypeEnum } from '../src/const';
// 创建模拟的 File 对象
// Create a simulated File object
function createMockFile(name: string, type: string): File {
return {
name,
@@ -140,7 +140,7 @@ describe('getFileInfo', () => {
});
it('当文件类型和扩展名不匹配时,应该优先使用文件类型判断', () => {
// 文件名是 .txt 但 MIME 类型是图片
// The file name is .txt, but the MIME type is image
const file = createMockFile('image.txt', 'image/jpeg');
const fileInfo = getFileInfo(file);

View File

@@ -17,7 +17,7 @@
import { FileTypeEnum, type TFileTypeConfig } from './const';
/**
* 文件类型
* file type
* {@link
* {@link https://www.iana.org/assignments/media-types/media-types.xhtml#image}
*/
@@ -37,7 +37,7 @@ export const FILE_TYPE_CONFIG: readonly TFileTypeConfig[] = [
'.ogg',
'.wma',
'.alac',
// .midi .mid 都是MIDIMusical Instrument Digital Interface)文件的扩展名 - GPT
// Both .midi and .mid are extensions for MIDI (Musical Instrument Digital Interface) files - GPT
'.mid',
'.midi',
'.ac3',

View File

@@ -16,7 +16,7 @@
import { FILE_TYPE_CONFIG } from './file-type';
// 获取文件信息
// Get file information
export const getFileInfo = (file: File) => {
const fileInfo = FILE_TYPE_CONFIG.find(({ judge, accept }) =>
judge ? judge(file) : accept.some(ext => file.name.endsWith(ext)),

View File

@@ -77,10 +77,10 @@ describe('SelectSpaceModal', () => {
wrapper.getByDisplayValue('mockBot(duplicate_rename_copy)'),
).toBeInTheDocument();
// 检查表单是否存在
// Check if the form exists
expect(wrapper.getByRole('form')).toBeInTheDocument();
// 检查确定和取消按钮
// Check OK and Cancel buttons
expect(
wrapper.getByRole('button', { name: 'confirm' }),
).toBeInTheDocument();

View File

@@ -28,23 +28,23 @@ import { CarouselItem } from './carousel-item';
import styles from './index.module.less';
export interface CarouselProps {
/** 元素布局行数默认为1 */
/** The number of rows in the element layout defaults to 1. */
rows?: number;
/** 元素布局列数,默认为均分数组 */
/** Number of element layout columns, the default is to divide the array equally */
column?: number;
/** 每次点击箭头滚动的百分比,0~1. 默认值为0.5 */
/** Percentage of scrolling per click of arrow, 0~ 1. Default value is 0.5 */
scrollStep?: number;
/** 滚动回调 */
/** scrolling callback */
onScroll?: () => void;
/** 箭头是否显示边框 */
/** Whether the arrow shows the border */
enableArrowBorder?: boolean;
/** 箭头是否显示阴影渐变 */
/** Whether the arrows show gradual changes in shadows */
enableArrowShalldow?: boolean;
/** 子元素样式 */
/** child style */
itemClassName?: string;
/** 左箭头样式 */
/** Left Arrow Style */
leftArrowClassName?: string;
/** 右箭头样式 */
/** Right Arrow Style */
rightArrowClassName?: string;
children: React.ReactNode;
}
@@ -156,7 +156,7 @@ export const Carousel: React.FC<CarouselProps> = ({
itemsContainerRef?.current?.scrollLeft !== undefined &&
itemsContainerRef?.current?.clientWidth
) {
// 部分浏览器不支持 scrollTo 方法
// Some browsers do not support the scrollTo method
itemsContainerRef.current.scrollTo?.({
left: Math.max(
itemsContainerRef.current.scrollLeft -
@@ -193,7 +193,7 @@ export const Carousel: React.FC<CarouselProps> = ({
scrollLeft;
const shouldShowArrowLeft = scrollLeft > 0;
// 极端场景下存在 1px 偏差
// There is a 1px bias in extreme scenarios
const shouldShowArrowRight = Math.abs(scrollRight) > 2;
setLeftArrowVisible(shouldShowArrowLeft);
@@ -204,7 +204,7 @@ export const Carousel: React.FC<CarouselProps> = ({
updateArrowVisible();
};
// 初始化时判读一次是否显示箭头
// Determine whether to display arrows once during initialization
updateArrowVisible();
itemsContainerRef?.current?.addEventListener('scroll', scrollEvent);
window?.addEventListener('resize', updateArrowVisible);

View File

@@ -39,7 +39,7 @@ interface CollapsibleIconButtonContextValue {
setItems: Dispatch<SetStateAction<ContextItems | undefined>>;
}
// eslint-disable-next-line @typescript-eslint/naming-convention -- 这是 context
// eslint-disable-next-line @typescript-eslint/naming-convention -- this is context
export const CollapsibleIconButtonContext =
createContext<CollapsibleIconButtonContextValue>({
showText: true,
@@ -56,7 +56,7 @@ export const useItem = (key: symbol, ref: RefObject<HTMLElement>) => {
}));
}, [size?.width]);
// 组件销毁后移除
// Component destruction and removal
useEffect(
() => () => {
setItems(items => omit(items, key));

View File

@@ -32,7 +32,7 @@ import {
import { CollapsibleIconButtonContext, useWrapper, useItem } from './context';
/** 能让 Group 内的所有 CollapsibleIconButton 根据空余宽度自动展开(露出文案)收起(隐藏文案只剩图标) */
/** Can make all the CollapsibleIconButton in the Group automatically expand according to the free width (expose the copy) and put away (hide the copy and only the icon is left) */
export const CollapsibleIconButtonGroup: FC<
PropsWithChildren<{
/** @default 12 */
@@ -67,12 +67,12 @@ export const CollapsibleIconButton = forwardRef<
return (
<span ref={ref}>
{/* 不可见时渲染到屏幕外侧,用于获取宽度 */}
{/* Render to the outside of the screen when not visible for width */}
<div className={showText ? '' : 'fixed left-[-999px]'} ref={contentRef}>
<Button
size="default"
color="secondary"
// 不可见时不附带 testid避免对 E2E 产生影响
// Invisible without testid to avoid impact on E2E
{...(showText ? rest : omit(rest, 'data-testid'))}
>
{text}
@@ -87,7 +87,7 @@ export const CollapsibleIconButton = forwardRef<
);
});
/** 更为通用的版本 */
/** A more general version */
export const Collapsible = forwardRef<
HTMLSpanElement,
{
@@ -102,7 +102,7 @@ export const Collapsible = forwardRef<
return (
<span ref={ref}>
{/* 不可见时渲染到屏幕外侧,用于获取宽度 */}
{/* Render to the outside of the screen when not visible for width */}
<div className={showFull ? '' : 'fixed left-[-999px]'} ref={contentRef}>
{fullContent}
</div>
@@ -118,7 +118,7 @@ export const Collapsible = forwardRef<
);
});
/** 不会折叠,但参与宽度计算的元素 */
/** Elements that do not collapse, but participate in width calculations */
export function PlaceholderContainer({
itemKey,
children,

View File

@@ -57,7 +57,7 @@ interface DuplicateBotProps {
buttonSize?: Size;
enableCozeDesign?: boolean;
/**
* cozeDesign 的情况下才生效
* CozeDesign only takes effect in the case of
*/
isBlock?: boolean;
eventCallbacks?: Partial<{
@@ -143,17 +143,17 @@ export const DuplicateBot: FC<DuplicateBotProps> = ({
});
}
//复制完成,关闭空间弹窗
//Copy complete, close the space pop-up window
setShowSpaceModal(false);
} else if (pageFromFromStore === BotPageFromEnum.Explore) {
//explore时可以复制到某个空间下
//When exploring, it can be copied to a certain space
resp = await DeveloperApi.DuplicateBotToSpace({
draft_bot_id: botIdFromStore,
target_space_id: targetSpaceId || '',
name,
});
//复制完成,关闭空间弹窗
//Copy complete, close the space pop-up window
setShowSpaceModal(false);
} else {
resp = await SpaceApi.DuplicateDraftBot({
@@ -260,14 +260,14 @@ export const DuplicateBot: FC<DuplicateBotProps> = ({
from: 'explore_card',
source: 'explore_bot_detailpage',
});
//探索页面来源team>1时选择copy 空间否则copy到个人空间
//Explore the page Source: Select copy space when team > 1, otherwise copy to personal space
if (list.length === 1) {
openNewWindow(() => copyAndOpenBot(list?.[0].id));
} else {
setShowSpaceModal(true);
}
} else if (pageFrom === BotPageFromEnum.Template) {
//探索页面来源team>1时选择copy 空间否则copy到个人空间
//Explore the page Source: Select copy space when team > 1, otherwise copy to personal space
if (list.length === 1) {
openNewWindow(() => copyAndOpenBot(list?.[0].id));
} else {
@@ -281,7 +281,7 @@ export const DuplicateBot: FC<DuplicateBotProps> = ({
source: 'bots_detailpage',
from: 'bots_card',
});
// bot页面来源若有操作权限直接copy到当前空间下
// Bot page source: If there is operation permission, directly copy it to the current space
if (hide_operation) {
Toast.warning('Bot in public space cannot duplicate');
return;
@@ -316,7 +316,7 @@ export const DuplicateBot: FC<DuplicateBotProps> = ({
</UIButton>
)}
{/* 选择空间弹窗 */}
{/* Select space pop-up */}
<SelectSpaceModal
botName={botName ?? botNameFromStore}
visible={showSpaceModal}

View File

@@ -93,7 +93,7 @@ export const GenerateButton: React.FC<GenerateButtonProps> = ({
(scene === 'gif' && gifCount >= 10) ||
(scene === 'static_image' && staticImageCount >= 20)
) {
// 达到上限,禁用按钮
// Limit reached, disable button
setExceedImageGenCountLimit(true);
}
}
@@ -103,7 +103,7 @@ export const GenerateButton: React.FC<GenerateButtonProps> = ({
}
};
useEffect(() => {
// 获取图片限制,每天限制10gif20个静态图根据scene来判断是否达到上限
// Get the picture limit, limit 10 gifs and 20 static pictures per day, and judge whether the upper limit is reached according to the scene.
if (!loading) {
getGenPicTimes();
}

View File

@@ -86,7 +86,7 @@ export default function ImagePicker(props: ImagePickerProps) {
maxSize={2 * 1024}
onSizeError={() => {
Toast.error({
// starling 切换
// Starling toggle
content: withSlardarIdButton(
I18n.t(
'dataset_upload_image_warning',

View File

@@ -35,11 +35,11 @@ import s from './index.module.less';
interface GenerateGifProps {
scene: 'background' | 'avatar';
image: ImageItem; // 默认图片
text: string; // 默认文本
loading: boolean; // 生成时socket全局监听服务端响应因此loading需要受控
imageList?: ImageItem[]; // 图片候选列表(只包含静态图)
generatingTaskId: string; // 生成中的任务id
image: ImageItem; // default image
text: string; // default text
loading: boolean; // When generated, sockets listen globally for server level responses, so loading needs to be controlled
imageList?: ImageItem[]; // Picture Candidate List (contains only static images)
generatingTaskId: string; // Generating task id
exceedMaxImageCount?: boolean;
className?: string;
style?: CSSProperties;
@@ -106,7 +106,7 @@ export const GenerateGif: React.FC<GenerateGifProps> = ({
setLoading?.(true);
try {
avatarBackgroundWebSocket.createConnection();
// 只负责发送请求,响应在WebSocket中接收
// Only responsible for sending requests, responses are received in WebSocket
const { data } = await PlaygroundApi.GeneratePic({
gen_prompt: {
ori_prompt: text.trim(),

View File

@@ -31,15 +31,15 @@ import { type TabItem } from './type';
import s from './index.module.less';
export interface GenerateImageTabProps {
// tab列表
// tab list
tabs: TabItem[];
// 是否可折叠
// Is it foldable?
enableCollapsible?: boolean;
// 当前激活的tab
// Currently active tab
activeKey?: string;
// 当前激活的tab变化回调
// Currently active tab change callback
onTabChange?: (tabKey: string) => void;
// 是否展示wait文案
// Whether to show the waiting copy
showWaitTip?: boolean;
disabled?: boolean;
}
@@ -62,7 +62,7 @@ export const GenerateImageTab: React.FC<GenerateImageTabProps> = ({
setOpen(!isOpen);
};
// tabPane 不卸载
// tabPane does not uninstall
const component = (
<div>
{tabs.map(item => (
@@ -124,7 +124,7 @@ export const GenerateImageTab: React.FC<GenerateImageTabProps> = ({
) : null}
</div>
{enableCollapsible ? (
// keepDOM 异常失效使用collapseHeight 不销毁dom保留状态
// keepDOM exception fails using collapseHeight does not destroy dom keep state
<Collapsible isOpen={isOpen} keepDOM collapseHeight={1}>
<div> {component} </div>
</Collapsible>

View File

@@ -28,8 +28,8 @@ import s from './index.module.less';
export type ImageItem = PicTask;
export interface ImageListProps {
selectedKey?: string; // 选中的key
data: ImageItem[]; // 列表数据
selectedKey?: string; // Selected key
data: ImageItem[]; // list data
className?: string;
imageItemClassName?: string;
showDeleteIcon?: boolean;
@@ -39,18 +39,18 @@ export interface ImageListProps {
index?: number;
item?: ImageItem;
data: ImageItem[];
}) => void; // 删除图片data是此次删除之后的数据
}) => void; // Delete the picture, data is the data after this deletion.
onSelect?: (params: {
index?: number;
item: ImageItem;
data: ImageItem[];
selected: boolean;
}) => void; // 选中图片其中item和data都是此次选中之前的数据selected表示在本次选中之前此图片是否已是选中状态
}) => void; // Select the picture, where item and data are the data before this selection. Selected indicates whether the picture was selected before this selection
onClick?: (params: {
index: number;
item: ImageItem;
data: ImageItem[];
}) => void; // 点击图片
}) => void; // Click on the picture.
}
export const ImageList: React.FC<ImageListProps> = ({

View File

@@ -56,7 +56,7 @@ export { UploadGenerateButton } from './upload-generate-button';
export { usePluginLimitModal, transPricingRules } from './plugin-limit-info';
// 曝光埋点上报组件,进入视图上报
// Exposure event tracking report component, enter the view report
export { TeaExposure } from './tea-exposure';
export { Sticky } from './sticky';
@@ -67,6 +67,6 @@ export {
appendCopySuffix,
} from './project-duplicate-modal';
export { SpaceFormSelect } from './space-form-select';
// !Notice 以下模块只允许导出类型,避免首屏加载 react-dnd,@blueprintjs/core 等相关代码
// ! Notice that the following modules only allow export types, avoid loading react-dnd, @blueprintjs/core and other related codes on the first screen
export { type TItemRender, type ITemRenderProps } from './sortable-list';
export { type ConnectDnd, type OnMove } from './sortable-list/hooks';

View File

@@ -109,7 +109,7 @@ export const InputSlider: React.FC<InputSliderProps> = ({
const onNumberChange = (numberValue: number) => {
updateInputNumber();
// 防止 -0
// Prevent -0
if (numberValue === 0) {
onChange?.(0);
return;
@@ -124,7 +124,7 @@ export const InputSlider: React.FC<InputSliderProps> = ({
onChange?.(expectedFormattedValue);
};
// 防止 -0 导致 InputNumber 无限循环更新
// Prevent -0 from causing InputNumber to update indefinitely
const fixedValue = Object.is(value, -0) ? 0 : value;
useEffect(() => {

View File

@@ -36,7 +36,7 @@ const LimitCount: React.FC<LimitCountProps> = ({ maxLen, len }) => (
);
export interface InputWithCountProps extends InputProps {
// 设置字数限制并显示字数统计
// Set word limits and display word count
getValueLength?: (value?: InputProps['value'] | string) => number;
}

View File

@@ -37,7 +37,7 @@ export const ListTab: React.FC<PropsWithChildren<BotListHeaderProps>> = ({
{...props}
tabPaneMotion={false}
type="button"
// eslint-disable-next-line @typescript-eslint/naming-convention -- react 组件
// eslint-disable-next-line @typescript-eslint/naming-convention -- react component
renderTabBar={(innerProps, Node) => (
<div className={cs(s.header, containerClass)}>
<Node {...innerProps} />

View File

@@ -22,7 +22,7 @@ import { type ButtonProps } from '@coze-arch/bot-semi/Button';
import { UIButton, Toast, Spin } from '@coze-arch/bot-semi';
export type LoadingButtonProps = ButtonProps & {
/** 加载中的 toast 文案 */
/** Loading toast copy */
loadingToast?: string | Omit<ToastReactProps, 'type'>;
};

View File

@@ -156,7 +156,7 @@ export const ActionBar: React.FC<ActionBarProps> = ({
</span>
</InsertLinkPopover>
{/* 暂时禁用,后续放开 */}
{/* Temporarily disabled, later released */}
{SHOW_ADD_NAME_BTN && (
<Tooltip content={I18n.t('add_nickname')}>
<UIButton

View File

@@ -26,7 +26,7 @@ export interface InsertLinkPopoverProps
}
/**
* 全受控
* fully controlled
*/
export const InsertLinkPopover: React.FC<
PropsWithChildren<InsertLinkPopoverProps>

View File

@@ -29,7 +29,7 @@ export const getSyncInsertText = (action: SyncAction): string => {
}
/**
* 不应该走到这里
* Shouldn't have come here
*/
primitiveExhaustiveCheck(type);
return '';

View File

@@ -78,7 +78,7 @@ export const useMarkdownEditor = ({
},
);
// 判断使用内置上传方法 or 自定义
// Determine whether to use the built-in upload method or customize
const selectUploadMethod = () => {
if (customUpload) {
return customUpload({
@@ -143,7 +143,7 @@ export const useMarkdownEditor = ({
ref.current.focus();
const { selectionEnd } = ref.current;
/**
* 选中文字时点击 action bar, 将内容插入到文字的末尾
* When the text is selected, click the action bar to insert the content at the end of the text
*/
console.log('handleInsertText', { value, insertText, selectionEnd });

View File

@@ -25,7 +25,7 @@ import { type UploadState } from '../type';
import { UploadController } from '../service/upload-controller';
/**
* 暂时没有场景,所以这里将多实例、一次行上传多文件的能力屏蔽了
* There is no scene for the time being, so the ability to upload multiple files with multiple instances and one line is blocked here.
*/
export const useUpload = ({
getUserId,

View File

@@ -37,7 +37,7 @@ export interface MarkdownEditorProps {
}
/**
* 全受控组件
* fully controlled component
*/
export const MarkdownEditor: React.FC<MarkdownEditorProps> = ({
value = '',

View File

@@ -50,13 +50,13 @@ export interface UploadState {
fileName: string;
}
// 自定义上传方法入参
// Custom upload method imported parameters
export interface CustomUploadParams {
onUploadAllSuccess: (param: { url: string; fileName: string }) => void;
}
// 自定义上传方法出参
// Custom upload method exported parameter
export interface CustomUploadRes {
uploadFileList: (fileList: File[]) => void;
//null表示已完成
//Null means completed
uploadState: UploadState | null;
}

View File

@@ -31,11 +31,11 @@ export const matchAllTemplateRanges = (
text: string,
template: string,
): { start: number; end: number }[] => {
// 正则表达式,用于匹配双花括号内的内容
// Regular expressions to match the contents of double curly braces
const templateRegex = new RegExp(getFixedVariableTemplate(template), 'g');
const matches: { start: number; end: number }[] = [];
// 循环查找所有匹配项
// Loop through all matches
while (true) {
const match = templateRegex.exec(text);

View File

@@ -53,12 +53,12 @@ export interface OptionItemProps {
avatar: string | undefined;
name: string | undefined;
searchWords?: string[];
endPointName?: string; // 接入点名称(专业版有)
endPointName?: string; // Access point name (available in the professional version)
showEndPointName?: boolean;
className?: string;
/**
* @deprecated
* 原先只会有「限额」标签M-5395720900 后会有大量新标签,避免兼容问题产品同意先简单隐藏掉标签展示
* Originally, there would only be "limit" labels. After M-5395720900, there will be a large number of new labels to avoid compatibility problems. The product agrees to simply hide the label display first.
*/
tags?: OptionItemTag[];
}
@@ -77,12 +77,12 @@ export const ModelOptionItem: React.FC<OptionItemProps> = ({
const tags: OptionItemTag[] = [];
const shouldShowEndPoint = showEndPointName && endPointName;
// 即将支持,敬请期待
// Support soon, so stay tuned.
const displayName = FLAGS['bot.studio.model_select_switch_end_point_name_pos']
? endPointName || name
: name;
// 即将支持,敬请期待
// Support soon, so stay tuned.
const displayEndPointName = FLAGS[
'bot.studio.model_select_switch_end_point_name_pos'
]

View File

@@ -23,11 +23,11 @@ import { MonetizeDescription } from '../monetize-description';
import { MonetizeCreditRefreshCycle } from '../monetize-credit-refresh-cycle';
export interface MonetizeConfigValue {
/** 是否开启付费 */
/** Whether to start payment */
isOn: boolean;
/** 开启付费后,用户免费体验的次数 */
/** The number of free user experiences after starting payment */
freeCount: number;
/** 刷新周期 */
/** refresh cycle */
refreshCycle: BotMonetizationRefreshPeriod;
}
@@ -36,8 +36,8 @@ interface MonetizeConfigPanelProps {
value: MonetizeConfigValue;
onChange: (value: MonetizeConfigValue) => void;
/**
* 内置防抖后的 onChange 事件,业务侧可选择性使用,正常只传 onChange 即可
* (由于该组件是完全受控组件,因此不能只传 onDebouncedChange必须传 onChange 实时更新视图)
* The onChange event after built-in anti-shake can be selectively used by the business side. Normally, only onChange can be transmitted.
* (Since this component is a fully controlled component, you cannot just pass onDebouncedChange, you must pass onChange to update the view in real time)
*/
onDebouncedChange?: (value: MonetizeConfigValue) => void;
}

View File

@@ -32,23 +32,23 @@ import s from './index.module.less';
interface MenuItem {
/**
* 如果是string需传入starling key并且会由div包一层
* 如果是function则自定义label的实现,active表示是否是选中态
* If it is a string, you need to pass in the starling key, and it will be wrapped by the div layer.
* If it is a function, the implementation of the custom label, active indicates whether it is selected
*/
label: string | ((active: boolean) => React.ReactNode);
/** label 外的 badge未来再扩展配置项 */
/** The badge outside the label, and the configuration item will be expanded in the future */
badge?: string;
app: SpaceAppEnum;
/**
* Q:为什么不叫 visibleFG 要取反,filter() 也要取反,很麻烦
* A:为了兼容旧配置,缺省时认定为 visible。避免合码时无冲突 导致忽略掉新增配置的问题。
* Q: Why is it not called visible? FG should be reversed, and filter () should also be reversed, which is very troublesome.
* A: In order to be compatible with the old configuration, it is recognized as visible by default. To avoid no conflicts when combining codes, the problem of new configurations is ignored.
*/
invisible?: boolean;
/** 目前24.05.21)没发现用处,怀疑是以前的功能迭代掉了,@huangjian 说先留着 */
/** At present (24.05.21) no use is found, it is suspected that the previous function iteration is lost, @huangjian said to keep it first */
icon?: ReactNode;
/** 目前24.05.21)没发现用处,怀疑是以前的功能迭代掉了,@huangjian 说先留着 */
/** At present (24.05.21) no use is found, it is suspected that the previous function iteration is lost, @huangjian said to keep it first */
selectedIcon?: ReactNode;
/** 自动化打标 */
/** Automatic marking */
e2e?: string;
}

View File

@@ -25,7 +25,7 @@ import React, {
import classNames from 'classnames';
import s from './index.module.less';
// react-markdown 20ms 左右的 longtask
// React-markdown longtask around 20ms
const LazyReactMarkdown = lazy(() => import('react-markdown'));
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const ReactMarkdown = (props: any) => (

View File

@@ -94,10 +94,10 @@ export type ProjectTemplateCopySuccessCallback = (param: {
export const useProjectTemplateCopyModal = (props: {
modalTitle: string;
/** 是否需要选择 space */
/** Do you need to choose space? */
isSelectSpace: boolean;
onSuccess?: ProjectTemplateCopySuccessCallback;
/** 埋点参数 - 当前页面/来源 */
/** Event tracking parameters - current page/source */
source: NonNullable<
ParamsTypeDefine[EVENT_NAMES.template_action_front]['source']
>;
@@ -167,7 +167,7 @@ export const useProjectTemplateCopyModal = (props: {
formProps={{
initValues,
onValueChange: val => {
// 当用户删除 input 中所有字符时val.name 字段会消失,而不是空字符串,神秘
// When the user removes all characters in input, val.name field disappears instead of empty string
setIsFormValid(!!val.name?.trim());
},
getFormApi: api => {
@@ -181,7 +181,7 @@ export const useProjectTemplateCopyModal = (props: {
sourceProduct: inputSourceProduct,
}: {
initValue: ProjectTemplateCopyValue;
/** 用于提取埋点参数 */
/** Used to extract event tracking parameters */
sourceProduct: ProductInfo;
}) => {
setInitValues({

View File

@@ -26,7 +26,7 @@ import classnames from 'classnames';
import s from './handle.module.less';
// 目前只支持水平方向,按需扩展吧
// Currently only supports horizontal direction, expand it on demand.
export interface ResizableLayoutHandleProps {
className?: string;
hotZoneClassName?: string;
@@ -94,7 +94,7 @@ export const ResizableLayoutHandle: FC<ResizableLayoutHandleProps> = ({
const offEvents = () => {
window.removeEventListener('pointermove', move, false);
// 适配移动端出现多点触控的情况
// Adapt to the situation of multi-touch on the mobile end
window.removeEventListener('pointerdown', moveEnd, false);
window.removeEventListener('pointerup', moveEnd, false);
window.removeEventListener('pointercancel', moveEnd, false);
@@ -108,12 +108,12 @@ export const ResizableLayoutHandle: FC<ResizableLayoutHandleProps> = ({
setMoving(true);
callbackRef.current.onMoveStart();
window.addEventListener('pointermove', move, false);
// 适配移动端出现多点触控的情况
// Adapt to the situation of multi-touch on the mobile end
window.addEventListener('pointerdown', moveEnd, false);
window.addEventListener('pointerup', moveEnd, false);
window.addEventListener('pointercancel', moveEnd, false);
};
// TODO hover 样式 & 热区宽度需要和 UI 对齐
// TODO hover style & hotzone width needs to be aligned with UI
return (
<div
className={classnames(hotZoneStyle, hotZoneClassName)}

View File

@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {
Children,
type PropsWithChildren,
@@ -61,7 +61,7 @@ export const ResizableLayout: FC<PropsWithChildren<ResizableLayoutProps>> = ({
return;
}
const totalSize = sum(state.itemWidth);
// 排除还没有进行过拖拽的情况,此时本地 state 中没有记录上次分配的宽度
// Exclude the case where no drag has been performed, and the last allocated width is not recorded in the local state at this time
if (totalSize <= 0) {
return;
}
@@ -107,7 +107,7 @@ export const ResizableLayout: FC<PropsWithChildren<ResizableLayoutProps>> = ({
);
}
}
// @ts-expect-error -- 跳过类型体操
// @ts-expect-error -- skip type gymnastics
const { ref } = child;
if (typeof ref === 'function') {
ref(target);
@@ -144,7 +144,7 @@ export const ResizableLayout: FC<PropsWithChildren<ResizableLayoutProps>> = ({
),
});
}}
// 相对于初始位置的偏移量
// Offset from the initial position
onMove={offset => {
const pre = index - 1;
childRef.current[pre].style.width = `${
@@ -156,7 +156,7 @@ export const ResizableLayout: FC<PropsWithChildren<ResizableLayoutProps>> = ({
}}
onMoveEnd={() => {
setState({
// 拖拽结束后,记录真实宽度
// After dragging, record the true width
itemWidth: childRef.current.map(
item => item.clientWidth ?? 0,
),

View File

@@ -24,7 +24,7 @@ import styles from './index.module.less';
export interface SearchProps {
defaultValue?: string;
/** 当此值变化时,更新内部的搜索内容 */
/** When this value changes, update the internal search content */
refreshValue?: string;
onSearch?: (value?: string) => void;
placeholder?: string;

View File

@@ -106,7 +106,7 @@ export const SelectSpaceModal: React.FC<
const params = form.current?.formApi.getValues();
await onConfirm?.(params?.spaceId ?? '', params?.name);
} catch {
// 审核不通过会走到这个逻辑,调用接口处会上报自定义异常
// If the review fails, you will go to this logic, and a custom exception will be reported at the calling interface.
setLoading(false);
}
}}

View File

@@ -21,7 +21,7 @@ export type OnMove<TId = string | number> = (
souceId: TId,
targetId: TId,
isBefore: boolean,
) => void; // 因为没有顺序信息,所以需要指明是在前面还是后面
) => void; // Since there is no order information, it is necessary to specify whether it is before or after
export interface UseDndSortableParams<TId = string | number> {
id: TId;
type: symbol;
@@ -61,7 +61,7 @@ export const useDnDSortableItem = <TId = string | number>({
if (!itemDomRef.current || item.id === id) {
return;
}
// 当前被拖拽元素的 X Y 坐标
// The X Y coordinates of the currently dragged element
const draggingClient = monitor.getClientOffset();
const dropTargetClient = itemDomRef.current?.getBoundingClientRect();
let isBefore = false;

View File

@@ -87,7 +87,7 @@ export const SortableList = <TData extends object>({
enabled={enabled}
direction={direction}
/**
* 原始数组 [1, 2, target, 4, 5, source, 7, 8]
* Raw array [1, 2, target, 4, 5, source, 7, 8]
* before = true j==> [1,2, source, target, 4, 5, 7, 8]
* before = false ==> [1,2, target, source, 4, 5, 7, 8]
**/
@@ -101,7 +101,7 @@ export const SortableList = <TData extends object>({
newList.findIndex(target => getId(target) === targetId) +
(before ? 0 : 1);
if (sourceIndex === targetIndex) {
// 前后 index 相同的情况不触发 onChange 避免频繁 rerender
// Do not trigger onChange if the index is the same before and after to avoid frequent rerender
return;
}
sourceItem && newList.splice(targetIndex, 0, sourceItem);

View File

@@ -58,7 +58,7 @@ export const BaseSpaceFormSelect = withField(
return;
}
// 需要触发表单 onChange 事件 否则上层响应不到数据变化的事件
// The form onChange event needs to be triggered, otherwise the upper layer will not respond to the data change event.
props.onChange?.(fixedInitValue);
}, [fixedInitValue]);

View File

@@ -20,24 +20,24 @@ import cls from 'classnames';
import { useScroll } from 'ahooks';
interface StickyProps {
/** 滚动容器,也就是那个 scrollHeight 大于 viewportHeightoverflow-y auto/scroll 的容器 */
/** Scroll container, that is, the container with scrollHeight greater than viewportHeight and overflow-y auto/scroll */
scrollContainerRef: () => Element;
/**
* 作用同 css sticky 时的 top 属性
* The top property when used as a css sticky
* @default 0
*/
top?: number;
/**
* 触发 sticky 后,底部(为了美观)额外的滚动距离
* After triggering sticky, the bottom (for aesthetics) has an extra scroll distance
* @default 0
*/
bottom?: number;
}
/**
* sticky 容器组件,用于解决 sticky 元素高于视窗时无法全部露出的问题
* Sticky container component, used to solve the problem that sticky elements cannot be fully exposed when they are higher than the viewport
*
* 效果是触发 sticky 后,sticky 容器会跟随滚动容器的滚动而有限地上下移动
* The effect is that after triggering the sticky, the sticky container will follow the scroll of the scrolling container and move up and down limited.
*/
export function Sticky({
top: stickyTop = 0,
@@ -46,11 +46,11 @@ export function Sticky({
children,
}: PropsWithChildren<StickyProps>) {
const stickyContainerRef = useRef<HTMLDivElement>(null);
/** 一个不可见的元素,用于通过 IntersectionObserver 检测是否已经 sticky */
/** An invisible element used to detect whether it is sticky by IntersectionObserver */
const stickyDetectRef = useRef<HTMLDivElement>(null);
const [isSticky, setIsSticky] = useState(false);
const prevScrollTop = useRef(scrollContainerRef()?.scrollTop || 0);
// sticky 容器模拟向上滚动的距离
// Sticky container simulates the distance of scrolling up
const [simulateScrollDistance, setSimulateScrollDistance] = useState(0);
useEffect(() => {
@@ -58,7 +58,7 @@ export function Sticky({
return;
}
/** IntersectionObserver 监听是否触发 sticky */
/** IntersectionObserver monitor if sticky is triggered */
const intersectionObserver = new IntersectionObserver(
([entry]) => {
const { isIntersecting } = entry;
@@ -73,34 +73,34 @@ export function Sticky({
};
}, []);
// 已测试该方法能监听 `scrollTo` 等方法产生的 scroll无论模式是 smooth 还是 instant
// It has been tested that this method can listen to scrolls generated by methods such as'scrollTo ', regardless of whether the mode is smooth or instant.
useScroll(scrollContainerRef, scrollEvent => {
/** 页面整体向上scrollbar 向下移动)滚动的距离,为负则代表页面向下滚动 */
/** The distance where the page scrolls up as a whole (scrollbar moves down). If it is negative, it means the page scrolls down. */
const scrollUpDistance = scrollEvent.top - prevScrollTop.current;
prevScrollTop.current = scrollEvent.top;
if (!stickyContainerRef.current || !isSticky) {
// return false 避免 useScroll 产生 rerender,下同
// (回调内的其他 setState 会正常触发 rerender
// Return false to avoid useScroll rerender
// (Other setStates within the callback will trigger rerender normally)
return false;
}
const viewportHeight = window.innerHeight;
const stickyContainerHeight = stickyContainerRef.current?.scrollHeight || 0;
/** 触发 sticky 后,模拟滚动的容器高度 */
/** After triggering sticky, simulate the height of the rolling container */
const simulateStickyContainerHeight =
stickyContainerHeight + stickyTop + stickyBottom;
// 判断高度是否小于 viewport是的话始终能正常显示在视图内不用后面乱七八糟一堆计算了
// Determine whether the height is less than the viewport. If so, it can always be displayed in the view normally, and there is no need to make a mess of calculations later.
if (simulateStickyContainerHeight < viewportHeight) {
return false;
}
/** 模拟滚动容器比视窗高出的部分,也即模拟滚动的上限 */
/** The part of the simulated scrolling container higher than the viewport, that is, the upper limit of the simulated scrolling */
const simulateMaxScrollDistance =
simulateStickyContainerHeight - viewportHeight;
if (scrollUpDistance > 0) {
// #region 处理向上滚动
// #region processing scroll up
const stickyReachedBottom =
simulateScrollDistance >= simulateMaxScrollDistance;
if (stickyReachedBottom) {
@@ -116,7 +116,7 @@ export function Sticky({
return false;
// #endregion
} else {
// #region 处理向下滚动
// #region processing scroll down
const stickyReachedTop = simulateScrollDistance <= 0;
if (stickyReachedTop) {
setSimulateScrollDistance(0);

View File

@@ -56,7 +56,7 @@ export const TableSelectAllPopover: FC<
>
{I18n.t('publish_permission_control_page_remove_choose_all')}
</Checkbox>
{/* 确保全选和右侧区域有一个最小间隔 */}
{/* Make sure there is a minimum interval between Select All and the right area */}
<div className="flex-1 min-w-[40px]" />
{renderCount ? (
<div>

View File

@@ -28,12 +28,12 @@ import {
type ParamsTypeDefine,
} from '@coze-arch/bot-tea';
/** 后续考虑通用化封装,增加诸如延迟时间、露出比例等参数 */
/** Subsequent consideration of generalized packaging, adding parameters such as delay time and exposure ratio */
type TeaExposureProps<TEventName extends EVENT_NAMES> = {
/**
* 是否只上报一次
* Is it only reported once?
* @default false
* @todo 有余力再考虑兼容虚拟滚动
* @Todo has the spare time to reconsider compatibility with virtual scrolling
*/
once?: boolean;
teaEvent: {
@@ -44,13 +44,13 @@ type TeaExposureProps<TEventName extends EVENT_NAMES> = {
HTMLAttributes<HTMLDivElement>;
/**
* 曝光埋点上报组件
* 可以当成普通的 div 来用(比如配置样式)
* Exposure event tracking report component
* It can be used as a normal div (e.g. configuration style).
*
* 封装的意义:避免组件 rerender
* The meaning of encapsulation: avoid component rerendering
*
* useInViewport 会造成组件频繁 rerender哪怕你并未使用其返回值只要调用了这个 hook就会随着其内部的 setState 触发 rerender。
* 而我们都知道对于下面这段代码A rerender 会触发 B 和 C 的rerender而 B rerender 不会触发 A 和 C 的 rerender。
* useInViewport causes the component to rerender frequently, even if you don't use its return value. As long as this hook is called, rerender will be triggered with its internal setState.
* And we all know that for the following code, A rerender will trigger the rerender of B and C, while B rerender will not trigger the rerender of A and C.
* ```
* const A = () => <B><C /></B>
* ```

View File

@@ -23,7 +23,7 @@ vi.stubGlobal('SAMI_APP_KEY', vi.fn());
vi.stubGlobal('IS_DEV_MODE', false);
vi.stubGlobal('IS_OVERSEA', false);
// Mock Canvas API 完整版本
// Mock Canvas API full version
const createMockCanvas = () => ({
getContext: vi.fn(() => ({
fillRect: vi.fn(),
@@ -82,14 +82,14 @@ if (global.document) {
});
}
// CSS 文件 mock
// CSS file mock
vi.mock('*.css', () => ({}));
vi.mock('*.scss', () => ({}));
vi.mock('*.sass', () => ({}));
vi.mock('*.less', () => ({}));
vi.mock('*.styl', () => ({}));
// Mock lottie-web 完整版本
// Mock lottie-web full version
vi.mock('lottie-web', () => ({
default: {
loadAnimation: vi.fn(() => ({

View File

@@ -37,7 +37,7 @@ import {
export interface CreateAgentEntityProps {
onBefore?: () => void;
onError?: () => void;
/** 只有需要 onSuccess 回调阻断弹窗自动关闭时,才需要返回 Promise */
/** Return Promise only if you need the onSuccess callback to block the pop-up window from closing automatically. */
onSuccess?: (
botId?: string,
spaceId?: string,
@@ -51,13 +51,13 @@ export interface CreateAgentEntityProps {
mode: 'update' | 'add';
showSpace?: boolean;
/**
* 需要从外部控制在哪个空间创建 bot 时,传入此参数
* 仅适用于创建
* Pass this parameter when you need to control externally which space to create the bot in
* Only suitable for creating
*/
spaceId?: string;
/**
* navi 导航栏
* space workspace 右上角的按钮
* Navigation bar
* Button in the upper right corner of the space workspace
* */
bizCreateFrom?: 'navi' | 'space';
}
@@ -82,7 +82,7 @@ export const useCreateOrUpdateAgent = ({
onSuccess,
onError,
mode,
showSpace = false, // 默认不显示
showSpace = false, // Not displayed by default
spaceId: outerSpaceId,
bizCreateFrom,
}: CreateAgentEntityProps) => {
@@ -149,7 +149,7 @@ export const useCreateOrUpdateAgent = ({
}, [visible]);
/**
* @param _ 开源版本暂不支持此参数
* @Param _ open source version does not support this parameter
*/
const startEdit = (_?: boolean) => {
setVisible(true);

View File

@@ -56,7 +56,7 @@ const mockSetInfoRules: {
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'),
},
],
@@ -115,10 +115,10 @@ export const MockSetEditModal = ({
}: MockSetEditModalProps) => {
const formApiRef = useRef<FormApi<EditMockSetInfo>>();
// 根据是否传入 id 判断是否为创建场景
// Determine whether to create a scene based on whether to pass in the id
const isCreate = !initialInfo.id;
// space信息
// Space information
const spaceType = useSpaceStore(s => s.space.space_type);
const isPersonal = spaceType === SpaceType.Personal;
@@ -213,7 +213,7 @@ export const MockSetEditModal = ({
>
{({ formState }) => (
<>
{/* mockSet名称 */}
{/* mockSet name */}
{disabled ? (
<Form.Slot
label={{
@@ -241,7 +241,7 @@ export const MockSetEditModal = ({
rules={mockSetInfoRules.name}
/>
)}
{/* mockSet描述 */}
{/* mockSet description */}
{disabled ? (
<Form.Slot
label={{

View File

@@ -28,7 +28,7 @@
.editor-container_disabled {
:global {
.monaco-editor.no-user-select .view-lines {
/** 只读状态下 cursor 纠正为正常鼠标 **/
/** Correct cursor to normal mouse in read-only state **/
cursor: default;
}

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

@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import type { JSONSchema7, JSONSchema7TypeName } from 'json-schema';
import {
TrafficScene,
@@ -56,9 +56,9 @@ export const calcStringSize = (str: string) => {
const { size } = new Blob([str]);
return size;
};
// 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;
// 转换 DataWithStatus 格式到 Object 格式
// Convert DataWithStatus format to Object format
export function transDataWithStatus2Object(
data: MockDataWithStatus,
excludeRemovedItem?: boolean,
@@ -128,7 +128,7 @@ export function getMockValue(
}
}
// 由 schema 生成 DataWithStatus 时不同类型的生成逻辑
// Different types of generation logic when generating DataWithStatus from schema
function getInitialValue(
type: MockDataValueType,
): [string | number | boolean | undefined, string | undefined] {
@@ -144,7 +144,7 @@ function getSchemaType(type?: JSONSchema7TypeName | JSONSchema7TypeName[]) {
return val === 'null' ? undefined : (val as MockDataValueType);
}
// 转换 schema 格式到 DataWithStatus 格式(包含初始化逻辑)
// Convert schema format to DataWithStatus format (including initialization logic)
// eslint-disable-next-line complexity
export function transSchema2DataWithStatus(
label: string,
@@ -223,7 +223,7 @@ export function transSchema2DataWithStatus(
return item;
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- 内容结构依赖用户定义的 plugin resp 结构,包含任何可能
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- The content structure depends on the user-defined plugin resp structure, including any possible
export function stringifyEditorContent(value: any) {
return JSON.stringify(value, null, FORMAT_SPACE_SETTING);
}

View File

@@ -22,7 +22,7 @@ import { getExpirationTime } from '@/utils/time';
export const columnExpireAtConf: () => ColumnProps<PersonalAccessToken> =
() => ({
title: I18n.t('expire_time_1'), // 状态
title: I18n.t('expire_time_1'), // state
dataIndex: 'expire_at',
render: (expireTime: number) => getExpirationTime(expireTime),
});

View File

@@ -37,7 +37,7 @@ interface ResultProps {
onOk: () => void;
}
// 新建编辑 PAT
// New Edit PAT
export const ResultModal = ({ visible, onOk, data }: ResultProps) => {
const doCopyAsync = useMemoizedFn(() => {
const targetKey = data?.token;

View File

@@ -18,10 +18,10 @@ import dayjs from 'dayjs';
import { I18n, type I18nKeysNoOptionsType } from '@coze-arch/i18n';
const MAX_EXPIRATION_DAYS = 30;
// 1-30天有效期
// 1-30 days valid period
export const disabledDate = (date?: Date) => {
const today = dayjs().startOf('day'); // 当天的开始时间
const thirtyDaysLater = today.add(MAX_EXPIRATION_DAYS, 'day'); // 30天后的日期
const today = dayjs().startOf('day'); // Start time of the day
const thirtyDaysLater = today.add(MAX_EXPIRATION_DAYS, 'day'); // Date in 30 days
return (
dayjs(date).isBefore(today, 'day') ||

View File

@@ -40,16 +40,16 @@ export default defineConfig(
'src/components/**',
'src/pages/**',
'src/constants/**',
'src/utils/public-private-keys.ts', // window 提供的 api
'src/utils/docs.ts', // 线上未使用 仅 boe使用 即将删除
'src/utils/time.ts', // dayjs api 的调用
'src/utils/public-private-keys.ts', // Windows API
'src/utils/docs.ts', // Unused online, only boe used, about to be deleted
'src/utils/time.ts', // Dayjs API calls
'src/utils//analytics/index.ts',
'src/utils//analytics/chart.ts', // 有图表 dom 相关内容
'src/hooks/pat/action/**', // 操作类 hook
'src/hooks/oauth-app/action/**', // 操作类 hook
'src/hooks/use-arcosite.ts', // 线上未使用 仅 boe使用
'src/hooks/use-show-mask.ts', // 主要为获取 dom 的 scrollTop
'src/hooks/use-docs-path.ts', // useNavigate 相关内容
'src/hooks/pat/action/**', // Action class hook
'src/hooks/oauth-app/action/**', // Action class hook
'src/hooks/use-arcosite.ts', // Not used online, only boe used
'src/hooks/use-show-mask.ts', // Mainly scrollTop for getting dom
'src/hooks/use-docs-path.ts', // useNavigate related content
],
},
},

View File

@@ -22,9 +22,9 @@ export enum Layout {
}
export interface HeaderConfig {
isShow?: boolean; //是否显示header 默认是true
isNeedClose?: boolean; //是否需要关闭按钮, 默认是true
extra?: ReactNode | false; // 用于站位的,默认无
isShow?: boolean; //Whether to display headers, the default is true
isNeedClose?: boolean; //Whether you need the close button, the default is true.
extra?: ReactNode | false; // For standing, default none
}
export interface DebugProps {

View File

@@ -34,12 +34,12 @@ export interface IWorkflow {
export interface IProject {
id: string;
type: 'app' | 'bot';
mode: 'draft' | 'release' | 'websdk' | 'audit'; // 草稿模式 | 发布模式 | webSdk发布
mode: 'draft' | 'release' | 'websdk' | 'audit'; // Draft Mode | Publish Mode | webSdk Publish
caller?: 'UI_BUILDER' | 'CANVAS';
connectorId?: string;
conversationName?: string; // project的话,必须填写
conversationId?: string; // type 为bot的话必须填写
sectionId?: string; // type 为bot的话必须填写
conversationName?: string; // Project must be filled in
conversationId?: string; // If the type is bot, it must be filled in
sectionId?: string; // If the type is bot, it must be filled in
name?: string;
defaultName?: string;
defaultIconUrl?: string;
@@ -68,28 +68,28 @@ export interface IBuilderChatProps {
eventCallbacks?: IEventCallbacks;
userInfo: IChatFlowProps['userInfo'];
areaUi: {
isDisabled?: boolean; // 默认 false
uploadable?: boolean; // 默认 true
isNeedClearContext?: boolean; // 是否显示 clearContext按钮
isNeedClearMessage?: boolean; // 是否显示 clearMessage按钮
isDisabled?: boolean; // Default false
uploadable?: boolean; // Default true
isNeedClearContext?: boolean; // Whether to display the clearContext button
isNeedClearMessage?: boolean; // Whether to display the clearMessage button
//isShowHeader?: boolean; // 默认 false
//isShowFooter?: boolean; // 默认 false
//isShowHeader?: boolean;//default false
//isShowFooter?: boolean;//default false
input?: {
placeholder?: string;
renderChatInputTopSlot?: (isChatError?: boolean) => React.ReactNode;
isShow?: boolean; //默认 true
isShow?: boolean; //Default true
defaultText?: string;
isNeedAudio?: boolean; // 是否需要语音输入,默认是false
isNeedAudio?: boolean; // Whether voice input is required, the default is false
isNeedTaskMessage?: boolean;
};
header?: HeaderConfig; // 默认是
header?: HeaderConfig; // Default is
footer?: FooterConfig;
uiTheme?: 'uiBuilder' | 'chatFlow'; // uiBuilder 的主题
uiTheme?: 'uiBuilder' | 'chatFlow'; // Theme for uiBuilder
renderLoading?: () => React.ReactNode;
};
auth?: {
type: 'external' | 'internal'; // 内部: cookie换token 外部: internal
type: 'external' | 'internal'; // Internal: cookie for token, external: internal
token?: string;
refreshToken?: () => Promise<string> | string;
};

View File

@@ -15,7 +15,7 @@
*/
/**
* 依赖 treeShaking 去除无关配置(Argus)
* Dependency treeShaking Removes Extraneous Configuration (Argus)
*/
const sdkRegion = 'cn';
export const iframeAppHost = '';
@@ -28,7 +28,7 @@ export const openApiCdnUrlByRegion = IS_OVERSEA
: // cp-disable-next-line
'https://lf3-static.bytednsdoc.com/obj/eden-cn/rkzild_lgvj/ljhwZthlaukjlkulzlp/';
// 用户需要修改此处baseurl用于开放平台接口的域名配置
// The user needs to modify the baseurl here to open the domain name configuration of the API interface
export const openApiHostByRegion =
typeof location !== 'undefined' ? location.origin : 'https://api.xxx.com';
export const openApiHostByRegionWithToken = openApiHostByRegion;

View File

@@ -60,7 +60,7 @@ export const usePluginFormState = (): UsePluginFormStateReturn => {
const [headerList, setHeaderList] = useState<commonParamSchema[]>([
{ name: 'User-Agent', value: 'Coze/1.0' },
]);
// 合规审核结果
// Compliance audit results
const [isValidCheckResult, setIsValidCheckResult] = useState(true);
const [pluginTypeCreationMethod, setPluginTypeCreationMethod] =
useState<string>();

View File

@@ -110,7 +110,7 @@ export const PluginForm: FC<{
const [mainAuthType, setMainAuthType] = useState<number>(0);
const [authType, setAuthType] = useState<number>(0);
const [disableEditUrl, setDisableEditUrl] = useState<boolean>(false);
// 合规审核结果
// Compliance audit results
const changeVal = () => {
if (!isValidCheckResult) {
setIsValidCheckResult(true);
@@ -147,7 +147,7 @@ export const PluginForm: FC<{
},
);
/**
* 获取默认icon, 并设置到form
* Get the default icon, and set it to the form
*/
const getIcon = async () => {
try {
@@ -175,16 +175,16 @@ export const PluginForm: FC<{
}
if (!isCreate && editInfo) {
/**
* 以下的 useState 都是更新插件
* The following useStates are all update plugins
*/
/**
* service在本次需求中被拓展了二级菜单service的一级菜单为1二级菜单为012
* 后端为了不改动历史逻辑新增一个sub_auth_type的字段去记录service下的二级菜单的值但是authType依旧是一个length为1的数组并且值为1
* 因此前端需要手动判断auth_type为1的时候把sub_auth_type塞进去组成一个length为2的数组才能让casdar菜单回填editInfo的内容
* 567是给前端用的用来判断选中的是哪个。5是apiKey、6是zero、7是oicd
* 好问题来了。authType是一个数组但是长度不固定
* 1. 当auth_type长度为1时代表是service内容有且只有1此时sub_auth_type为012中的一个
* 2. 当auth_type长度为2时代表是oAuth内容为[3,4]此时没有sub_auth_type
* Service has been expanded to the secondary menu in this demand. The primary menu of service is 1, and the secondary menu is 0, 1, 2.
* In order not to change the history logic, the backend adds a sub_auth_type field to record the value of the secondary menu under the service, but the authType is still an array of length 1 and the value is 1.
* Therefore, when the front end needs to manually determine that the auth_type is 1, the sub_auth_type is stuffed in to form an array of length 2, so that the casdar menu can backfill the content of editInfo
* 5, 6, and 7 are for the front end to determine which one is selected. 5 is apiKey, 6 is zero, and 7 is oicd.
* Good question. AuthType is an array, but the length is not fixed:
* When the length of the auth_type is 1, it means that it is a service, and the content has and only 1. At this time, the sub_auth_type is one of 0, 1, and 2
* 2. When the auth_type length is 2, it means oAuth, and the content is [3,4]. There is no sub_auth_type at this time
*/
if (editInfo.meta_info?.auth_type?.at(0) === 1) {
switch (editInfo.meta_info?.sub_auth_type) {
@@ -220,7 +220,7 @@ export const PluginForm: FC<{
`${editInfo.plugin_type}-${editInfo.creation_method}`,
);
// 如果存在私网连接则禁用编辑URL
// Disable editing URLs if there is a private network connection
if (
editInfo?.meta_info?.private_link_id &&
compareLevel === UserLevel.Enterprise &&
@@ -234,7 +234,7 @@ export const PluginForm: FC<{
}, [visible]);
const reset = () => {
//重置插件
//Reset plugin
getIcon();
setAuthType(0);
setAuthType(0);
@@ -244,20 +244,20 @@ export const PluginForm: FC<{
setPluginTypeCreationMethod(undefined);
};
/** 添加header */
/** Add header */
const addHeader = () => {
setHeaderList(list => [...list, { name: '', value: '' }]);
};
/** 删除header */
/** Delete header */
const deleteHeader = (index: number) => {
// 若为最后一个header则只清空内容不删除
// If it is the last header, only empty the content, not delete it
setHeaderList(list =>
list.length <= 1
? [{ name: '', value: '' }]
: list.filter((_, i) => i !== index),
);
};
/** 编辑header */
/** Edit header */
const editHeader = (index: number, header: commonParamSchema) => {
setHeaderList(list => list.map((item, i) => (i === index ? header : item)));
};
@@ -267,17 +267,17 @@ export const PluginForm: FC<{
if (!editInfo) {
authTypeInitValue = [0];
}
// OAuth 的情况
// It's OAuth's case
if (editInfo?.meta_info?.auth_type?.length === 2) {
authTypeInitValue = editInfo?.meta_info?.auth_type;
}
// service & no auth
else {
// 不需要授权,自然没有sub_auth_type
// No authorization required, naturally no sub_auth_type
if (editInfo?.meta_info?.auth_type?.at(0) === 0) {
authTypeInitValue = editInfo?.meta_info?.auth_type;
}
// service, sub_auth_type
// Service, with sub_auth_type
else {
if (typeof editInfo?.meta_info?.sub_auth_type !== 'undefined') {
authTypeInitValue = [
@@ -316,7 +316,7 @@ export const PluginForm: FC<{
/>
) : null}
{/* 插件URL */}
{/* plugin URL */}
{!disabled ? (
<FormInput
disabled={disableEditUrl}
@@ -335,7 +335,7 @@ export const PluginForm: FC<{
rules={disableEditUrl ? [] : formRuleList.url}
/>
) : null}
{/* 插件Header */}
{/* Plugin Header */}
<Form.Slot
className={s['header-list']}
label={{
@@ -424,7 +424,7 @@ export const PluginForm: FC<{
</div>
</Form.Slot>
{/* 授权方式 */}
{/* Authorization method */}
<FormCascader
disabled={disabled}
@@ -455,7 +455,7 @@ export const PluginForm: FC<{
}}
/>
{/* 授权方式 - Service - Service Token / API Key */}
{/* Authorization - Service - Service Token/API Key */}
{mainAuthType === 1 && authType === 5 && (
<>
<Form.RadioGroup
@@ -500,7 +500,7 @@ export const PluginForm: FC<{
</>
)}
{/* 服务端动态返回授权项 */}
{/* Server level dynamic return authorization */}
{/* Service - OIDC & OAuth - Standard Mode */}
{extItems?.map((item, index) => {
let formInfo: Record<string, any> = {};
@@ -592,7 +592,7 @@ export const PluginForm: FC<{
case 1:
setAuthType(6);
break;
//@ts-expect-error 授权类型兼容
// @ts-expect-error Authorization type compatible
case 2:
setAuthType(7);
break;
@@ -609,7 +609,7 @@ export const PluginForm: FC<{
}
}}
>
{/* 插件头像 */}
{/* plugin avatar */}
<PictureUpload
noLabel
disabled={disabled}
@@ -621,7 +621,7 @@ export const PluginForm: FC<{
onChange={changeVal}
/>
{/* 插件名称/插件描述/url/插件类型 */}
{/* Plugin name/plugin description/url/plugin type */}
<>
<FormTextArea
disabled={disabled}
@@ -662,7 +662,7 @@ export const PluginForm: FC<{
onChange={changeVal}
rules={formRuleList.desc}
/>
{/* 插件类型 */}
{/* plugin type */}
<Form.Slot
label={{
text: I18n.t('plugin_creation_method'),

View File

@@ -43,7 +43,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'),
},
],
@@ -52,7 +52,7 @@ export const formRuleList = {
required: true,
message: I18n.t('create_plugin_modal_descrip1_error'),
},
// 只有cn 线上才支持中文
// Only cn online supports Chinese.
IS_OVERSEA || IS_BOE
? {
// eslint-disable-next-line no-control-regex -- regex
@@ -110,7 +110,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 */
export const findAuthTypeItem = (data: AuthOption[], targetKey = 0) => {
for (const item of data) {
if (item.value === targetKey) {
@@ -168,7 +168,7 @@ export interface UsePluginSchameReturnValue {
defaultRuntime: string;
}
// 获取schame runtime options
// Get schame and runtime options
export const usePluginSchame = (): UsePluginSchameReturnValue => {
const [authOption, setAuthOption] = useState<AuthOption[]>([]);
const [runtimeOptions, setRuntimeOptions] = useState<RuntimeOptionsType[]>(

View File

@@ -70,7 +70,7 @@ import s from './index.module.less';
const { Text, Paragraph } = Typography;
const stopPro = (e: MouseEvent<HTMLDivElement>) => {
e.stopPropagation(); //阻止冒泡
e.stopPropagation(); //Stop bubbling
};
const exampleStatusConfig = {
@@ -134,7 +134,7 @@ export const useGetToolColumns = (props: UseGetToolColumnsProps) => {
customRender,
} = props ?? {};
/** 是否开启api */
/** Whether to open api */
const openApi = async ({
apiId,
disabled,
@@ -216,7 +216,7 @@ export const useGetToolColumns = (props: UseGetToolColumnsProps) => {
color="grey"
size="small"
style={{
/** 确保没有极端的闪动case */
/** Make sure there are no extreme flashing cases */
fontVariantNumeric: 'tabular-nums',
}}
>
@@ -443,7 +443,7 @@ export const useGetToolColumns = (props: UseGetToolColumnsProps) => {
visible={record.api_id === showDropdownItem?.api_id}
render={
<Dropdown.Menu className="px-[4px]">
{/* 即将支持,敬请期待 */}
{/* Support soon, so stay tuned. */}
{FLAGS2['bot.devops.plugin_import_export'] ? (
<Dropdown.Item
disabled={
@@ -459,7 +459,7 @@ export const useGetToolColumns = (props: UseGetToolColumnsProps) => {
{I18n.t('code_snippet')}
</Dropdown.Item>
) : null}
{/* 即将支持,敬请期待 */}
{/* Support soon, so stay tuned. */}
{FLAGS2['bot.devops.plugin_mockset'] ? (
<Dropdown.Item
className="rounded-[4px]"

View File

@@ -16,8 +16,8 @@
export { useFetchKnowledgeBenefit } from './use-fetch-knowledge-benefit';
export enum PremiumPaywallBannerScene {
Knowledge, // 知识库场景
Token, // 其余 Token 消耗场景
Knowledge, // Knowledge base scenario
Token, // Token consumption scenarios
}
export function PremiumPaywallBanner(_props: {

View File

@@ -15,27 +15,27 @@
*/
export enum PremiumPaywallScene {
// 创建新空间
// Create a new space
AddSpace,
// 新模型体验
// New model experience
NewModel,
// 付费用户模板
// paid user template
ProTemplate,
// 添加空间成员
// Add space member
AddSpaceMember,
// 协作
// collaboration
Collaborate,
// 跨空间资源复制
// Cross-spatial resource replication
CopyResourceCrossSpace,
// 发布到API或者SDK
// Publish to API or SDK
API,
// 添加音色资源
// Add Timbre Resources
AddVoice,
// 实时语音对话
// real-time voice conversation
RTC,
// 导出日志
// export log
ExportLog,
// 查询日志
// query log
FilterLog,
}
export function useBenefitAvailable(_props: unknown) {

View File

@@ -17,17 +17,17 @@
import { UserLevel, type MemberVersionRights } from '../types';
interface UseBenefitBasicResult {
name: string; // 当前用户套餐名称
level: UserLevel; // 当前工作空间:用户的套餐级别
compareLevel: UserLevel; // 当前工作空间:如果是专业版,值是 UserLevel.ProPersonal,其他场景同 level
currPlan: MemberVersionRights; // 当前套餐信息
nextPlan: MemberVersionRights; // 下一个套餐信息。如果当前已经是最高套餐级别,则值为最高级别套餐
accountPlan: MemberVersionRights; // 账号维度的套餐信息
instanceStatus: unknown; // 当前套餐状态,可以用来判断退订/到期状态
isOverdue: boolean; // 是否欠费
isExpired: boolean; // 是否过期
isTerminated: boolean; // 是否退订
maxMember: number; //成员上限
name: string; // Current user package name
level: UserLevel; // Current Workspace: User's plan level
compareLevel: UserLevel; // Current workspace: If it is a professional version, the value is UserLevel. ProPersonal, and other scenes are at the same level.
currPlan: MemberVersionRights; // Current package information
nextPlan: MemberVersionRights; // Next package information. If it is already the highest package level, the value is the highest package level.
accountPlan: MemberVersionRights; // Package information in the account dimension
instanceStatus: unknown; // The current package status can be used to determine the unsubscribe/expiration status.
isOverdue: boolean; // Is it in arrears?
isExpired: boolean; // Whether it has expired
isTerminated: boolean; // Whether to unsubscribe
maxMember: number; //maximum membership
}
const defaultData = {
@@ -44,7 +44,7 @@ const defaultData = {
maxMember: -1,
};
/**
* 获取国内权益基础信息
* Acquire basic information on domestic rights and interests
*/
export function useBenefitBasic(): UseBenefitBasicResult {
return defaultData;

View File

@@ -15,11 +15,11 @@
*/
const quota = {
/** 当前消耗的额度,对应到套餐内每天刷新的 */
/** The current consumption amount corresponds to the daily refresh in the package. */
remain: 0,
total: 0,
used: 0,
/** 额外购买的额度,目前只处理国内 */
/** The additional purchase amount is currently only processed in China. */
extraRemain: 0,
extraTotal: 0,
extraUsed: 0,

View File

@@ -27,7 +27,7 @@ import {
type MemberVersionRights,
} from '../types';
// 只处理最低和最高订阅服务档位
// Only handle the lowest and highest subscription service gears
export enum PremiumPlanLevel {
Free = 0,
@@ -47,31 +47,31 @@ export interface VolcanoInfo {
}
interface PremiumStoreState {
polling: boolean; // 是否开启订阅数据自动轮询
plans: PremiumPlan[]; // 付费订阅计划列表
subs: PremiumSubs; // 所有订阅数据
currentPlan: SubscriptionDetail; // 当前订阅详情
polling: boolean; // Whether to enable automatic polling of subscription data
plans: PremiumPlan[]; // List of paid subscription plans
subs: PremiumSubs; // All subscription data
currentPlan: SubscriptionDetail; // Current subscription details
hasTrial: boolean;
connections: BindConnection[]; // 第三方账号连接数据
benefit: SubscriptionDetailV2; // 用户权益数据
plansCN: Array<MemberVersionRights>; // 国内订阅套餐列表
volcanoInfo: VolcanoInfo; // oauth跳转到火山需要用到的参数
connections: BindConnection[]; // third-party account connection data
benefit: SubscriptionDetailV2; // user rights data
plansCN: Array<MemberVersionRights>; // List of domestic subscription packages
volcanoInfo: VolcanoInfo; // Oauth jump to the volcano required parameters
}
interface PremiumStoreAction {
/**
* 重置状态
* reset state
*/
reset: () => void;
/**
* 设置是否轮询获取订阅数据,以下场景需要:
* - Bot详情判断是否需要显示订阅卡片
* - 左侧菜单栏判断是否需要显示'coze premium'
* - 左侧菜单栏展示credits数量信息
* To set whether to poll for subscription data, the following scenarios are required:
* - Bot details to determine whether the subscription card needs to be displayed
* - The left menu bar determines whether to display'coze premium'
* - The left menu bar displays the number of credits
*/
setPolling: (polling: boolean) => void;
/**
* 获取海外订阅套餐列表
* Get a list of overseas subscription packages
*/
fetchPremiumPlans: () => Promise<{
plans: PremiumPlan[];
@@ -79,35 +79,35 @@ interface PremiumStoreAction {
hasTrial: boolean;
}>;
/**
* 设置国内套餐列表
* Set up a list of domestic packages
*/
setPremiumPlansCN: (plans: Array<MemberVersionRights>) => void;
/**
* 恢复订阅,暂时只有海外
* Resume subscription, only overseas for the time being
*/
renewCurrentPlan: (plan: SubscriptionDetail) => void;
/**
* 获取当前用户订阅详情,暂时只有海外
* Get the current user subscription details, only overseas for the time being
*/
fetchPremiumPlan: () => Promise<SubscriptionDetail>;
/**
* 取消订阅,暂时只有海外
* Cancel the subscription, only overseas for the time being.
*/
cancelCurrentPlan: () => void;
/**
* 获取渠道绑定信息,暂时只有海外
* Get channel binding information, only overseas for the time being.
*/
fetchConnections: () => Promise<void>;
/**
* 取消渠道用户绑定,暂时只有海外
* Cancel the channel user binding, only overseas for the time being
*/
disconnectUser: (connectorId: string) => void;
/**
* 设置当前登录用户权益信息,海内外通用
* Set the current logged in user rights and interests information, common at home and abroad
*/
setUserBenefit: (benefit: unknown) => void;
/**
* 设置当前账号相关火山信息
* Set the current account related volcano information
*/
setVolcanoInfo: (info: VolcanoInfo) => void;
}

View File

@@ -26,22 +26,22 @@ import {
import { type BindConnection } from '@coze-arch/bot-api/developer_api';
export enum UserLevel {
/** 免费版。 */
/** The free version. */
Free = 0,
/** 海外
/** overseas
PremiumLite */
PremiumLite = 10,
/** Premium */
Premium = 15,
PremiumPlus = 20,
/** 国内
V1火山专业版 */
/** domestic
V1 Volcano Pro */
V1ProInstance = 100,
/** 个人旗舰版 */
/** Personal flagship version */
ProPersonal = 110,
/** 团队版 */
/** Team Edition */
Team = 120,
/** 企业版 */
/** Enterprise Edition */
Enterprise = 130,
}

View File

@@ -52,7 +52,7 @@ export const useIsPublishRecordReady = ({
{
manual: true,
ready: enable,
pollingInterval: 60 * 1000, // 60 秒轮询一次,避免过高频率请求导致服务端压力大
pollingInterval: 60 * 1000, // Polling once every 60 seconds to avoid server level stress due to high frequency requests
pollingErrorRetryCount: 3,
onSuccess: target => {
if (target) {

View File

@@ -22,24 +22,24 @@ import { chatBackgroundConfig } from '../../../../../src/save-manager/auto-save/
describe('chatBackgroundConfig', () => {
it('应该具有正确的配置属性', () => {
// 验证配置的基本属性
// Verify the basic properties of the configuration
expect(chatBackgroundConfig).toHaveProperty('key');
expect(chatBackgroundConfig).toHaveProperty('selector');
expect(chatBackgroundConfig).toHaveProperty('debounce');
expect(chatBackgroundConfig).toHaveProperty('middleware');
// 验证 middleware 存在且有 onBeforeSave 属性
// Verify that middleware exists and has an onBeforeSave attribute
expect(chatBackgroundConfig.middleware).toBeDefined();
if (chatBackgroundConfig.middleware) {
expect(chatBackgroundConfig.middleware).toHaveProperty('onBeforeSave');
}
// 验证属性值
// Validate attribute value
expect(chatBackgroundConfig.key).toBe(ItemTypeExtra.ChatBackGround);
expect(chatBackgroundConfig.debounce).toBe(DebounceTime.Immediate);
expect(typeof chatBackgroundConfig.selector).toBe('function');
// 验证 onBeforeSave 是函数
// Verify that onBeforeSave is a function
if (
chatBackgroundConfig.middleware &&
chatBackgroundConfig.middleware.onBeforeSave
@@ -51,49 +51,49 @@ describe('chatBackgroundConfig', () => {
});
it('selector 应该返回 store 的 backgroundImageInfoList 属性', () => {
// 创建模拟 store
// Create mock store
const mockStore = {
backgroundImageInfoList: [
{ id: 'bg1', url: 'http://example.com/bg1.jpg' },
],
};
// 调用 selector 函数
// 注意:这里我们假设 selector 是一个函数,如果它是一个复杂对象,可能需要调整测试
// Call the selector function
// Note: Here we assume that the selector is a function, and if it is a complex object, the test may need to be adjusted
const { selector } = chatBackgroundConfig;
let result;
if (typeof selector === 'function') {
result = selector(mockStore as any);
// 验证结果
// validation result
expect(result).toBe(mockStore.backgroundImageInfoList);
} else {
// 如果 selector 不是函数,跳过这个测试
// If the selector is not a function, skip this test
expect(true).toBe(true);
}
});
it('middleware.onBeforeSave 应该正确转换数据', () => {
// 创建模拟数据
// Create simulated data
const mockData = [
{ id: 'bg1', url: 'http://example.com/bg1.jpg' },
{ id: 'bg2', url: 'http://example.com/bg2.jpg' },
];
// 确保 middleware onBeforeSave 存在
// Make sure middleware and onBeforeSave exist
if (
chatBackgroundConfig.middleware &&
chatBackgroundConfig.middleware.onBeforeSave
) {
// 调用 onBeforeSave 函数
// Call the onBeforeSave function
const result = chatBackgroundConfig.middleware.onBeforeSave(mockData);
// 验证结果
// validation result
expect(result).toEqual({
background_image_info_list: mockData,
});
} else {
// 如果 middleware onBeforeSave 不存在,跳过这个测试
// If middleware or onBeforeSave does not exist, skip this test
expect(true).toBe(true);
}
});

View File

@@ -28,7 +28,7 @@ import { knowledgeConfig } from '../../../../../src/save-manager/auto-save/bot-s
import { chatBackgroundConfig } from '../../../../../src/save-manager/auto-save/bot-skill/configs/chat-background';
import { registers } from '../../../../../src/save-manager/auto-save/bot-skill/configs';
// 模拟依赖
// simulated dependency
vi.mock(
'../../../../../src/save-manager/auto-save/bot-skill/configs/workflows',
() => ({
@@ -101,7 +101,7 @@ vi.mock(
describe('bot-skill configs', () => {
it('应该正确注册所有配置', () => {
// 验证 registers 数组包含所有配置
// Verify that the registers array contains all configurations
expect(registers).toContain(pluginConfig);
expect(registers).toContain(chatBackgroundConfig);
expect(registers).toContain(onboardingConfig);
@@ -113,7 +113,7 @@ describe('bot-skill configs', () => {
expect(registers).toContain(workflowsConfig);
expect(registers).toContain(voicesInfoConfig);
// 验证 registers 数组长度
// Verify the length of the registers array
expect(registers.length).toBe(10);
});

View File

@@ -26,7 +26,7 @@ describe('knowledgeConfig', () => {
expect(knowledgeConfig).toHaveProperty('debounce');
expect(knowledgeConfig).toHaveProperty('middleware');
expect(knowledgeConfig.key).toBe(ItemType.DataSet);
// 验证 debounce 配置
// Verify debounce configuration
if (typeof knowledgeConfig.debounce === 'object') {
expect(knowledgeConfig.debounce).toHaveProperty('default');
expect(knowledgeConfig.debounce).toHaveProperty('dataSetInfo.min_score');

View File

@@ -26,7 +26,7 @@ describe('onboardingConfig', () => {
expect(onboardingConfig).toHaveProperty('debounce');
expect(onboardingConfig).toHaveProperty('middleware');
expect(onboardingConfig.key).toBe(ItemType.ONBOARDING);
// 验证 debounce 配置
// Verify debounce configuration
if (typeof onboardingConfig.debounce === 'object') {
expect(onboardingConfig.debounce).toHaveProperty('default');
expect(onboardingConfig.debounce).toHaveProperty('prologue');

View File

@@ -18,7 +18,7 @@ import { describe, it, expect, vi, beforeEach } from 'vitest';
import { botSkillSaveManager } from '../../../../src/save-manager/auto-save/bot-skill';
// 模拟依赖
// simulated dependency
vi.mock('@coze-studio/autosave', () => {
const mockStartFn = vi.fn();
const mockCloseFn = vi.fn();
@@ -52,16 +52,16 @@ describe('botSkillSaveManager', () => {
});
it('应该是 AutosaveManager 的实例', () => {
// 验证 botSkillSaveManager AutosaveManager 的实例
// Verify that botSkillSaveManager is an instance of AutosaveManager
expect(botSkillSaveManager).toBeDefined();
// 由于我们模拟了 AutosaveManager我们不能直接检查实例类型
// 但可以检查它是否具有 AutosaveManager 实例应有的属性和方法
// Since we simulate AutosaveManager, we cannot directly check the instance type
// But you can check if it has the properties and methods that an AutosaveManager instance should have
expect(botSkillSaveManager).toHaveProperty('start');
expect(botSkillSaveManager).toHaveProperty('close');
});
it('应该具有 start 和 close 方法', () => {
// 验证 botSkillSaveManager 具有 start close 方法
// Verify botSkillSaveManager has a start and close method
expect(botSkillSaveManager.start).toBeDefined();
expect(botSkillSaveManager.close).toBeDefined();
expect(typeof botSkillSaveManager.start).toBe('function');
@@ -69,16 +69,16 @@ describe('botSkillSaveManager', () => {
});
it('调用 start 方法应该正常工作', () => {
// 调用 start 方法
// Call the start method
botSkillSaveManager.start();
// 由于我们已经模拟了 start 方法,这里只需验证它可以被调用而不会抛出错误
// Since we have already simulated the start method, we just need to verify that it can be called without throwing an error
expect(true).toBe(true);
});
it('调用 close 方法应该正常工作', () => {
// 调用 close 方法
// Call the close method
botSkillSaveManager.close();
// 由于我们已经模拟了 close 方法,这里只需验证它可以被调用而不会抛出错误
// Since we have simulated the close method, we just need to verify that it can be called without throwing an error
expect(true).toBe(true);
});
});

View File

@@ -21,7 +21,7 @@ import { modelSaveManager } from '../../../src/save-manager/auto-save/model';
import { autosaveManager } from '../../../src/save-manager/auto-save/index';
import { botSkillSaveManager } from '../../../src/save-manager/auto-save/bot-skill';
// 模拟依赖
// simulated dependency
vi.mock('../../../src/save-manager/auto-save/persona', () => ({
personaSaveManager: {
start: vi.fn(),
@@ -46,24 +46,24 @@ vi.mock('../../../src/save-manager/auto-save/bot-skill', () => ({
describe('autosave manager', () => {
beforeEach(() => {
vi.clearAllMocks();
// 正确模拟 console.log
// Correctly emulate console.log
vi.spyOn(console, 'log').mockImplementation(() => {
// 什么都不做
// Do nothing.
});
});
afterEach(() => {
// 恢复原始的 console.log
// Restore the original console.log
vi.restoreAllMocks();
});
it('应该在启动时调用所有管理器的 start 方法', () => {
autosaveManager.start();
// 验证 console.log 被调用
// Verify that console.log is called
expect(console.log).toHaveBeenCalledWith('start:>>');
// 验证所有管理器的 start 方法被调用
// Verify that the start method of all managers is called
expect(personaSaveManager.start).toHaveBeenCalledTimes(1);
expect(botSkillSaveManager.start).toHaveBeenCalledTimes(1);
expect(modelSaveManager.start).toHaveBeenCalledTimes(1);
@@ -72,10 +72,10 @@ describe('autosave manager', () => {
it('应该在关闭时调用所有管理器的 close 方法', () => {
autosaveManager.close();
// 验证 console.log 被调用
// Verify that console.log is called
expect(console.log).toHaveBeenCalledWith('close:>>');
// 验证所有管理器的 close 方法被调用
// Verify that all managers' close methods are called
expect(personaSaveManager.close).toHaveBeenCalledTimes(1);
expect(botSkillSaveManager.close).toHaveBeenCalledTimes(1);
expect(modelSaveManager.close).toHaveBeenCalledTimes(1);

View File

@@ -22,7 +22,7 @@ import { useBotInfoStore } from '../../../src/store/bot-info';
import { saveFetcher } from '../../../src/save-manager/utils/save-fetcher';
import { saveRequest } from '../../../src/save-manager/auto-save/request';
// 模拟依赖
// simulated dependency
vi.mock('@coze-arch/bot-api', () => ({
PlaygroundApi: {
UpdateDraftBotInfoAgw: vi.fn(),
@@ -53,7 +53,7 @@ describe('auto-save request', () => {
beforeEach(() => {
vi.clearAllMocks();
// 设置默认状态
// Set default state
(useBotInfoStore.getState as any).mockReturnValue({
botId: mockBotId,
});
@@ -71,19 +71,19 @@ describe('auto-save request', () => {
it('应该使用正确的参数调用 saveFetcher', async () => {
await saveRequest(mockPayload, mockItemType);
// 验证 saveFetcher 被调用
// Verify that saveFetcher is called
expect(saveFetcher).toHaveBeenCalledTimes(1);
// 验证 saveFetcher 的第二个参数是正确的 itemType
// Verify that the second argument of saveFetcher is the correct itemType.
expect(saveFetcher).toHaveBeenCalledWith(
expect.any(Function),
mockItemType,
);
// 获取并执行 saveFetcher 的第一个参数(函数)
// Get and execute the first argument (function) of saveFetcher.
const saveRequestFn = (saveFetcher as any).mock.calls[0][0];
await saveRequestFn();
// 验证 UpdateDraftBotInfoAgw 被调用,并且参数正确
// Verify that UpdateDraftBotInfoAgw is called and the parameters are correct
expect(PlaygroundApi.UpdateDraftBotInfoAgw).toHaveBeenCalledWith({
bot_info: {
bot_id: mockBotId,

View File

@@ -25,7 +25,7 @@ import {
} from '../../../src/save-manager/utils/save-fetcher';
import { saveDevHooksConfig } from '../../../src/save-manager/manual-save/dev-hooks';
// 模拟依赖
// simulated dependency
vi.mock('../../../src/store/bot-skill', () => ({
useBotSkillStore: {
getState: vi.fn(),
@@ -45,7 +45,7 @@ describe('dev-hooks save manager', () => {
beforeEach(() => {
vi.clearAllMocks();
// 设置默认状态
// Set default state
(useBotSkillStore.getState as any).mockReturnValue({
devHooks: mockDevHooks,
});
@@ -66,12 +66,12 @@ describe('dev-hooks save manager', () => {
} as any as HookInfo;
await saveDevHooksConfig(newConfig);
// 验证 updateBotRequest 被调用,并且参数正确
// Verify that updateBotRequest was called and the parameters are correct
expect(updateBotRequest).toHaveBeenCalledWith({
hook_info: newConfig,
});
// 验证 saveFetcher 被调用,并且参数正确
// Verify that saveFetcher is called and the parameters are correct
expect(saveFetcher).toHaveBeenCalledWith(
expect.any(Function),
ItemType.HOOKINFO,

View File

@@ -24,7 +24,7 @@ import {
} from '../../../src/save-manager/utils/save-fetcher';
import { saveTableMemory } from '../../../src/save-manager/manual-save/memory-table';
// 模拟依赖
// simulated dependency
vi.mock('../../../src/store/bot-skill', () => ({
useBotSkillStore: {
getState: vi.fn(),
@@ -49,7 +49,7 @@ describe('memory-table save manager', () => {
beforeEach(() => {
vi.clearAllMocks();
// 设置默认状态
// Set default state
(useBotSkillStore.getState as any).mockReturnValue({
databaseList: mockDatabaseList,
transformVo2Dto: mockTransformVo2Dto,
@@ -68,17 +68,17 @@ describe('memory-table save manager', () => {
it('应该正确保存内存表变量', async () => {
await saveTableMemory();
// 验证 transformVo2Dto.databaseList 被调用
// Verify that transformVo2Dto.DatabaseList is called
expect(mockTransformVo2Dto.databaseList).toHaveBeenCalledWith(
mockDatabaseList,
);
// 验证 updateBotRequest 被调用,并且参数正确
// Verify that updateBotRequest was called and the parameters are correct
expect(updateBotRequest).toHaveBeenCalledWith({
database_list: { transformed: mockDatabaseList },
});
// 验证 saveFetcher 被调用,并且参数正确
// Verify that saveFetcher is called and the parameters are correct
expect(saveFetcher).toHaveBeenCalledWith(
expect.any(Function),
ItemType.TABLE,

View File

@@ -29,7 +29,7 @@ import {
saveConnectorType,
} from '../../../src/save-manager/manual-save/multi-agent';
// 模拟依赖
// simulated dependency
vi.mock('@coze-arch/bot-api', () => ({
PlaygroundApi: {
UpdateAgentV2: vi.fn(),
@@ -68,7 +68,7 @@ vi.mock('../../../src/save-manager/utils/save-fetcher', () => ({
describe('multi-agent save manager', () => {
const mockBotId = 'mock-bot-id';
const mockSpaceId = 'mock-space-id';
// 创建一个符合 Agent 类型的模拟对象
// Create a mock object that conforms to the Agent type
const mockAgent = {
id: 'agent-1',
name: 'Agent 1',
@@ -99,7 +99,7 @@ describe('multi-agent save manager', () => {
beforeEach(() => {
vi.clearAllMocks();
// 设置默认状态
// Set default state
(useBotInfoStore.getState as any).mockReturnValue({
botId: mockBotId,
});
@@ -133,22 +133,22 @@ describe('multi-agent save manager', () => {
it('应该正确更新代理', async () => {
await saveUpdateAgents(mockAgent as any);
// 验证 transformVo2Dto.agent 被调用
// Verify that transformVo2Dato.agent is called
expect(
useMultiAgentStore.getState().transformVo2Dto.agent,
).toHaveBeenCalledWith(mockAgent);
// 验证 saveFetcher 被调用,并且参数正确
// Verify that saveFetcher is called and the parameters are correct
expect(saveFetcher).toHaveBeenCalledWith(
expect.any(Function),
ItemTypeExtra.MultiAgent,
);
// 获取并执行 saveFetcher 的第一个参数(函数)
// Get and execute the first argument (function) of saveFetcher.
const saveRequestFn = (saveFetcher as any).mock.calls[0][0];
await saveRequestFn();
// 验证 UpdateAgentV2 被调用,并且参数正确
// Verify that UpdateAgentV2 is called and the parameters are correct
expect(PlaygroundApi.UpdateAgentV2).toHaveBeenCalledWith({
...mockAgentDto,
bot_id: mockBotId,
@@ -163,17 +163,17 @@ describe('multi-agent save manager', () => {
const agentId = 'agent-to-delete';
await saveDeleteAgents(agentId);
// 验证 saveFetcher 被调用,并且参数正确
// Verify that saveFetcher is called and the parameters are correct
expect(saveFetcher).toHaveBeenCalledWith(
expect.any(Function),
ItemTypeExtra.MultiAgent,
);
// 获取并执行 saveFetcher 的第一个参数(函数)
// Get and execute the first argument (function) of saveFetcher.
const saveRequestFn = (saveFetcher as any).mock.calls[0][0];
await saveRequestFn();
// 验证 UpdateAgentV2 被调用,并且参数正确
// Verify that UpdateAgentV2 is called and the parameters are correct
expect(PlaygroundApi.UpdateAgentV2).toHaveBeenCalledWith({
bot_id: mockBotId,
space_id: mockSpaceId,
@@ -188,17 +188,17 @@ describe('multi-agent save manager', () => {
it('应该正确保存多代理数据', async () => {
await saveMultiAgentData();
// 验证 saveFetcher 被调用,并且参数正确
// Verify that saveFetcher is called and the parameters are correct
expect(saveFetcher).toHaveBeenCalledWith(
expect.any(Function),
ItemTypeExtra.MultiAgent,
);
// 获取并执行 saveFetcher 的第一个参数(函数)
// Get and execute the first argument (function) of saveFetcher.
const saveRequestFn = (saveFetcher as any).mock.calls[0][0];
await saveRequestFn();
// 验证 UpdateMultiAgent 被调用,并且参数正确
// Verify that UpdateMultiAgent is invoked and the parameters are correct
expect(PlaygroundApi.UpdateMultiAgent).toHaveBeenCalledWith({
space_id: mockSpaceId,
bot_id: mockBotId,
@@ -210,21 +210,21 @@ describe('multi-agent save manager', () => {
describe('saveConnectorType', () => {
it('应该正确保存连接器类型', async () => {
// 使用数字代替枚举值
const connectorType = 0; // 假设 0 代表 Straight
// Using numbers instead of enumerated values
const connectorType = 0; // Assume 0 is Straight
await saveConnectorType(connectorType as any);
// 验证 saveFetcher 被调用,并且参数正确
// Verify that saveFetcher is called and the parameters are correct
expect(saveFetcher).toHaveBeenCalledWith(
expect.any(Function),
ItemTypeExtra.ConnectorType,
);
// 获取并执行 saveFetcher 的第一个参数(函数)
// Get and execute the first argument (function) of saveFetcher.
const saveRequestFn = (saveFetcher as any).mock.calls[0][0];
await saveRequestFn();
// 验证 UpdateMultiAgent 被调用,并且参数正确
// Verify that UpdateMultiAgent is invoked and the parameters are correct
expect(PlaygroundApi.UpdateMultiAgent).toHaveBeenCalledWith({
space_id: mockSpaceId,
bot_id: mockBotId,

View File

@@ -25,7 +25,7 @@ import {
import { ItemTypeExtra } from '../../../src/save-manager/types';
import { updateQueryCollect } from '../../../src/save-manager/manual-save/query-collect';
// 模拟依赖
// simulated dependency
vi.mock('../../../src/store/query-collect', () => ({
useQueryCollectStore: {
getState: vi.fn(),
@@ -46,7 +46,7 @@ describe('query-collect save manager', () => {
beforeEach(() => {
vi.clearAllMocks();
// 设置默认状态
// Set default state
(useQueryCollectStore.getState as any).mockReturnValue({
...mockQueryCollect,
});
@@ -62,18 +62,18 @@ describe('query-collect save manager', () => {
});
it('应该正确保存 query collect 配置', async () => {
// 创建一个符合 UserQueryCollectConf 类型的对象作为参数
// Create an object of UserQueryCollectConf type as a parameter
const queryCollectConf =
mockQueryCollect as unknown as UserQueryCollectConf;
await updateQueryCollect(queryCollectConf);
// 验证 updateBotRequest 被调用,并且参数正确
// Verify that updateBotRequest was called and the parameters are correct
expect(updateBotRequest).toHaveBeenCalledWith({
user_query_collect_conf: queryCollectConf,
});
// 验证 saveFetcher 被调用,并且参数正确
// Verify that saveFetcher is called and the parameters are correct
expect(saveFetcher).toHaveBeenCalledWith(
expect.any(Function),
ItemTypeExtra.QueryCollect,
@@ -84,7 +84,7 @@ describe('query-collect save manager', () => {
const mockError = new Error('Save failed');
(saveFetcher as any).mockRejectedValue(mockError);
// 创建一个符合 UserQueryCollectConf 类型的对象作为参数
// Create an object of UserQueryCollectConf type as a parameter
const queryCollectConf =
mockQueryCollect as unknown as UserQueryCollectConf;

View File

@@ -24,7 +24,7 @@ import {
import { ItemTypeExtra } from '../../../src/save-manager/types';
import { updateShortcutSort } from '../../../src/save-manager/manual-save/shortcuts';
// 模拟依赖
// simulated dependency
vi.mock('../../../src/store/bot-skill', () => ({
useBotSkillStore: {
getState: vi.fn(),
@@ -46,7 +46,7 @@ describe('shortcuts save manager', () => {
beforeEach(() => {
vi.clearAllMocks();
// 设置默认状态
// Set default state
(useBotSkillStore.getState as any).mockReturnValue({
shortcut: mockShortcut,
transformVo2Dto: mockTransformVo2Dto,
@@ -66,12 +66,12 @@ describe('shortcuts save manager', () => {
const newSort = ['shortcut-2', 'shortcut-1'];
await updateShortcutSort(newSort);
// 验证 updateBotRequest 被调用,并且参数正确
// Verify that updateBotRequest was called and the parameters are correct
expect(updateBotRequest).toHaveBeenCalledWith({
shortcut_sort: newSort,
});
// 验证 saveFetcher 被调用,并且参数正确
// Verify that saveFetcher is called and the parameters are correct
expect(saveFetcher).toHaveBeenCalledWith(
expect.any(Function),
ItemTypeExtra.Shortcut,

View File

@@ -24,7 +24,7 @@ import {
import { ItemTypeExtra } from '../../../src/save-manager/types';
import { saveTimeCapsule } from '../../../src/save-manager/manual-save/time-capsule';
// 模拟依赖
// simulated dependency
vi.mock('../../../src/store/bot-skill', () => ({
useBotSkillStore: {
getState: vi.fn(),
@@ -54,7 +54,7 @@ describe('time-capsule save manager', () => {
beforeEach(() => {
vi.clearAllMocks();
// 设置默认状态
// Set default state
(useBotSkillStore.getState as any).mockReturnValue({
timeCapsule: mockTimeCapsule,
transformVo2Dto: mockTransformVo2Dto,
@@ -73,17 +73,17 @@ describe('time-capsule save manager', () => {
it('应该正确保存 time capsule 配置', async () => {
await saveTimeCapsule();
// 验证 transformVo2Dto.timeCapsule 被调用,参数应该是包含 time_capsule_mode disable_prompt_calling 的对象
// Verify that transformVo2To.timeCapsule is called, the argument should be an object containing time_capsule_mode and disable_prompt_calling
expect(mockTransformVo2Dto.timeCapsule).toHaveBeenCalledWith({
time_capsule_mode: mockTimeCapsule.time_capsule_mode,
disable_prompt_calling: mockTimeCapsule.disable_prompt_calling,
});
// 验证 updateBotRequest 被调用,并且参数正确
// Verify that updateBotRequest was called and the parameters are correct
expect(updateBotRequest).toHaveBeenCalledWith({
bot_tag_info: mockTransformedTimeCapsule,
});
// 验证 saveFetcher 被调用,并且参数正确
// Verify that saveFetcher is called and the parameters are correct
expect(saveFetcher).toHaveBeenCalledWith(
expect.any(Function),
ItemTypeExtra.TimeCapsule,

View File

@@ -25,7 +25,7 @@ import {
import { ItemTypeExtra } from '../../../src/save-manager/types';
import { saveTTSConfig } from '../../../src/save-manager/manual-save/tts';
// 模拟依赖
// simulated dependency
vi.mock('lodash-es', () => ({
cloneDeep: vi.fn(obj => JSON.parse(JSON.stringify(obj))),
merge: vi.fn((target, ...sources) => Object.assign({}, target, ...sources)),
@@ -73,7 +73,7 @@ describe('tts save manager', () => {
beforeEach(() => {
vi.clearAllMocks();
// 设置默认状态
// Set default state
(useBotSkillStore.getState as any).mockReturnValue({
tts: mockTTS,
voicesInfo: mockVoicesInfo,
@@ -93,21 +93,21 @@ describe('tts save manager', () => {
it('应该正确保存 TTS 配置', async () => {
await saveTTSConfig();
// 验证 transformVo2Dto.tts 被调用
// Verify that transformVo2To.tts is called
expect(mockTransformVo2Dto.tts).toHaveBeenCalledTimes(1);
// 验证传递给 transformVo2Dto.tts 的参数是 tts 的克隆
// Verify that the parameter passed to transformVo2To.tts is a clone of tts
const ttsArg = mockTransformVo2Dto.tts.mock.calls[0][0];
expect(ttsArg).toEqual(mockTTS);
expect(ttsArg).not.toBe(mockTTS); // 确保是克隆而不是原始对象
expect(ttsArg).not.toBe(mockTTS); // Make sure it's a clone and not the original object
// 验证 cloneDeep 被调用
// Verify that cloneDeep is called
expect(cloneDeep).toHaveBeenCalledTimes(3);
// 验证 transformVo2Dto.voicesInfo 被调用
// Verify that transformVo2To.voicesInfo is called
expect(mockTransformVo2Dto.voicesInfo).toHaveBeenCalledWith(mockVoicesInfo);
// 验证 updateBotRequest 被调用,并且参数正确
// Verify that updateBotRequest was called and the parameters are correct
expect(updateBotRequest).toHaveBeenCalledWith({
voices_info: {
muted: mockTTS.muted,
@@ -120,7 +120,7 @@ describe('tts save manager', () => {
},
});
// 验证 saveFetcher 被调用,并且参数正确
// Verify that saveFetcher is called and the parameters are correct
expect(saveFetcher).toHaveBeenCalledWith(
expect.any(Function),
ItemTypeExtra.TTS,

View File

@@ -25,7 +25,7 @@ import { useBotSkillStore } from '../../../src/store/bot-skill';
import { useBotInfoStore } from '../../../src/store/bot-info';
import { getBotDetailDtoInfo } from '../../../src/save-manager/utils/bot-dto-info';
// 模拟依赖
// simulated dependency
vi.mock('@coze-arch/report-events', () => ({
REPORT_EVENTS: {
botDebugSaveAll: 'botDebugSaveAll',
@@ -130,7 +130,7 @@ describe('bot-dto-info utils', () => {
beforeEach(() => {
vi.clearAllMocks();
// 设置默认状态
// Set default state
(useBotInfoStore.getState as any).mockReturnValue({
mode: BotMode.SingleMode,
});
@@ -156,18 +156,18 @@ describe('bot-dto-info utils', () => {
it('应该正确转换所有 bot 信息为 DTO 格式', () => {
const result = getBotDetailDtoInfo();
// 验证 bot skill info
// Verify bot skill info
const { botSkillInfo } = result;
// 验证 persona 转换
// Validate persona conversion
expect(mockPersona.transformVo2Dto).toHaveBeenCalledWith(
mockPersona.systemMessage,
);
// 验证 model 转换
// Validation model transformation
expect(mockModel.transformVo2Dto).toHaveBeenCalledWith(mockModel.config);
// 验证 bot skill 转换
// Verify bot skill conversion
expect(mockTransformVo2Dto.knowledge).toHaveBeenCalledWith(
mockBotSkill.knowledge,
);
@@ -203,17 +203,17 @@ describe('bot-dto-info utils', () => {
mockBotSkill.voicesInfo,
);
// 验证 queryCollect 转换
// Verify queryCollect conversion
expect(mockQueryCollect.transformVo2Dto).toHaveBeenCalledWith(
mockQueryCollect,
);
// 验证结果结构
// Validation result structure
expect(botSkillInfo).toBeDefined();
});
it('在多智能体模式下应该正确转换', () => {
// 设置为多智能体模式
// Set to multi-agent mode
(useBotInfoStore.getState as any).mockReturnValue({
mode: BotMode.MultiMode,
});
@@ -221,12 +221,12 @@ describe('bot-dto-info utils', () => {
const result = getBotDetailDtoInfo();
const { botSkillInfo } = result;
// 验证多智能体模式下的转换
// Verify transitions in multi-agent mode
expect(mockMultiAgent.transformVo2Dto.agent).toHaveBeenCalledWith(
mockMultiAgent.agents[0],
);
// 验证多智能体模式下某些字段应该是 undefined
// Verify that some fields should be undefined in multi-agent mode
expect(botSkillInfo).toBeDefined();
});
});

View File

@@ -28,7 +28,7 @@ import {
updateBotRequest,
} from '../../../src/save-manager/utils/save-fetcher';
// 模拟依赖
// simulated dependency
vi.mock('@coze-arch/logger', () => ({
reporter: {
successEvent: vi.fn(),
@@ -84,7 +84,7 @@ describe('save-fetcher utils', () => {
beforeEach(() => {
vi.clearAllMocks();
// 设置默认状态
// Set default state
(usePageRuntimeStore.getState as any).mockReturnValue({
editable: true,
isPreview: false,
@@ -118,7 +118,7 @@ describe('save-fetcher utils', () => {
describe('saveFetcher', () => {
it('应该在只读模式下不执行任何操作', async () => {
// 设置为只读模式
// Set to read-only mode
(usePageRuntimeStore.getState as any).mockReturnValue({
editable: false,
isPreview: false,
@@ -134,7 +134,7 @@ describe('save-fetcher utils', () => {
});
it('应该在预览模式下不执行任何操作', async () => {
// 设置为预览模式
// Set to preview mode
(usePageRuntimeStore.getState as any).mockReturnValue({
editable: true,
isPreview: true,
@@ -150,7 +150,7 @@ describe('save-fetcher utils', () => {
});
it('应该在探索模式下不执行任何操作', async () => {
// 设置为探索模式
// Set to exploration mode
(usePageRuntimeStore.getState as any).mockReturnValue({
editable: true,
isPreview: false,
@@ -166,7 +166,7 @@ describe('save-fetcher utils', () => {
});
it('应该在未初始化时不执行任何操作', async () => {
// 设置为未初始化
// Set to uninitialized
(usePageRuntimeStore.getState as any).mockReturnValue({
editable: true,
isPreview: false,
@@ -184,32 +184,32 @@ describe('save-fetcher utils', () => {
it('应该在可编辑模式下正确执行保存操作', async () => {
await saveFetcher(mockSaveRequest, mockScopeKey as any);
// 验证设置保存状态
// Verify settings save state
expect(mockSetPageRuntimeByImmer).toHaveBeenCalledTimes(3);
// 验证第一次调用 - 设置保存中状态
// Verify First Call - Set Saved State
const firstCall = mockSetPageRuntimeByImmer.mock.calls[0][0];
const mockState1 = { savingInfo: {} };
firstCall(mockState1);
expect(mockState1.savingInfo.saving).toBe(true);
expect(mockState1.savingInfo.scopeKey).toBe(String(mockScopeKey));
// 验证保存请求被调用
// Verify that the save request was invoked
expect(mockSaveRequest).toHaveBeenCalledTimes(1);
// 验证第二次调用 - 设置保存完成状态
// Verify Second Call - Set Save Complete Status
const secondCall = mockSetPageRuntimeByImmer.mock.calls[1][0];
const mockState2 = { savingInfo: {} };
secondCall(mockState2);
expect(mockState2.savingInfo.saving).toBe(false);
expect(mockState2.savingInfo.time).toBe('12:34:56');
// 验证第三次调用 - 设置未发布变更状态
// Verify Third Call - Set Unpublished Change Status
const thirdCall = mockSetPageRuntimeByImmer.mock.calls[2][0];
const mockState3 = {};
thirdCall(mockState3);
expect(mockState3.hasUnpublishChange).toBe(true);
// 验证设置协作状态
// Verify settings collaboration status
expect(mockSetCollaborationByImmer).toHaveBeenCalledTimes(1);
const collaborationCall = mockSetCollaborationByImmer.mock.calls[0][0];
const mockCollabState = { branch: { id: 'branch-id' } };
@@ -217,7 +217,7 @@ describe('save-fetcher utils', () => {
expect(mockCollabState.sameWithOnline).toBe(false);
expect(mockCollabState.branch).toEqual({ id: 'updated-branch-id' });
// 验证成功事件被报告
// Validation success events are reported
expect(reporter.successEvent).toHaveBeenCalledWith({
eventName: REPORT_EVENTS.AutosaveSuccess,
meta: { itemType: mockScopeKey },
@@ -230,13 +230,13 @@ describe('save-fetcher utils', () => {
await saveFetcher(mockSaveRequest, mockScopeKey as any);
// 验证设置保存中状态
// Verify settings save status
expect(mockSetPageRuntimeByImmer).toHaveBeenCalledTimes(1);
// 验证保存请求被调用
// Verify that the save request was invoked
expect(mockSaveRequest).toHaveBeenCalledTimes(1);
// 验证错误事件被报告
// Validation error events are reported
expect(reporter.errorEvent).toHaveBeenCalledWith({
eventName: REPORT_EVENTS.AutosaveError,
error: mockError,
@@ -249,19 +249,19 @@ describe('save-fetcher utils', () => {
data: {
has_change: true,
same_with_online: false,
// 没有 branch 信息
// No branch information
},
});
await saveFetcher(mockSaveRequest, mockScopeKey as any);
// 验证设置协作状态
// Verify settings collaboration status
expect(mockSetCollaborationByImmer).toHaveBeenCalledTimes(1);
const collaborationCall = mockSetCollaborationByImmer.mock.calls[0][0];
const mockCollabState = { branch: { id: 'branch-id' } };
collaborationCall(mockCollabState);
expect(mockCollabState.sameWithOnline).toBe(false);
// 分支信息应该保持不变
// Branch information should remain unchanged
expect(mockCollabState.branch).toEqual({ id: 'branch-id' });
});
});

View File

@@ -21,7 +21,7 @@ import {
describe('diff-task store', () => {
beforeEach(() => {
// 每个测试前重置 store 状态
// Reset the stored state before each test
useDiffTaskStore.getState().clear();
});
@@ -99,7 +99,7 @@ describe('diff-task store', () => {
const state = useDiffTaskStore.getState();
expect(state.diffTask).toBe('model');
// promptDiffInfo 应该保持不变
// promptDiffInfo should remain unchanged
expect(state.promptDiffInfo).toEqual(
getDefaultDiffTaskStore().promptDiffInfo,
);
@@ -108,43 +108,43 @@ describe('diff-task store', () => {
test('exitDiffMode 应该调用 clear 方法', () => {
const { enterDiffMode, exitDiffMode, clear } = useDiffTaskStore.getState();
// 模拟 clear 方法
// Simulated clearing method
const mockClear = vi.fn();
useDiffTaskStore.setState(state => ({ ...state, clear: mockClear }));
// 先进入 diff 模式
// Enter diff mode first
enterDiffMode({ diffTask: 'prompt' });
// 退出 diff 模式
// Exit diff mode
exitDiffMode();
// 验证 clear 被调用
// Verify clear is called
expect(mockClear).toHaveBeenCalledTimes(1);
// 恢复原始的 clear 方法
// Restore the original clear method
useDiffTaskStore.setState(state => ({ ...state, clear }));
});
test('clear 应该重置状态到默认值', () => {
const { setDiffTask, clear } = useDiffTaskStore.getState();
// 修改状态
// Modify state
setDiffTask({
diffTask: 'model',
hasContinueTask: true,
continueTask: 'prompt',
});
// 验证状态已更改
// Verification status has changed
let state = useDiffTaskStore.getState();
expect(state.diffTask).toBe('model');
expect(state.hasContinueTask).toBe(true);
expect(state.continueTask).toBe('prompt');
// 重置状态
// reset state
clear();
// 验证状态已重置
// Verification status reset
state = useDiffTaskStore.getState();
expect(state).toEqual({
...getDefaultDiffTaskStore(),

View File

@@ -665,9 +665,9 @@ describe('resetHostAgent', () => {
});
useBotInfoStore.getState().setBotInfo(getOverall());
// 接口错误返回
// interface error return
expect(await useMultiAgentStore.getState().addAgent({})).toBeUndefined();
// 接口错误返回走default
// Interface error return go default
expect(useCollaborationStore.getState().sameWithOnline).toEqual(
getDefaultCollaborationStore().sameWithOnline,
);
@@ -1051,7 +1051,7 @@ describe('addAgentIntent', () => {
};
useMultiAgentStore.getState().addAgent2Store(agent);
const findAgent = useMultiAgentStore.getState().agents?.[0];
// 这里想要mock findTargetAgent的返回值
// Here I want to mock the return value of findTargetAgent
const mockFindAgent = vi
.spyOn(findAgentModule, 'findTargetAgent')
.mockReturnValueOnce({

View File

@@ -19,7 +19,7 @@ import { globalVars } from '@coze-arch/web-context';
import { getExecuteDraftBotRequestId } from '../../src/utils/execute-draft-bot-request-id';
// 模拟 globalVars
// Simulate globalVars
vi.mock('@coze-arch/web-context', () => ({
globalVars: {
LAST_EXECUTE_ID: 'mock-execute-id',
@@ -35,14 +35,14 @@ describe('execute-draft-bot-request-id utils', () => {
});
it('应该在 LAST_EXECUTE_ID 变化时返回新值', () => {
// 修改模拟的 LAST_EXECUTE_ID
// Modify the simulated LAST_EXECUTE_ID
(globalVars as any).LAST_EXECUTE_ID = 'new-execute-id';
const result = getExecuteDraftBotRequestId();
expect(result).toBe('new-execute-id');
// 恢复原始值,避免影响其他测试
// Restore the original value to avoid affecting other tests
(globalVars as any).LAST_EXECUTE_ID = 'mock-execute-id';
});
});

View File

@@ -35,7 +35,7 @@ import {
} from '../../src/types/generate-image';
import { useBotSkillStore } from '../../src/store/bot-skill';
// 模拟依赖
// simulated dependency
vi.mock('../../src/store/bot-skill', () => ({
useBotSkillStore: {
getState: vi.fn(),
@@ -124,8 +124,8 @@ describe('generate-image utils', () => {
};
(getDotStatus as any)
.mockReturnValueOnce(DotStatus.Generating) // 静态图状态
.mockReturnValueOnce(DotStatus.None); // 动图状态
.mockReturnValueOnce(DotStatus.Generating) // static graph state
.mockReturnValueOnce(DotStatus.None); // animation status
getInitBackgroundInfo(data, state);
@@ -173,8 +173,8 @@ describe('generate-image utils', () => {
};
(getDotStatus as any)
.mockReturnValueOnce(DotStatus.None) // 静态图状态
.mockReturnValueOnce(DotStatus.Success); // 动图状态
.mockReturnValueOnce(DotStatus.None) // static graph state
.mockReturnValueOnce(DotStatus.Success); // animation status
getInitBackgroundInfo(data, state);
@@ -276,13 +276,13 @@ describe('generate-image utils', () => {
(getDotStatus as any).mockReturnValue(DotStatus.None);
// 在调用函数前,先准备一个空的任务对象,模拟函数内部的行为
// Before calling the function, prepare an empty task object to simulate the behavior inside the function
const emptyTask = {
id: '',
img_info: {},
};
// 修改测试数据,添加一个空任务
// Modify the test data and add an empty task
data.tasks = [emptyTask as any];
getInitAvatarInfo(data, state);
@@ -291,9 +291,9 @@ describe('generate-image utils', () => {
expect(state.gif.loading).toBe(false);
expect(state.image.loading).toBe(false);
// 直接修改 state.selectedImage,使其与预期值匹配
// Modify state.selectedImage directly to match the expected value
state.selectedImage = emptyTask;
// 修改断言,与实际函数行为一致
// Modify the assertion to match the actual function behavior
expect(state.selectedImage).toEqual(emptyTask);
});
@@ -340,8 +340,8 @@ describe('generate-image utils', () => {
};
(getDotStatus as any)
.mockReturnValueOnce(DotStatus.None) // 动图状态
.mockReturnValueOnce(DotStatus.Success); // 静态图状态
.mockReturnValueOnce(DotStatus.None) // animation status
.mockReturnValueOnce(DotStatus.Success); // static graph state
getInitAvatarInfo(data, state);
@@ -398,8 +398,8 @@ describe('generate-image utils', () => {
};
(getDotStatus as any)
.mockReturnValueOnce(DotStatus.Generating) // 动图状态
.mockReturnValueOnce(DotStatus.None); // 静态图状态
.mockReturnValueOnce(DotStatus.Generating) // animation status
.mockReturnValueOnce(DotStatus.None); // static graph state
getInitAvatarInfo(data, state);
@@ -473,8 +473,8 @@ describe('generate-image utils', () => {
};
(getDotStatus as any)
.mockReturnValueOnce(DotStatus.Success) // 动图状态
.mockReturnValueOnce(DotStatus.Success); // 静态图状态
.mockReturnValueOnce(DotStatus.Success) // animation status
.mockReturnValueOnce(DotStatus.Success); // static graph state
getInitAvatarInfo(data, state);

View File

@@ -18,13 +18,13 @@ import { describe, it, expect } from 'vitest';
import { DotStatus } from '../../src/types/generate-image';
// 模拟 PicType 枚举
// Analog PicType Enumeration
enum MockPicType {
AVATAR = 1,
BACKGROUND = 2,
}
// 模拟 GetPicTaskData 类型
// Emulate the GetPicTaskData type
interface MockTask {
type: MockPicType;
status: number;
@@ -40,7 +40,7 @@ interface MockGetPicTaskData {
notices?: MockNotice[];
}
// 简化版的 getDotStatus 函数
// Simplified version of getDotStatus function
function simplifiedGetDotStatus(
data: MockGetPicTaskData | null,
picType: MockPicType,

View File

@@ -20,7 +20,7 @@ import { type Branch, type Committer } from '@coze-arch/bot-api/developer_api';
import { updateHeaderStatus } from '../../src/utils/handle-status';
import { useCollaborationStore } from '../../src/store/collaboration';
// 模拟 useCollaborationStore
// Analog useCollaborationStore
vi.mock('../../src/store/collaboration', () => ({
useCollaborationStore: {
getState: vi.fn().mockReturnValue({
@@ -59,7 +59,7 @@ describe('handle-status utils', () => {
expect(useCollaborationStore.getState).toHaveBeenCalled();
expect(mockSetCollaborationByImmer).toHaveBeenCalled();
// 验证 setCollaborationByImmer 的回调函数
// Validate setCollaborationByImmer callback function
const callback = mockSetCollaborationByImmer.mock.calls[0][0];
const mockStore = {
sameWithOnline: false,
@@ -91,7 +91,7 @@ describe('handle-status utils', () => {
setCollaborationByImmer: mockSetCollaborationByImmer,
});
// 只提供部分参数
// Only some parameters are provided
const mockProps = {
same_with_online: true,
};
@@ -101,7 +101,7 @@ describe('handle-status utils', () => {
expect(useCollaborationStore.getState).toHaveBeenCalled();
expect(mockSetCollaborationByImmer).toHaveBeenCalled();
// 验证 setCollaborationByImmer 的回调函数
// Validate setCollaborationByImmer callback function
const callback = mockSetCollaborationByImmer.mock.calls[0][0];
const mockStore = {
sameWithOnline: false,
@@ -114,7 +114,7 @@ describe('handle-status utils', () => {
callback(mockStore);
// 只有 sameWithOnline 应该被更新
// Only sameWithOnline should be updated
expect(mockStore).toEqual({
sameWithOnline: true,
commit_time: 'old_time',
@@ -133,13 +133,13 @@ describe('handle-status utils', () => {
const mockProps = {
committer: {
// commit_time name 都是 undefined
// commit_time and name are both undefined.
} as Committer,
};
updateHeaderStatus(mockProps);
// 验证 setCollaborationByImmer 的回调函数
// Validate setCollaborationByImmer callback function
const callback = mockSetCollaborationByImmer.mock.calls[0][0];
const mockStore = {
sameWithOnline: true,
@@ -149,7 +149,7 @@ describe('handle-status utils', () => {
callback(mockStore);
// 应该使用空字符串作为默认值
// Should use empty string as default
expect(mockStore).toEqual({
sameWithOnline: false,
commit_time: '',

View File

@@ -25,7 +25,7 @@ import {
describe('plugin-apis', () => {
describe('getPluginApisFilterExample', () => {
it('应该过滤掉所有插件API中的debug_example字段', () => {
// 使用 as unknown as PluginApi[] 来绕过类型检查
// Use as unknown as PluginApi [] to bypass type checking
const mockPluginApis = [
{
name: 'plugin1',
@@ -56,7 +56,7 @@ describe('plugin-apis', () => {
describe('getSinglePluginApiFilterExample', () => {
it('应该过滤掉单个插件API中的debug_example字段', () => {
// 使用 as unknown as PluginApi 来绕过类型检查
// Use as unknown as PluginApi to bypass type checking
const mockPluginApi = {
name: 'plugin1',
debug_example: 'example1',

View File

@@ -30,20 +30,20 @@ describe('replacedBotPrompt', () => {
expect(result).toHaveLength(3);
// 检查系统提示
// Check system prompt
expect(result[0]).toEqual({
prompt_type: PromptType.SYSTEM,
data: '这是一个系统提示',
record_id: '123456',
});
// 检查用户前缀
// Check user prefix
expect(result[1]).toEqual({
prompt_type: PromptType.USERPREFIX,
data: '',
});
// 检查用户后缀
// Check user suffix
expect(result[2]).toEqual({
prompt_type: PromptType.USERSUFFIX,
data: '',
@@ -60,20 +60,20 @@ describe('replacedBotPrompt', () => {
expect(result).toHaveLength(3);
// 检查系统提示
// Check system prompt
expect(result[0]).toEqual({
prompt_type: PromptType.SYSTEM,
data: '',
record_id: '',
});
// 检查用户前缀
// Check user prefix
expect(result[1]).toEqual({
prompt_type: PromptType.USERPREFIX,
data: '',
});
// 检查用户后缀
// Check user suffix
expect(result[2]).toEqual({
prompt_type: PromptType.USERSUFFIX,
data: '',
@@ -89,7 +89,7 @@ describe('replacedBotPrompt', () => {
expect(result).toHaveLength(3);
// 检查系统提示
// Check system prompt
expect(result[0]).toEqual({
prompt_type: PromptType.SYSTEM,
data: '这是一个系统提示',

View File

@@ -20,7 +20,7 @@ import { PromptType } from '@coze-arch/bot-api/developer_api';
import { getReplacedBotPrompt } from '../../src/utils/save';
import { usePersonaStore } from '../../src/store/persona';
// 模拟 usePersonaStore
// emulation usePersonaStore
vi.mock('../../src/store/persona', () => ({
usePersonaStore: {
getState: vi.fn().mockReturnValue({
@@ -38,19 +38,19 @@ describe('save utils', () => {
expect(result).toHaveLength(3);
// 验证系统消息
// Verify system message
expect(result[0]).toEqual({
prompt_type: PromptType.SYSTEM,
data: '模拟的系统消息',
});
// 验证用户前缀
// validate user prefix
expect(result[1]).toEqual({
prompt_type: PromptType.USERPREFIX,
data: '',
});
// 验证用户后缀
// validate user suffix
expect(result[2]).toEqual({
prompt_type: PromptType.USERSUFFIX,
data: '',

View File

@@ -20,7 +20,7 @@ import { setterActionFactory } from '../../src/utils/setter-factory';
describe('setterActionFactory', () => {
it('应该创建一个增量更新函数', () => {
// 创建模拟的 set 函数
// Create a simulated set function
const mockSet = vi.fn(updater => {
if (typeof updater === 'function') {
return updater({ a: 1, b: 2 });
@@ -28,37 +28,37 @@ describe('setterActionFactory', () => {
return updater;
});
// 创建 setter 函数
// Create a setter function
const setter = setterActionFactory(mockSet);
// 调用 setter 进行增量更新
// Call setter for incremental update
setter({ a: 3 });
// 验证 set 函数被调用
// Verify that the set function is called
expect(mockSet).toHaveBeenCalled();
// 验证更新后的状态
// Verify the updated status
const updater = mockSet.mock.calls[0][0];
const result = updater({ a: 1, b: 2 });
expect(result).toEqual({ a: 3, b: 2 });
});
it('应该创建一个全量更新函数', () => {
// 创建模拟的 set 函数
// Create a simulated set function
const mockSet = vi.fn();
// 创建 setter 函数
// Create a setter function
const setter = setterActionFactory(mockSet);
// 调用 setter 进行全量更新
// Call setter for full update
setter({ a: 3 }, { replace: true });
// 验证 set 函数被调用,并且传入了正确的参数
// Verify that the set function is called and the correct parameters are passed in
expect(mockSet).toHaveBeenCalledWith({ a: 3 });
});
it('应该处理空对象的增量更新', () => {
// 创建模拟的 set 函数
// Create a simulated set function
const mockSet = vi.fn(updater => {
if (typeof updater === 'function') {
return updater({});
@@ -66,43 +66,43 @@ describe('setterActionFactory', () => {
return updater;
});
// 创建 setter 函数
// Create a setter function
const setter = setterActionFactory(mockSet);
// 调用 setter 进行增量更新
// Call setter for incremental update
setter({ a: 1 });
// 验证 set 函数被调用
// Verify that the set function is called
expect(mockSet).toHaveBeenCalled();
// 验证更新后的状态
// Verify the updated status
const updater = mockSet.mock.calls[0][0];
const result = updater({});
expect(result).toEqual({ a: 1 });
});
it('应该处理空对象的全量更新', () => {
// 创建模拟的 set 函数
// Create a simulated set function
const mockSet = vi.fn();
// 创建 setter 函数
// Create a setter function
const setter = setterActionFactory(mockSet);
// 调用 setter 进行全量更新
// Call setter for full update
setter({}, { replace: true });
// 验证 set 函数被调用,并且传入了正确的参数
// Verify that the set function is called and the correct parameters are passed in
expect(mockSet).toHaveBeenCalledWith({});
});
it('应该处理复杂对象的增量更新', () => {
// 创建一个复杂的初始状态
// Create a complex initial state
const initialState = {
user: { name: 'John', age: 30 },
settings: { theme: 'dark', notifications: true },
};
// 创建模拟的 set 函数
// Create a simulated set function
const mockSet = vi.fn(updater => {
if (typeof updater === 'function') {
return updater(initialState);
@@ -110,22 +110,22 @@ describe('setterActionFactory', () => {
return updater;
});
// 创建 setter 函数
// Create a setter function
const setter = setterActionFactory(mockSet);
// 调用 setter 进行增量更新
// Call setter for incremental update
setter({
user: { name: 'Jane', age: 25 },
});
// 验证 set 函数被调用
// Verify that the set function is called
expect(mockSet).toHaveBeenCalled();
// 验证更新后的状态
// Verify the updated status
const updater = mockSet.mock.calls[0][0];
const result = updater(initialState);
// 检查结果是否正确合并了对象
// Check if the result is correct and the objects are merged.
expect(result).toEqual({
user: { name: 'Jane', age: 25 },
settings: { theme: 'dark', notifications: true },

View File

@@ -19,7 +19,7 @@ import { describe, it, expect, vi, beforeEach } from 'vitest';
import { createStorage, storage } from '../../src/utils/storage';
import { useCollaborationStore } from '../../src/store/collaboration';
// 模拟 useCollaborationStore
// Analog useCollaborationStore
vi.mock('../../src/store/collaboration', () => ({
useCollaborationStore: {
getState: vi.fn().mockReturnValue({
@@ -32,7 +32,7 @@ describe('storage utils', () => {
let mockStorage: Storage;
beforeEach(() => {
// 创建模拟的 Storage 对象
// Create a simulated Storage object
mockStorage = {
getItem: vi.fn(),
setItem: vi.fn(),
@@ -55,19 +55,19 @@ describe('storage utils', () => {
prefix,
);
// 测试设置值
// test settings
proxy.testKey = 'testValue';
expect(mockStorage.setItem).toHaveBeenCalledWith(
`${prefix}.testKey`,
'testValue',
);
// 测试获取值
// Test Get Value
(mockStorage.getItem as any).mockReturnValueOnce('storedValue');
expect(proxy.testKey).toBe('storedValue');
expect(mockStorage.getItem).toHaveBeenCalledWith(`${prefix}.testKey`);
// 测试删除值
// Test Delete Value
delete proxy.testKey;
expect(mockStorage.removeItem).toHaveBeenCalledWith(`${prefix}.testKey`);
});
@@ -76,22 +76,22 @@ describe('storage utils', () => {
const target: Record<string, any> = {};
const proxy = createStorage<Record<string, any>>(mockStorage, target);
// 设置字符串值应该成功
// Setting string value should succeed
proxy.key1 = 'value1';
expect(mockStorage.setItem).toHaveBeenCalledTimes(1);
// 注意:在实际代码中,设置非字符串值会返回 false但不会抛出错误
// 在测试中,我们只验证 setItem 没有被再次调用
// Note: In actual code, setting a non-string value will return false, but no error will be thrown
// In the test, we only verify that setItem is not called again
try {
// 这里可能会抛出错误,但我们不关心错误本身
// Errors may be thrown here, but we don't care about the errors themselves
proxy.key2 = 123 as any;
// 如果没有抛出错误,我们期望 setItem 不会被再次调用
// If no error is thrown, we expect that setItem will not be called again
} catch (e) {
// 如果抛出错误,我们也期望 setItem 不会被再次调用
// If an error is thrown, we also expect that setItem will not be called again
console.log('捕获到错误,但这是预期的行为');
}
// 无论是否抛出错误,我们都期望 setItem 不会被再次调用
// Whether an error is thrown or not, we expect that setItem will not be called again
expect(mockStorage.setItem).toHaveBeenCalledTimes(1);
});
@@ -114,17 +114,17 @@ describe('storage utils', () => {
it('设置 baseVersion 应该打印错误', () => {
const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {
/* 空函数 */
/* empty function */
});
// 注意:在实际代码中,设置 baseVersion 会返回 false 并打印错误,但不会抛出错误
// 在测试中,我们只验证 console.error 被调用
// Note: In the actual code, setting baseVersion will return false and print an error, but no error will be thrown
// In testing, we only verify that console.error is called
try {
// 这里可能会抛出错误,但我们不关心错误本身
// Errors may be thrown here, but we don't care about the errors themselves
storage.baseVersion = 'new-version';
// 如果没有抛出错误,我们期望 console.error 被调用
// If no error is thrown, we expect console.error to be called
} catch (e) {
// 如果抛出错误,我们也期望 console.error 被调用
// If an error is thrown, we also expect console.error to be called
console.log('捕获到错误,但这是预期的行为');
}

View File

@@ -20,7 +20,7 @@ import { UIToast } from '@coze-arch/bot-semi';
import { hasBraces, verifyBracesAndToast } from '../../src/utils/submit';
// 模拟 UIToast I18n
// Analog UIToast and I18n
vi.mock('@coze-arch/bot-semi', () => ({
UIToast: {
warning: vi.fn(),

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