feat: manually mirror opencoze's code from bytedance

Change-Id: I09a73aadda978ad9511264a756b2ce51f5761adf
This commit is contained in:
fanlv
2025-07-20 17:36:12 +08:00
commit 890153324f
14811 changed files with 1923430 additions and 0 deletions

View File

@@ -0,0 +1,17 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export { FieldItem, type FieldItemProps } from './item';

View File

@@ -0,0 +1,46 @@
.field-item {
margin-bottom: 12px;
}
.item-title {
position: relative;
margin-bottom: 4px;
font-size: 12px;
line-height: 16px;
overflow-wrap: break-word;
.item-label {
display: flex;
align-items: center;
margin-bottom: 2px;
}
.item-tag {
flex-shrink: 0;
margin-left: 4px;
}
.tooltip-icon {
margin-left: 4px;
color: var(--coz-fg-dim);
}
}
.title-text {
color: var(--coz-fg-primary);
}
.title-required {
color: var(--coz-fg-hglt-red);
}
.item-description {
color: var(--coz-fg-secondary);
}
.item-feedback {
margin-top: 2px;
font-size: 12px;
line-height: 16px;
color: var(--coz-fg-hglt-red);
overflow-wrap: break-word;
}

View File

@@ -0,0 +1,90 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import React from 'react';
import { IconCozInfoCircle } from '@coze-arch/coze-design/icons';
import { Tag, Tooltip, Typography } from '@coze-arch/coze-design';
import css from './item.module.less';
export interface FieldItemProps {
title?: React.ReactNode;
description?: React.ReactNode;
tag?: React.ReactNode;
tooltip?: React.ReactNode;
feedback?: string;
required?: boolean;
['data-testid']?: string;
}
export const FieldItem: React.FC<React.PropsWithChildren<FieldItemProps>> = ({
title,
required,
tooltip,
tag,
description,
children,
feedback,
...props
}) => (
<div className={css['field-item']} data-testid={props['data-testid']}>
{/* title */}
<div className={css['item-title']}>
<div className={css['item-label']}>
<Typography.Text className={css['title-text']} strong size="small">
{title}
</Typography.Text>
{required ? (
<Typography.Text className={css['title-required']}>*</Typography.Text>
) : null}
{tooltip ? (
<Tooltip content={tooltip}>
<IconCozInfoCircle className={css['tooltip-icon']} />
</Tooltip>
) : null}
{tag ? (
<Tag className={css['item-tag']} size="mini" color="primary">
{tag}
</Tag>
) : null}
</div>
{description ? (
<Typography.Text
ellipsis={{
showTooltip: {
opts: {
position: 'left',
style: {
maxWidth: 500,
},
},
},
}}
className={css['item-description']}
size="small"
>
{description}
</Typography.Text>
) : null}
</div>
{/* children */}
<div>{children}</div>
{/* feedback */}
{feedback ? <div className={css['item-feedback']}>{feedback}</div> : null}
</div>
);

View File

@@ -0,0 +1,53 @@
.collapse-title {
display: flex;
align-items: center;
font-size: 14px;
font-weight: 500;
height: 40px;
position: sticky;
top: 0;
background: var(--coz-bg-plus);
border-bottom: 1px solid var(--coz-bg-plus);
z-index: 1;
cursor: pointer;
&:hover .collapse-icon{
opacity: 1;
}
&.is-sticky {
border-color: var(--coz-stroke-primary);
}
}
.collapse-label {
font-size: 14px;
font-weight: 500;
height: 20px;
color: var(--coz-fg-primary);
}
.collapse-label-tooltip {
font-size: 14px;
margin-left: 4px;
color: var(--coz-fg-dim);
}
.collapse-icon {
transition: transform 0.3s ease-in-out, opacity 0.2s ease-in-out;
opacity: 0;
color: var(--coz-fg-dim);
font-size: 14px;
margin: 0 1px;
&.is-show {
opacity: 1;
}
&.is-close {
transform: rotate(-90deg);
}
}
.collapse-content {
padding: 0 16px;
}
.collapse-extra {
width: 0;
flex-grow: 1;
padding-right: 16px;
}

View File

@@ -0,0 +1,82 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import React, { useState, useRef } from 'react';
import { clsx } from 'clsx';
import { useInViewport } from 'ahooks';
import {
IconCozArrowDownFill,
IconCozInfoCircle,
} from '@coze-arch/coze-design/icons';
import { Collapsible, Tooltip } from '@coze-arch/coze-design';
import css from './collapse.module.less';
interface CollapseProps {
label: React.ReactNode;
tooltip?: React.ReactNode;
extra?: React.ReactNode;
fade?: boolean;
duration?: number;
}
export const GroupCollapse: React.FC<
React.PropsWithChildren<CollapseProps>
> = ({ label, tooltip, extra, children }) => {
const [isOpen, setIsOpen] = useState(true);
const ref = useRef(null);
/**
* 探测标题是否处于 sticky 状态
*/
const [inViewport] = useInViewport(ref);
return (
<div>
{/* 探测元素 */}
<div ref={ref} />
{/* header */}
<div
onClick={() => setIsOpen(!isOpen)}
className={clsx(
css['collapse-title'],
(!inViewport || !isOpen) && css['is-sticky'],
)}
>
<IconCozArrowDownFill
className={clsx(css['collapse-icon'], !isOpen && css['is-close'])}
/>
<span className={css['collapse-label']}>{label}</span>
{tooltip ? (
<Tooltip content={tooltip}>
<IconCozInfoCircle className={css['collapse-label-tooltip']} />
</Tooltip>
) : null}
{extra ? (
<div
className={css['collapse-extra']}
onClick={e => e.stopPropagation()}
>
{extra}
</div>
) : null}
</div>
{/* children */}
<Collapsible isOpen={isOpen} keepDOM fade duration={300}>
<div className={css['collapse-content']}>{children}</div>
</Collapsible>
</div>
);
};

View File

@@ -0,0 +1,17 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export { GroupCollapse } from './collapse';

View File

@@ -0,0 +1,27 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* 基础表单物料
*/
export { InputNumber, InputNumberProps } from './input-number';
export { InputString, type InputStringProps } from './input-string';
export { InputTime, type InputTimeProps } from './input-time';
export { InputJson, type InputJsonProps } from './input-json';
export { SelectBoolean } from './select-boolean';
export { SelectVoice } from './select-voice';
export { FieldItem, type FieldItemProps } from './field-item';
export { GroupCollapse } from './group-collapse';

View File

@@ -0,0 +1,17 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export { InputJson, type InputJsonProps } from './json';

View File

@@ -0,0 +1,33 @@
.input-json-wrap {
border: 1px solid var(--coz-stroke-plus);
border-radius: 8px;
&.disabled {
background-color: rgba(var(--coze-bg-5), var(--coze-bg-5-alpha));
cursor: not-allowed;
}
&.error {
border: 1px solid var(--coz-stroke-hglt-red);
}
}
.json-header {
display: flex;
align-items: center;
justify-content: space-between;
height: 28px;
padding: 0 4px;
border-bottom: 1px solid var(--coz-stroke-plus);
border-top-left-radius: 8px;
border-top-right-radius: 8px;
.json-label {
font-size: 12px;
color: var(--coz-fg-secondary);
font-weight: 500;
}
}
.json-editor {
overflow: hidden;
border-bottom-left-radius: 8px;
}

View File

@@ -0,0 +1,88 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { clsx } from 'clsx';
import {
JsonEditor,
safeFormatJsonString,
} from '@coze-workflow/test-run-shared';
import { I18n } from '@coze-arch/i18n';
import { IconCozBroom } from '@coze-arch/coze-design/icons';
import { Tooltip, IconButton } from '@coze-arch/coze-design';
import css from './json.module.less';
export interface InputJsonProps {
value?: string;
disabled?: boolean;
extensions?: any;
jsonSchema?: any;
height?: string;
validateStatus?: 'error';
['data-testid']?: string;
onChange?: (v?: string) => void;
didMount?: (editor: any) => void;
}
export const InputJson: React.FC<InputJsonProps> = ({
value,
disabled,
validateStatus,
onChange,
...props
}) => {
const handleFormat = () => {
const next = safeFormatJsonString(value);
if (next !== value) {
onChange?.(next);
}
};
return (
<div
className={clsx(
css['input-json-wrap'],
disabled && css.disabled,
validateStatus === 'error' && css.error,
)}
data-testid={props['data-testid']}
>
<div className={css['json-header']}>
<div className={css['json-label']}>JSON</div>
<div>
<Tooltip content={I18n.t('workflow_exception_ignore_format')}>
<IconButton
icon={<IconCozBroom />}
disabled={disabled}
size="small"
color="secondary"
onMouseDown={e => e.preventDefault()}
onClick={handleFormat}
/>
</Tooltip>
</div>
</div>
<div className={css['json-editor']}>
<JsonEditor
value={value}
disabled={disabled}
onChange={onChange}
{...props}
/>
</div>
</div>
);
};

View File

@@ -0,0 +1,17 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export { InputNumber, type InputNumberProps } from './input-number';

View File

@@ -0,0 +1,27 @@
.buttons {
display: flex;
flex-direction: column;
width: 20px;
position: relative;
right: -7px;
}
.button {
font-size: 10px;
color: var(--coz-fg-primary);
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
&:hover {
background-color: rgba(var(--coze-bg-5), var(--coze-bg-5-alpha));
}
&.up {
border-top-left-radius: var(--coze-5);
border-top-right-radius: var(--coze-5);
}
&.down {
border-bottom-left-radius: var(--coze-5);
border-bottom-right-radius: var(--coze-5);
}
}

View File

@@ -0,0 +1,147 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { useRef, useEffect } from 'react';
import clsx from 'clsx';
import BigNumber, { type BigNumber as IBigNumber } from 'bignumber.js';
import {
IconCozArrowDownFill,
IconCozArrowUpFill,
} from '@coze-arch/coze-design/icons';
import { Input, type InputProps } from '@coze-arch/coze-design';
import css from './input-number.module.less';
export interface InputNumberProps {
value?: string;
style?: React.CSSProperties;
placeholder?: string;
validateStatus?: InputProps['validateStatus'];
disabled?: boolean;
onChange: (v?: string) => void;
onBlur: () => void;
onFocus: () => void;
/** 整型 */
int?: boolean;
}
/** 是否是合法的数字字符串 */
function isValidNumber(str: string) {
try {
const value = new BigNumber(str);
return !value.isNaN();
} catch {
return false;
}
}
function normalizeNumber(str?: string) {
if (!str || !isValidNumber(str)) {
return;
}
return new BigNumber(str);
}
export const InputNumber: React.FC<InputNumberProps> = ({
int,
onChange,
onBlur,
...props
}) => {
const verifiedRef = useRef<undefined | IBigNumber>(
normalizeNumber(props.value),
);
const fixed = (num: IBigNumber, innerInt?: boolean) =>
innerInt ? num.toFixed(0, BigNumber.ROUND_DOWN) : num.toFixed();
const handleBlur = () => {
if (props.value === '' || props.value === undefined) {
/** 失焦时若值为空,则同时清空验证值 */
verifiedRef.current = undefined;
if (props.value === '') {
onChange(undefined);
}
} else {
/** 失焦时若值不为空,则需要验证值的合法性 */
/**
* 1. 若值本身合法,则对值做格式化
* 2. 若值不合法,则采纳最近一次的合法值
* 3. 若都没有,则返回 undefined
*/
let next: undefined | string;
const nextBig = normalizeNumber(props.value) || verifiedRef.current;
if (nextBig) {
next = fixed(nextBig, int);
}
if (next !== props.value) {
onChange(next);
}
}
onBlur();
};
const handlePlus = () => {
let next = '1';
if (verifiedRef.current) {
const nextNum = verifiedRef.current.plus('1');
next = fixed(nextNum, int);
}
onChange(next);
};
const handleMinus = () => {
let next = '0';
if (verifiedRef.current) {
const nextNum = verifiedRef.current.minus('1');
next = fixed(nextNum, int);
}
onChange(next);
};
/** 当值发生变化,需要把值同步到合法数字 */
useEffect(() => {
if (props.value === '' || props.value === undefined) {
verifiedRef.current = undefined;
}
const next = normalizeNumber(props.value);
if (next) {
verifiedRef.current = normalizeNumber(props.value);
}
}, [props.value]);
return (
<Input
onChange={onChange}
onBlur={handleBlur}
size="small"
suffix={
props.disabled ? null : (
<div className={css.buttons}>
<div className={clsx(css.button, css.up)} onClick={handlePlus}>
<IconCozArrowUpFill />
</div>
<div className={clsx(css.button, css.down)} onClick={handleMinus}>
<IconCozArrowDownFill />
</div>
</div>
)
}
{...props}
/>
);
};

View File

@@ -0,0 +1,17 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export { InputString, type InputStringProps } from './input';

View File

@@ -0,0 +1,14 @@
// semi 和 coze 都不支持小尺寸的 textarea 需要业务实现
.input-string.small {
font-size: 12px;
line-height: 20px;
padding: 1px 3px;
border-radius: 6px;
:global textarea {
font-size: 12px;
line-height: 20px;
}
:global .semi-input-clearbtn {
height: 22px;
}
}

View File

@@ -0,0 +1,34 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import clsx from 'clsx';
import { TextArea } from '@coze-arch/coze-design';
import css from './input.module.less';
export interface InputStringProps {
value?: string;
}
export const InputString: React.FC<InputStringProps> = props => (
<TextArea
className={clsx(css['input-string'], css.small)}
autosize={{ minRows: 1, maxRows: 5 }}
rows={1}
showClear
{...props}
/>
);

View File

@@ -0,0 +1,17 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export { InputTime, type InputTimeProps } from './time';

View File

@@ -0,0 +1,6 @@
.input-time {
width: 100%;
:global .semi-select {
width: 100%;
}
}

View File

@@ -0,0 +1,50 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import React from 'react';
import { clsx } from 'clsx';
import { DatePicker } from '@coze-arch/coze-design';
import css from './time.module.less';
export interface InputTimeProps {
className?: string;
value?: string;
onChange?: (v?: string) => void;
}
export const InputTime: React.FC<InputTimeProps> = ({
className,
value,
onChange,
...props
}) => (
<DatePicker
className={clsx(css['input-time'], className)}
type="dateTime"
size="small"
showClear={false}
showSuffix={false}
value={value}
onChange={(_date, dateString) => {
if (typeof dateString === 'string' || dateString === undefined) {
onChange?.(dateString);
}
}}
{...props}
/>
);

View File

@@ -0,0 +1,17 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export { SelectBoolean } from './select';

View File

@@ -0,0 +1,3 @@
.select-boolean {
width: 100%;
}

View File

@@ -0,0 +1,61 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import React, { useCallback, useMemo } from 'react';
import { clsx } from 'clsx';
import { Select, type SelectProps } from '@coze-arch/coze-design';
import css from './select.module.less';
interface SelectBooleanProps {
className?: string;
value?: boolean;
onChange?: (v?: boolean) => void;
}
export const SelectBoolean: React.FC<SelectBooleanProps> = ({
className,
value,
onChange,
...props
}) => {
const formattedValue = useMemo(
() => (value === undefined ? undefined : Number(value)),
[value],
);
const handleChange = useCallback(
(v?: SelectProps['value']) => {
const next = v === undefined ? v : Boolean(v);
onChange?.(next);
},
[onChange],
);
return (
<Select
className={clsx(css['select-boolean'], className)}
size="small"
value={formattedValue}
onChange={handleChange}
{...props}
>
<Select.Option value={1}>True</Select.Option>
<Select.Option value={0}>False</Select.Option>
</Select>
);
};

View File

@@ -0,0 +1,36 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { VoiceSelect } from '@coze-workflow/components';
interface SelectVoiceProps {
value?: string;
onChange?: (v?: string) => void;
onBlur?: () => void;
}
export const SelectVoice: React.FC<SelectVoiceProps> = ({
onChange,
onBlur,
...props
}) => {
const handleChange = (v?: string) => {
onChange?.(v);
onBlur?.();
};
return <VoiceSelect onChange={handleChange} {...props} />;
};

View File

@@ -0,0 +1,50 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import React from 'react';
import { I18n } from '@coze-arch/i18n';
import {
FieldItem as BaseFieldItem,
type FieldItemProps,
} from '../../base-form-materials';
import { useFieldSchema } from '../../../form-engine';
import { TestFormFieldName } from '../../../constants';
export const FieldItem: React.FC<React.PropsWithChildren<FieldItemProps>> = ({
tag,
...props
}) => {
const schema = useFieldSchema();
const isBatchField = schema.path.includes(TestFormFieldName.Batch);
/** 批处理变量 tag 增加额外描述 */
const currentTag =
tag && isBatchField
? `${tag} - ${I18n.t('workflow_detail_node_batch')}`
: tag;
return (
<BaseFieldItem
title={schema.title}
description={schema.description}
required={schema.required}
tag={currentTag}
{...props}
/>
);
};

View File

@@ -0,0 +1,27 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* 表单物料
*/
export { InputString } from './input-string';
export { FieldItem } from './field-item';
export { InputNumber } from './input-number';
export { InputInteger } from './input-integer';
export { InputTime } from './input-time';
export { InputJson } from './input-json';
export { SelectBoolean } from './select-boolean';
export { SelectVoice } from './select-voice';

View File

@@ -0,0 +1,19 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { InputNumber as BaseInputNumber } from '../../base-form-materials';
export const InputInteger = props => <BaseInputNumber int {...props} />;

View File

@@ -0,0 +1,17 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export { InputJson } from '../../base-form-materials';

View File

@@ -0,0 +1,19 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { InputNumber as BaseInputNumber } from '../../base-form-materials';
export const InputNumber = props => <BaseInputNumber {...props} />;

View File

@@ -0,0 +1,19 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { InputString as BaseInputString } from '../../base-form-materials';
export const InputString = BaseInputString;

View File

@@ -0,0 +1,17 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export { InputTime } from '../../base-form-materials';

View File

@@ -0,0 +1,17 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export { SelectBoolean } from '../../base-form-materials';

View File

@@ -0,0 +1,17 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export { SelectVoice } from '../../base-form-materials';

View File

@@ -0,0 +1,17 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export { TestRunForm } from './test-run-form';

View File

@@ -0,0 +1,72 @@
/*
* Copyright 2025 coze-dev Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { Form, type FormModel } from '@flowgram-adapter/free-layout-editor';
import {
InputString,
InputNumber,
InputInteger,
InputJson,
SelectBoolean,
SelectVoice,
InputTime,
FieldItem,
} from '../form-materials';
import {
createSchemaField,
type FormSchema,
useCreateForm,
type IFormSchema,
type FormSchemaReactComponents,
} from '../../form-engine';
const SchemaField = createSchemaField({
components: {
InputString,
InputNumber,
InputInteger,
InputTime,
InputJson,
SelectBoolean,
SelectVoice,
FieldItem,
},
});
interface TestRunFormProps {
schema: IFormSchema;
components?: FormSchemaReactComponents;
onFormValuesChange?: (payload: any) => void;
onMounted?: (formModel: FormModel, schema: FormSchema) => void;
}
export const TestRunForm: React.FC<TestRunFormProps> = ({
schema,
components,
onFormValuesChange,
onMounted,
}) => {
const { control, formSchema } = useCreateForm(schema, {
onFormValuesChange,
onMounted,
});
return (
<Form control={control}>
<SchemaField schema={formSchema} components={components} />
</Form>
);
};