chore: replace all cn comments of fe to en version by volc api (#320)
This commit is contained in:
@@ -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>);
|
||||
|
||||
@@ -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]);
|
||||
|
||||
@@ -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 => {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* 基础表单物料
|
||||
* basic form material
|
||||
*/
|
||||
export { InputNumber, InputNumberProps } from './input-number';
|
||||
export { InputString, type InputStringProps } from './input-string';
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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')}`
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* 表单物料
|
||||
* form material
|
||||
*/
|
||||
export { InputString } from './input-string';
|
||||
export { FieldItem } from './field-item';
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 = () => {
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* 表单引擎
|
||||
* form engine
|
||||
*/
|
||||
export { createSchemaField } from './fields';
|
||||
export { FormSchema } from './shared';
|
||||
|
||||
@@ -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[] = [];
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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',
|
||||
};
|
||||
|
||||
@@ -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');
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 = {};
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -23,7 +23,7 @@ interface DebugUrlParams {
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算 DebugUrl
|
||||
* Calculate DebugUrl
|
||||
*/
|
||||
const getDebugUrl = (params: DebugUrlParams) => {
|
||||
const { spaceId, workflowId, executeId, subExecuteId, nodeId } = params;
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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],
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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}`;
|
||||
}
|
||||
|
||||
@@ -22,8 +22,8 @@ export type LineAttrs = Pick<
|
||||
SVGAttributes<unknown>,
|
||||
'stroke' | 'strokeDasharray' | 'strokeWidth'
|
||||
> & {
|
||||
lineRadius?: number; // line圆角半径 注意:这个数值不要大于 indent/2
|
||||
lineGap?: number; // line距离box的gap
|
||||
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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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>;
|
||||
|
||||
Reference in New Issue
Block a user