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

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

View File

@@ -22,7 +22,7 @@ import { render, screen } from '@testing-library/react';
import { FieldItem } from '../../../src/components/base-form-materials/field-item';
describe('FieldItem', () => {
// 测试基本渲染
// Test basic rendering
it('should render title', () => {
const title = 'Test Title';
render(<FieldItem title={title} />);
@@ -30,14 +30,14 @@ describe('FieldItem', () => {
expect(titleElement).toBeInTheDocument();
});
// 测试必填标记渲染
// Test required tag rendering
it('should render required marker', () => {
render(<FieldItem title="Test" required />);
const requiredMarker = screen.getByText('*');
expect(requiredMarker).toBeInTheDocument();
});
// 测试提示信息渲染
// Test prompt information rendering
it('should render tooltip', () => {
const tooltipText = 'This is a tooltip';
const el = render(<FieldItem title="Test" tooltip={tooltipText} />);
@@ -47,7 +47,7 @@ describe('FieldItem', () => {
expect(tooltipIcon).toBeInTheDocument();
});
// 测试标签渲染
// test label rendering
it('should render tag', () => {
const tagText = 'New';
render(<FieldItem title="Test" tag={tagText} />);
@@ -55,7 +55,7 @@ describe('FieldItem', () => {
expect(tagElement).toBeInTheDocument();
});
// 测试描述信息渲染
// Test description information rendering
it('should render description', () => {
const descriptionText = 'This is a description';
render(<FieldItem title="Test" description={descriptionText} />);
@@ -63,7 +63,7 @@ describe('FieldItem', () => {
expect(descriptionElement).toBeInTheDocument();
});
// 测试反馈信息渲染
// Test feedback rendering
it('should render feedback', () => {
const feedbackText = 'This is a feedback';
render(<FieldItem title="Test" feedback={feedbackText} />);
@@ -71,7 +71,7 @@ describe('FieldItem', () => {
expect(feedbackElement).toBeInTheDocument();
});
// 测试子元素渲染
// Test child element rendering
it('should render children', () => {
const childText = 'Child Content';
render(<FieldItem title="Test">{childText}</FieldItem>);

View File

@@ -23,7 +23,7 @@ import { render, screen, fireEvent } from '@testing-library/react';
import { GroupCollapse } from '../../../src/components/base-form-materials/group-collapse/collapse';
describe('GroupCollapse', () => {
// 测试基本渲染
// Test basic rendering
it('should render label and initial content', () => {
const label = 'Test Label';
const childContent = 'Child Content';
@@ -36,7 +36,7 @@ describe('GroupCollapse', () => {
expect(childElement).toBeInTheDocument();
});
// 测试提示信息渲染
// Test prompt information rendering
it('should render tooltip', () => {
const tooltipText = 'This is a tooltip';
const el = render(
@@ -51,7 +51,7 @@ describe('GroupCollapse', () => {
expect(tooltipIcon).toBeInTheDocument();
});
// 测试额外内容渲染
// Test Extra Content Rendering
it('should render extra content', () => {
const extraText = 'Extra Content';
render(
@@ -64,26 +64,26 @@ describe('GroupCollapse', () => {
expect(extraElement).toBeInTheDocument();
});
// 测试点击标题展开/折叠功能
// Test click title to expand/collapse function
it('should toggle content when clicking the title', () => {
const childContent = 'Child Content';
const { getByText, queryByText } = render(
<GroupCollapse label="Test">{childContent}</GroupCollapse>,
);
// 初始状态下内容应该可见
// The content should be visible in the initial state
expect(queryByText(childContent)).toBeInTheDocument();
// 点击标题
// Click on the title
act(() => {
fireEvent.click(getByText('Test'));
});
// 点击后内容应该隐藏
// Content should be hidden after clicking
expect(queryByText(childContent)).toBeNull();
});
// 测试粘性状态样式
// Test sticky state style
it('should apply sticky class when out of viewport or closed', async () => {
const { useInViewport } = await vi.importMock('ahooks');
(useInViewport as any).mockReturnValue([false]);

View File

@@ -19,19 +19,19 @@ import { describe, it, expect } from 'vitest';
import { isFormSchemaPropertyEmpty } from '../../src/utils/is-property-empty';
describe('isFormSchemaPropertyEmpty', () => {
// 测试空对象
// Test an empty object
it('should return true for an empty object', () => {
const emptyObject = {};
expect(isFormSchemaPropertyEmpty(emptyObject)).toBe(true);
});
// 测试非空对象
// Testing non-empty objects
it('should return false for a non-empty object', () => {
const nonEmptyObject = { key: 'value' };
expect(isFormSchemaPropertyEmpty(nonEmptyObject)).toBe(false);
});
// 测试非对象值
// Testing non-object values
it('should return true for non-object values', () => {
const values = [null, undefined, 123, 'string', true, false, []];
values.forEach(value => {

View File

@@ -19,13 +19,13 @@ import { describe, it, expect } from 'vitest';
import { stringifyFormValuesFromBacked } from '../../src/utils/stringify-form-values-from-backed';
describe('stringifyFormValuesFromBacked', () => {
// 测试输入为空的情况
// When the test input is empty
it('should return undefined when input is null or undefined', () => {
expect(stringifyFormValuesFromBacked(null as any)).toBeUndefined();
expect(stringifyFormValuesFromBacked(undefined as any)).toBeUndefined();
});
// 测试输入包含字符串和布尔值的情况
// Test if the input contains strings and boolean values
it('should return the same string and boolean values', () => {
const input = {
str: 'hello',
@@ -38,7 +38,7 @@ describe('stringifyFormValuesFromBacked', () => {
});
});
// 测试输入包含对象和数组的情况
// Test if the input contains objects and arrays
it('should stringify objects and arrays', () => {
const input = {
obj: { key: 'value' },
@@ -51,7 +51,7 @@ describe('stringifyFormValuesFromBacked', () => {
});
});
// 测试输入包含 null undefined 的情况
// Test if the input contains null and undefined
it('should set null and undefined values to undefined in the result', () => {
const input = {
nullValue: null,

View File

@@ -40,12 +40,12 @@ export const GroupCollapse: React.FC<
const [isOpen, setIsOpen] = useState(true);
const ref = useRef(null);
/**
* 探测标题是否处于 sticky 状态
* Detect if the title is sticky
*/
const [inViewport] = useInViewport(ref);
return (
<div>
{/* 探测元素 */}
{/* probe element */}
<div ref={ref} />
{/* header */}
<div

View File

@@ -15,7 +15,7 @@
*/
/**
* 基础表单物料
* basic form material
*/
export { InputNumber, InputNumberProps } from './input-number';
export { InputString, type InputStringProps } from './input-string';

View File

@@ -35,11 +35,11 @@ export interface InputNumberProps {
onChange: (v?: string) => void;
onBlur: () => void;
onFocus: () => void;
/** 整型 */
/** integer */
int?: boolean;
}
/** 是否是合法的数字字符串 */
/** Is it a legal numeric string? */
function isValidNumber(str: string) {
try {
const value = new BigNumber(str);
@@ -71,17 +71,17 @@ export const InputNumber: React.FC<InputNumberProps> = ({
const handleBlur = () => {
if (props.value === '' || props.value === undefined) {
/** 失焦时若值为空,则同时清空验证值 */
/** If the value is empty when out of focus, the verification value is also cleared */
verifiedRef.current = undefined;
if (props.value === '') {
onChange(undefined);
}
} else {
/** 失焦时若值不为空,则需要验证值的合法性 */
/** If the value is not empty when out of focus, you need to verify the legitimacy of the value */
/**
* 1. 若值本身合法,则对值做格式化
* 2. 若值不合法,则采纳最近一次的合法值
* 3. 若都没有,则返回 undefined
* 1. If the value itself is legal, format the value
* 2. If the value is not legal, the most recent legal value is adopted
* 3. If none, return undefined
*/
let next: undefined | string;
const nextBig = normalizeNumber(props.value) || verifiedRef.current;
@@ -113,7 +113,7 @@ export const InputNumber: React.FC<InputNumberProps> = ({
onChange(next);
};
/** 当值发生变化,需要把值同步到合法数字 */
/** When the value changes, you need to synchronize the value to a legal number */
useEffect(() => {
if (props.value === '' || props.value === undefined) {
verifiedRef.current = undefined;

View File

@@ -32,7 +32,7 @@ export const FieldItem: React.FC<React.PropsWithChildren<FieldItemProps>> = ({
const schema = useFieldSchema();
const isBatchField = schema.path.includes(TestFormFieldName.Batch);
/** 批处理变量 tag 增加额外描述 */
/** Batch variable tag adds extra description */
const currentTag =
tag && isBatchField
? `${tag} - ${I18n.t('workflow_detail_node_batch')}`

View File

@@ -15,7 +15,7 @@
*/
/**
* 表单物料
* form material
*/
export { InputString } from './input-string';
export { FieldItem } from './field-item';

View File

@@ -15,7 +15,7 @@
*/
/**
* 固定的内部 field name
* Fixed internal field name
*/
export enum TestFormFieldName {
Node = '_node',
@@ -23,7 +23,7 @@ export enum TestFormFieldName {
Input = '_input',
Setting = '_setting',
JSON = '_json',
/** 关联内容 */
/** Linked Content */
Related = '_related',
Bot = '_bot',
Conversation = '_conversation',

View File

@@ -26,7 +26,7 @@ import { type StoreApi } from 'zustand';
import { type IFormSchema } from '../form-engine';
/**
* 单一表单内的全局性质状态集中管理
* Global nature state centralized management within a single form
*/
export interface TestRunFormState {
schema: IFormSchema | null;

View File

@@ -31,7 +31,7 @@ interface ReactiveFieldProps {
}
/**
* 接入响应式的 Field
* Access Responsive Fields
*/
const ReactiveField: React.FC<ReactiveFieldProps> = ({ parentUIState }) => {
const components = useComponents();
@@ -41,7 +41,7 @@ const ReactiveField: React.FC<ReactiveFieldProps> = ({ parentUIState }) => {
const formUIState = useFormUIState();
const fieldState = useCurrentFieldState();
/**
* 自生的 disabled 态由父亲和自身一起控制
* The autologous disabled state is controlled by the father along with the self
*/
const disabled =
parentUIState?.disabled || uiState.disabled || formUIState.disabled;

View File

@@ -27,7 +27,7 @@ const computePath = (path?: string[], name?: string) =>
[...(path || []), name].filter((i): i is string => Boolean(i));
/**
* 递归 Field
* Recursive Field
*/
const RecursionField: React.FC<RecursionFieldProps> = ({ name, schema }) => {
const renderProperties = () => {

View File

@@ -15,7 +15,7 @@
*/
/**
* 表单引擎
* form engine
*/
export { createSchemaField } from './fields';
export { FormSchema } from './shared';

View File

@@ -26,7 +26,7 @@ interface PropertyWithKey {
}
export class FormSchema implements IFormSchema {
/** IFormSchema 透传属性 */
/** IFormSchema pass-through properties */
type?: string | undefined;
title?: ReactNode;
description?: ReactNode;
@@ -34,7 +34,7 @@ export class FormSchema implements IFormSchema {
properties?: Record<string, IFormSchema>;
defaultValue?: any;
/** 模型属性 */
/** Model Properties */
uiState = new ReactiveState<FormSchemaUIState>({ disabled: false });
path: string[] = [];
@@ -64,7 +64,7 @@ export class FormSchema implements IFormSchema {
}
/**
* 获得有序的 properties
* Obtain ordered properties
*/
static getProperties(schema: FormSchema | IFormSchema) {
const orderProperties: PropertyWithKey[] = [];

View File

@@ -33,65 +33,65 @@ export interface FormSchemaUIState {
export interface IFormSchema<FrameworkComponent = React.ReactNode> {
/*******************************************************
* 核心属性
* core attributes
*/
version?: string;
name?: string;
type?: FormSchemaTypes;
/** 默认值“default” 是 jsonSchema 标准字段,但其为 js 关键字,遂使用 defaultValue */
/** Default value, "default" is the jsonSchema standard field, but it is the js keyword, so defaultValue is used */
defaultValue?: any;
/*******************************************************
* 下钻属性
* drill down properties
*/
properties?: Record<string, IFormSchema<FrameworkComponent>>;
items?: IFormSchema<FrameworkComponent>[];
/*******************************************************
* ui 属性
* UI attribute
*/
title?: FrameworkComponent | string;
description?: FrameworkComponent | string;
/** 顺序 */
/** order */
['x-index']?: number;
['x-visible']?: boolean;
['x-hidden']?: boolean;
['x-disabled']?: boolean;
/** 渲染的组件 */
/** Rendered components */
['x-component']?: string;
['x-component-props']?: Record<string, unknown>;
/** 装饰器 */
/** decorator */
['x-decorator']?: string;
['x-decorator-props']?: Record<string, unknown>;
/*******************************************************
* 合法性属性
* Legitimacy Attribute
*/
required?: boolean;
['x-validator']?: IFormSchemaValidate;
/*******************************************************
* 不常用或实现成本较高
* Less commonly used or more expensive to implement
*/
['x-reactions']?: any;
['x-content']?: FrameworkComponent;
/** 通配符字段 */
/** wild-card field */
patternProperties?: Record<string, IFormSchema<FrameworkComponent>>;
/** 定义之外的字段 */
/** Fields outside the definition */
additionalProperties?: IFormSchema<FrameworkComponent>;
/** 定义之外的项 */
/** Items outside the definition */
additionalItems?: IFormSchema<FrameworkComponent>;
/*******************************************************
* 业务自定义字段
* business custom field
*/
/** 节点 id */
/** Node ID */
['x-node-id']?: string;
/** 节点类型 */
/** Node type */
['x-node-type']?: string;
/** 表单模式 */
/** form mode */
['x-form-mode']?: 'form' | 'json';
/** 字段对应变量原始类型 */
/** Field corresponding variable primitive type */
['x-origin-type']?: string;
[key: string]: any;
}

View File

@@ -25,13 +25,13 @@ export const generateFieldComponent = (
options: GenerateFieldComponentOptions,
) => {
const { type, validateJsonSchema } = options;
/** 音色类型 */
/** timbre type */
if (ViewVariableType.Voice === type) {
return {
['x-component']: 'SelectVoice',
};
}
/** 文件类型 */
/** file type */
if (ViewVariableType.isFileType(type)) {
const fileType = [
ViewVariableType.Image,
@@ -42,14 +42,14 @@ export const generateFieldComponent = (
return {
['x-component']: 'TypedFileInput',
['x-component-props']: {
// 如果是数组类型,则表明是多选的文件选择器
// If it is an array type, it indicates that it is a multi-selected file selector
multiple: ViewVariableType.isArrayType(type),
accept: getFileAccept(type),
fileType,
},
};
}
/** 排除文件类型的对象类型、数组类型 */
/** Exclude object types and array types for file types */
if (ViewVariableType.isArrayType(type) || ViewVariableType.Object === type) {
return {
['x-component']: 'InputJson',
@@ -80,7 +80,7 @@ export const generateFieldComponent = (
['x-component']: 'InputTime',
};
}
/** string 类型和其它未知类型都渲染普通输入框 */
/** String type and other unknown types all render normal text boxes */
return {
['x-component']: 'InputString',
};

View File

@@ -29,8 +29,8 @@ interface GenerateFieldValidatorOptions {
}
/**
* ajv 实例缓存
* 无需导入创建或者多次创建,优化内存开销
* AJV instance cache
* No need to import or create multiple times, optimizing memory overhead
*/
let ajvCache: undefined | Ajv;
@@ -45,7 +45,7 @@ export const generateFieldValidator = (
param_name: title || name,
});
}
// 如果有结构化描述,还需要对值进行反序列化校验
// If there is a structured description, the value also needs to be deserialized
if (validateJsonSchema && value !== undefined) {
if (!ajvCache) {
ajvCache = new Ajv();
@@ -57,9 +57,9 @@ export const generateFieldValidator = (
return valid ? undefined : I18n.t('workflow_debug_wrong_json');
} catch {
/**
* 报错有多种可能,预期结果都是校验不通过
* 1. 值反序列化失败
* 2. 反序列化的值不合法
* There are many possibilities for error reporting, and the expected result is that the verification fails.
* 1. Value deserialization failed
* 2. The deserialized value is not legal
*/
return I18n.t('workflow_debug_wrong_json');
}

View File

@@ -32,7 +32,7 @@ interface GenerateFieldOptions {
}
/**
* 表单 Field Schema 计算
* Form Field Schema Calculation
*/
export const generateField = (options: GenerateFieldOptions): IFormSchema => {
const {
@@ -57,9 +57,9 @@ export const generateField = (options: GenerateFieldOptions): IFormSchema => {
},
['x-origin-type']: type as unknown as string,
...generateFieldValidator(options),
// 渲染组件相关
// rendering component related
...generateFieldComponent({ type, validateJsonSchema }),
// component 也自带默认值,入参的默认值优先级更高
// Component also comes with default values, and the default values of imported parameters have higher priority
defaultValue,
...extra,
};

View File

@@ -17,7 +17,7 @@
import { isObject } from 'lodash-es';
/**
* 是否是空的 properties
* Is it an empty property?
*/
export const isFormSchemaPropertyEmpty = (properties: unknown) =>
isObject(properties) ? !Object.keys(properties).length : true;

View File

@@ -19,21 +19,21 @@ import { describe, it, expect } from 'vitest';
import { safeJsonParse } from '../../src/utils/safe-json-parse';
describe('utils-safe-json-parse', () => {
// 测试正常解析 JSON 字符串
// Test parsing JSON string normally
it('should parse valid JSON string', () => {
const jsonString = '{"key": "value"}';
const result = safeJsonParse(jsonString);
expect(result).toEqual({ key: 'value' });
});
// 测试解析无效 JSON 字符串
// Test parsing invalid JSON string
it('should return undefined when parsing invalid JSON string', () => {
const invalidJsonString = '{key: "value"}';
const result = safeJsonParse(invalidJsonString);
expect(result).toBeUndefined();
});
// 测试空字符串输入
// Test empty string input
it('should return emptyValue when input is an empty string', () => {
const emptyString = '';
const emptyValue = {};

View File

@@ -28,19 +28,19 @@ import css from './panel.module.less';
interface BasePanelProps {
className?: string;
/**
* 面板头,不传不渲染
* Panel header, no pass and no render
*/
header?: React.ReactNode;
/**
* 面板脚,不传不渲染
* Panel foot, do not pass and do not render
*/
footer?: React.ReactNode;
/**
* 默认初始高度,不支持响应式
* Default initial height, does not support responsive
*/
height?: number;
/**
* 是否可拖拽改变高度
* Can you drag and drop to change the height?
*/
resizable?:
| boolean
@@ -49,7 +49,7 @@ interface BasePanelProps {
max?: number;
};
/**
* 点击关闭事件,仅当渲染面板头时可能触发
* Click to close the event, which may only be triggered when rendering the panel header
*/
onClose?: () => void;
}

View File

@@ -25,26 +25,26 @@ interface Config {
}
/**
* 目前仅支持高度可变
* Currently only highly variable is supported
*/
export const useResize = (config: Config) => {
const [dragging, setDragging] = useState(false);
const [height, setHeight] = useState(config.default);
const ref = useRef<HTMLDivElement>(null);
/**
* 拖拽过程中
* Dragging process
*/
const resizing = useRef(false);
/**
* y 轴变化
* Y-axis variation
*/
const startY = useRef(0);
/** 开始位置 */
/** starting position */
const start = useRef(0);
const handleMouseMove = useMemoizedFn(e => {
if (resizing.current) {
const newHeight = start.current - (e.clientY - startY.current); // 计算新的高度
const newHeight = start.current - (e.clientY - startY.current); // Calculate the new height
if (config.max && newHeight > config.max) {
setHeight(config.max);
} else if (config.min && newHeight < config.min) {
@@ -57,17 +57,17 @@ export const useResize = (config: Config) => {
const handleMouseUp = useCallback(() => {
resizing.current = false;
setDragging(false);
document.removeEventListener('mousemove', handleMouseMove); // 取消监听
document.removeEventListener('mouseup', handleMouseUp); // 取消监听
document.removeEventListener('mousemove', handleMouseMove); // Cancel listening
document.removeEventListener('mouseup', handleMouseUp); // Cancel listening
}, [handleMouseMove]);
const handleMouseDown = useMemoizedFn(e => {
resizing.current = true;
setDragging(true);
startY.current = e.clientY; // 记录鼠标开始拖拽时的 Y 轴坐标
startY.current = e.clientY; // Record the Y-axis coordinates when the mouse starts dragging
start.current = ref.current?.offsetHeight || 0;
document.addEventListener('mousemove', handleMouseMove); // 监听鼠标移动事件
document.addEventListener('mouseup', handleMouseUp); // 监听鼠标抬起事件
document.addEventListener('mousemove', handleMouseMove); // Monitor mouse movement events
document.addEventListener('mouseup', handleMouseUp); // Monitor mouse lift events
});
return {

View File

@@ -23,7 +23,7 @@ interface DebugUrlParams {
}
/**
* 计算 DebugUrl
* Calculate DebugUrl
*/
const getDebugUrl = (params: DebugUrlParams) => {
const { spaceId, workflowId, executeId, subExecuteId, nodeId } = params;

View File

@@ -35,7 +35,7 @@ export const useTrace = () => {
const fetch = useMemoizedFn(async (logId: string) => {
setLoading(true);
/** 查询日志时,开始结束时间必传,由于用户可查范围为 7 天内,所以直接伪造 7 天时间间隔即可 */
/** When querying the log, the start and end time must be passed. Since the user can check the range within 7 days, he can directly fake the 7-day time interval. */
const now = dayjs().endOf('day').valueOf();
const end = dayjs()
.subtract(MAX_TRACE_TIME, 'day')

View File

@@ -80,9 +80,9 @@ export const useOptions = (workflowId: string) => {
next.unshift(first);
}
}
// eslint-disable-next-line @coze-arch/no-empty-catch -- 无需报错
// eslint-disable-next-line @coze-arch/no-empty-catch -- no error required
} catch {
// 无需报错
// No error required
}
}
next.forEach(s => {
@@ -91,7 +91,7 @@ export const useOptions = (workflowId: string) => {
}
});
setOptions(next);
// 如果没有初始化,就初始化一次
// If it is not initialized, it is initialized once
if (!ready && !span && maybeInitialSpan) {
patch({ span: maybeInitialSpan });
}
@@ -103,7 +103,7 @@ export const useOptions = (workflowId: string) => {
const handleDateChange = useCallback(
(next: [Date, Date]) => {
const [start, end] = next;
// 时间选择器选择的日期是当天 0 点,需要转化为当天 11 点 59 分 59 秒
// The date selected by the time selector is 0:00 on the day, which needs to be converted to 11:59:59 on the day.
setDate([start, dayjs(end).endOf('day').toDate()] as [Date, Date]);
},
[setDate],

View File

@@ -20,5 +20,5 @@ export enum TraceChartsMode {
}
export const MAX_TRACE_LENGTH = 50;
/** 日志最多查询 7 天 */
/** Log query for up to 7 days */
export const MAX_TRACE_TIME = 7;

View File

@@ -24,14 +24,14 @@ export interface TraceListState {
spaceId: string;
workflowId: string;
isInOp?: boolean;
/** 初次打开时需要先请求列表,然后选中第一项 */
/** When opening it for the first time, you need to request the list first, and then select the first item. */
ready: boolean;
/** 当前选中的 span */
/** Currently selected span */
span: Span | null;
}
export interface TraceListAction {
/** 更新状态 */
/** update status */
patch: (next: Partial<TraceListState>) => void;
}

View File

@@ -79,7 +79,7 @@ export const defaultLabelStyle: LabelStyle = {
export const defaultLabelText: LabelText = (datum, element, params) =>
`${datum.start}-${datum.end}`;
// xScale的padding(解决hover后rect边框被截断问题)
// padding of xScale (solve the problem of rect border being truncated after hover)
export const scrollbarMargin = 10;
export const datazoomHeight = 20;
export const datazoomDecimals = 0;

View File

@@ -130,7 +130,7 @@ export const Flamethread: FC<FlamethreadProps> = props => {
[_globalLabelStyle],
);
// eslint-disable-next-line @typescript-eslint/no-magic-numbers -- 计算需要
// eslint-disable-next-line @typescript-eslint/no-magic-numbers -- calculation required
const topOffset = datazoomHeight + datazoomPaddingBottom + 8;
const globalStyle: GlobalStyle = useMemo(
@@ -146,7 +146,7 @@ export const Flamethread: FC<FlamethreadProps> = props => {
return rowCount * rowHeight;
}, [flamethreadData]);
// 此参数含义: 可视窗口Height / 火焰图Height
// Meaning of this parameter: Visual Window Height/Flame Map Height
const yScaleRangeFactor = useMemo(() => {
const rowCount = uniqWith(
flamethreadData,
@@ -187,7 +187,7 @@ export const Flamethread: FC<FlamethreadProps> = props => {
const tickData = scale.tickData(visibleColumnCount);
const dx =
tickData.length > 1
? // eslint-disable-next-line @typescript-eslint/no-magic-numbers -- 计算需要
? // eslint-disable-next-line @typescript-eslint/no-magic-numbers -- calculation required
(range[1] - range[0]) / (tickData.length - 1) / 2
: 0;
@@ -202,7 +202,7 @@ export const Flamethread: FC<FlamethreadProps> = props => {
style: { dx: -dx },
formatMethod: (_value: string) => {
const value = Number(_value);
// 特化逻辑: 隐藏0刻度
// Specialized logic: hide 0 ticks
if (dx > 0 && value === 0) {
return '';
}
@@ -218,7 +218,7 @@ export const Flamethread: FC<FlamethreadProps> = props => {
{
type: GrammarMarkType.component,
componentType: ComponentEnum.grid,
tickCount: visibleColumnCount, // vgrammer库的类型写的不严谨实际是可用的
tickCount: visibleColumnCount, // The types of the vgrammer library are not strictly written, but are actually usable
scale: 'xScale',
gridType: 'line',
gridShape: 'line',
@@ -277,7 +277,7 @@ export const Flamethread: FC<FlamethreadProps> = props => {
lineWidth,
lineDash,
visible: true,
// eslint-disable-next-line @typescript-eslint/no-magic-numbers -- 尺寸计算,无须处理
// eslint-disable-next-line @typescript-eslint/no-magic-numbers -- size calculation, no processing required
distance: lineWidth / 2,
};
},
@@ -297,7 +297,7 @@ export const Flamethread: FC<FlamethreadProps> = props => {
lineWidth,
lineDash,
visible: true,
// eslint-disable-next-line @typescript-eslint/no-magic-numbers -- 尺寸计算,无须定义常量
// eslint-disable-next-line @typescript-eslint/no-magic-numbers -- size calculation, no need to define constants
distance: lineWidth / 2,
};
},
@@ -318,7 +318,7 @@ export const Flamethread: FC<FlamethreadProps> = props => {
lineWidth,
lineDash,
visible: true,
// eslint-disable-next-line @typescript-eslint/no-magic-numbers -- 尺寸计算,无须定义常量
// eslint-disable-next-line @typescript-eslint/no-magic-numbers -- size calculation, no need to define constants
distance: lineWidth / 2,
};
},
@@ -344,7 +344,7 @@ export const Flamethread: FC<FlamethreadProps> = props => {
},
encode: {
update: {
pickable: false, // vgrammer库的类型写的不严谨实际是可用的
pickable: false, // The types of the vgrammer library are not strictly written, but are actually usable
text: labelText ?? defaultLabelText,
fill: (datum, _element, _params) => datum?.labelStyle.fill,
},
@@ -551,7 +551,7 @@ export const Flamethread: FC<FlamethreadProps> = props => {
[selectedKey],
);
// 创建/更新view
// Create/update view
useLayoutEffect(() => {
const initializeYScale = (view: IView) => {
const yScale = view?.getScaleById('yScale');
@@ -565,7 +565,7 @@ export const Flamethread: FC<FlamethreadProps> = props => {
const registerEvent = (view: IView) => {
const rectElm = view?.getMarkById('rect');
// rect点击事件
// Rect click event
rectElm?.addEventListener('click', ((event, element) => {
onClick?.(event, element);
}) as InteractionEventHandler);
@@ -574,7 +574,7 @@ export const Flamethread: FC<FlamethreadProps> = props => {
onClick?.(event, element);
}) as InteractionEventHandler);
// rect hover高亮
// Rect hover highlight
view?.interaction('element-highlight', {
selector: 'rect',
highlightState: 'hover2',
@@ -594,7 +594,7 @@ export const Flamethread: FC<FlamethreadProps> = props => {
});
}
// rect hover显示tooltip
// Rect hover tooltip
if (tooltip) {
view?.interaction('tooltip', {
selector: 'rect',

View File

@@ -51,7 +51,7 @@ export interface RectNode {
end: number;
rectStyle?: RectStyle;
labelStyle?: Pick<LabelStyle, 'fill'>;
// 其他字段,会透传
// Other fields will be passed through
extra?: unknown;
}
@@ -71,7 +71,7 @@ export interface FlamethreadProps {
rectStyle?: RectStyle;
labelStyle?: LabelStyle;
labelText?: LabelText;
// 结构太复杂,直接暴漏即可
// The structure is too complicated, just leak it directly
tooltip?: Tooltip;
globalStyle?: GlobalStyle;
rowHeight?: number;

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
/* eslint-disable @typescript-eslint/no-magic-numbers -- 本组件中会有很多位置计算的数字,无须处理*/
/* eslint-disable @typescript-eslint/no-magic-numbers -- there will be many numbers calculated in this component, no need to deal with them*/
import { type FC, useCallback, useMemo, useState } from 'react';
import { isFunction, mergeWith } from 'lodash-es';
@@ -68,8 +68,8 @@ export const Tree: FC<TreeProps> = ({
);
/**
* 使得指定的selectKey的Line置于顶层。
* 通过调整line顺序来实现z-index效果key${selectKey}的line在最上层
* Causes the Line of the specified selectKey to be placed at the top level.
* By adjusting the line order, the z-index effect is achieved: the line with the key ${selectKey} is at the top
*/
const adjustLineOrder = useCallback(
(lines: Line[]): Line[] => {
@@ -86,7 +86,7 @@ export const Tree: FC<TreeProps> = ({
}
}
// 支持根据zIndex控制高度
// Support controlling height according to zIndex
lines.sort((lineA, lineB) => {
const zIndexA = lineA.endNode.zIndex ?? -1;
const zIndexB = lineB.endNode.zIndex ?? -1;
@@ -137,7 +137,7 @@ export const Tree: FC<TreeProps> = ({
);
/**
* 根据line信息生成svg path。 colNo, rowNum都从0开始
* Generate svg path from line information. colNo, rowNum all start from 0
*/
const genSvgPath = useCallback(
(line: Line): string => {
@@ -151,41 +151,41 @@ export const Tree: FC<TreeProps> = ({
const { lineRadius = 0, lineGap = 0 } = normalLineStyle;
const nodeHeight = nodeBoxHeight + verticalInterval;
// 起始点
// starting point
const startX = startColNo * indent + offsetX;
const startY =
startRowNo * nodeHeight + (nodeBoxHeight + verticalInterval / 2);
if (startColNo === endColNo) {
// 竖线的长度
// The length of the vertical line
const lineASize =
(endRowNo - startRowNo - 1) * nodeHeight + verticalInterval;
// 移动到起始点
// Move to the starting point
const moveToStartPoint = `M ${startX} ${startY + lineGap}`;
// 竖线
// vertical line
const lineA = `L ${startX} ${startY + lineASize}`;
return `${moveToStartPoint} ${lineA}`;
} else {
// 竖线的长度
// The length of the vertical line
const lineASize =
(endRowNo - startRowNo - 1) * nodeHeight +
verticalInterval / 2 +
nodeHeight / 2 -
lineRadius;
// 横线的长度
// The length of the horizontal line
const lineBSize =
(endColNo - startColNo) * indent - offsetX - lineRadius;
// 结束点的坐标
// Coordinates of the end point
const endX = startX + lineBSize + lineRadius;
const endY = startY + lineASize + lineRadius;
// 移动到起始点
// Move to the starting point
const moveToStartPoint = `M ${startX} ${startY + lineGap}`;
// 竖线
// vertical line
const lineA = `L ${startX} ${startY + lineASize}`;
// 二次贝塞尔曲线
// Quadratic Bézier Curve
const qbc = `Q ${startX} ${endY} ${startX + lineRadius} ${endY}`;
// 横线
// horizontal line
const lineB = `L ${endX - lineGap} ${endY}`;
return `${moveToStartPoint} ${lineA} ${qbc} ${lineB}`;
}

View File

@@ -22,8 +22,8 @@ export type LineAttrs = Pick<
SVGAttributes<unknown>,
'stroke' | 'strokeDasharray' | 'strokeWidth'
> & {
lineRadius?: number; // line圆角半径 注意:这个数值不要大于 indent/2
lineGap?: number; // line距离boxgap
lineRadius?: number; // Line fillet radius, note: this value should not be greater than indent/2
lineGap?: number; // Line distance box gap
};
export interface LineStyle {
@@ -36,12 +36,12 @@ export interface LineStyle {
export interface TreeNode {
key: string;
title: ReactNode | ((nodeData: TreeNodeExtra) => ReactNode);
selectEnabled?: boolean; // 默认值 true
indentDisabled?: boolean; // 关闭缩进。 仅针对如下场景生效:子节点中的最后一个节点
lineStyle?: LineStyle; // 当指定了此属性时会覆盖全局的lineStyle
selectEnabled?: boolean; // Default value true
indentDisabled?: boolean; // Turn off indentation. Only works for the following scenarios: the last node in the sub-node
lineStyle?: LineStyle; // When this property is specified, the global lineStyle is overridden.
children?: TreeNode[];
zIndex?: number;
// 其他字段,会透传
// Other fields will be passed through
extra?: unknown;
}
@@ -58,12 +58,12 @@ export interface FilteredTreeNode extends SpanNode, TreeNodeInfo {
export type TreeNodeExtra = Omit<TreeNode, 'children'> & {
colNo: number;
rowNo: number;
unindented: boolean; // 相对于父节点,是否未缩进
selected: boolean; // 是否被选中
hover: boolean; // 是否hover
unindented: boolean; // Is it unindented relative to the parent node?
selected: boolean; // Is it selected?
hover: boolean; // Whether to hover
};
// 拉平后的TreeNode信息
// Flattened TreeNode information
export type TreeNodeFlatten = Omit<TreeNodeExtra, 'selected' | 'hover'>;
export interface Line {
@@ -72,9 +72,9 @@ export interface Line {
}
export interface GlobalStyle {
indent?: number; // 父节点和子节点的缩进距离
verticalInterval?: number; // node节点的垂直间距
nodeBoxHeight?: number; // node-box节点的高度
indent?: number; // Indent distance of parent and child nodes
verticalInterval?: number; // Vertical spacing of nodes
nodeBoxHeight?: number; // The height of the node-box node
offsetX?: number;
}
@@ -86,7 +86,7 @@ export interface MouseEventParams {
export interface TreeProps {
treeData: TreeNode;
selectedKey?: string;
indentDisabled?: boolean; // 关闭缩进。 仅针对如下场景生效:最后一个节点
indentDisabled?: boolean; // Turn off indentation. Only works for the following scenarios: the last node
lineStyle?: LineStyle;
globalStyle?: GlobalStyle;
className?: string;

View File

@@ -19,14 +19,14 @@ import { omit } from 'lodash-es';
import { type TreeNodeFlatten, type TreeNode, type Line } from './typing';
/**
* 基于TreeData生成:
* Generated based on TreeData:
*
* @param treeData tree原始数据
* @param options.indentDisabled 是否取消缩进。仅针对下述场景有效:异常节点+最后一个节点
* @param treeData tree original data source
* @Param options.indentDisabled Whether to unindent. Valid only for the following scenarios: exception node + last node
*
* @returns
* 1. nodes, 拉平后的node节点信息
* 2. lines, 用于将node进行连接
* 1. nodes, node information after leveling
* 2. lines, used to connect nodes
*/
export const flattenTreeData = (
treeData: TreeNode,
@@ -45,7 +45,7 @@ export const flattenTreeData = (
...omit(node, ['children']),
colNo: nodeColNo,
rowNo: nodes.length,
unindented: fatherNodeFlatten?.colNo === nodeColNo, // 未缩进
unindented: fatherNodeFlatten?.colNo === nodeColNo, // Unindented
};
nodes.push(nodeFlatten);
if (fatherNodeFlatten !== undefined) {
@@ -59,7 +59,7 @@ export const flattenTreeData = (
const childNodes = node.children;
childNodes.forEach((childNode, index) => {
// 取消缩进。 生效场景:异常节点+最后一个节点
// Cancel indentation. Effective scene: exception node + last node
const indentDisabled =
childNode.indentDisabled ?? options.indentDisabled;
if (indentDisabled && childNodes.length - 1 === index) {

View File

@@ -15,8 +15,8 @@
*/
/**
* @flow-devops/observation-components copy
* 暂不去理解其中逻辑
* From @flow-devops/observation-components copy
* I don't understand the logic yet.
*/
export { TraceTree } from './trace-tree';
export { TraceFlameThread } from './trace-flame-thread';

View File

@@ -33,12 +33,12 @@ export type TraceTreeProps = {
onCollapseChange?: (id: string) => void;
defaultDisplayMode?: DisplayMode;
/**
* 隐藏模式选择器
* hidden mode selector
*/
hideModeSelect?: boolean;
/** 宿主用户信息 */
/** Host user information */
hostUser?: {
/** 用户邮箱 */
/** user email */
email?: string;
/** user id */
id?: string;

View File

@@ -35,25 +35,25 @@ export interface Value {
}
export enum FrontedTagType {
/** 文本 */
/** Text */
TEXT = 0,
/** 时间,用时间戳,单位是微秒 */
/** Time, with timestamp, in microseconds */
TIME = 1,
/** 时间间隔,单位是微秒 */
/** Time interval, in microseconds */
TIME_DURATION = 2,
}
export interface FrontendTag {
key: string;
/** 多语,如无配置时值沿用 key */
/** Multilingual, if there is no configuration value, use the key */
key_alias?: string;
tag_type: TagType;
value?: Value;
/** 用于自定义渲染 */
/** For custom rendering */
element?: ReactNode;
/** 前端类型,用于前端处理 */
/** Front-end type for front-end processing */
frontend_tag_type?: FrontedTagType;
/** 是否可复制 */
/** Can it be copied? */
can_copy?: boolean;
}
@@ -64,7 +64,7 @@ export interface Tag {
}
export enum InputOutputType {
/** 文本类型 */
/** Text type */
TEXT = 0,
}
@@ -86,9 +86,9 @@ export interface TraceFrontendSpan {
name?: string;
alias_name?: string;
parent_id?: string;
/** 单位是微秒 */
/** That's in microseconds. */
duration?: Int64;
/** 单位是微秒 */
/** That's in microseconds. */
start_time?: Int64;
status_code?: number;
product_line?: string;
@@ -97,16 +97,16 @@ export interface TraceFrontendSpan {
owner_list?: Array<string>;
rundown_doc_url?: string;
tags?: Array<Tag>;
/** 节点详情 */
/** node details */
summary?: SpanSummary;
input?: SpanInputOutput;
output?: SpanInputOutput;
}
export interface TraceHeader {
/** 单位是微秒 */
/** That's in microseconds. */
duration?: Int64;
/** 输入消耗token数 */
/** Enter the number of tokens consumed */
tokens?: number;
status_code?: number;
tags?: Array<FrontendTag>;