mirror of
https://gitee.com/baidu/amis.git
synced 2024-11-29 18:48:45 +08:00
补充表单项组件testid (#9646)
This commit is contained in:
parent
51131b64c0
commit
c747bf62ea
@ -246,6 +246,7 @@ export default function (schema, schemaProps, showCode, envOverrides) {
|
||||
};
|
||||
});
|
||||
},
|
||||
enableTestid: true,
|
||||
...envOverrides
|
||||
};
|
||||
|
||||
|
@ -478,9 +478,11 @@ export class SchemaRenderer extends React.Component<SchemaRendererProps, any> {
|
||||
// 优先使用组件自己的testid或者id,这个解决不了table行内的一些子元素
|
||||
// 每一行都会出现这个testid的元素,只在测试工具中直接使用nth拿序号
|
||||
if (props.testid || props.id || props.testIdBuilder == null) {
|
||||
props.testIdBuilder = new TestIdBuilder(
|
||||
rest.env.enableTestid ? props.testid || props.id : null
|
||||
);
|
||||
if (!(props.testIdBuilder instanceof TestIdBuilder)) {
|
||||
props.testIdBuilder = new TestIdBuilder(
|
||||
rest.env.enableTestid ? props.testid || props.id : null
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// 自动解析变量模式,主要是方便直接引入第三方组件库,无需为了支持变量封装一层
|
||||
|
@ -2,6 +2,7 @@
|
||||
import type {JSONSchema7} from 'json-schema';
|
||||
import {ListenerAction} from './actions/Action';
|
||||
import {debounceConfig, trackConfig} from './utils/renderer-event';
|
||||
import type {TestIdBuilder} from './utils/helper';
|
||||
|
||||
export interface Option {
|
||||
/**
|
||||
@ -689,6 +690,8 @@ export interface BaseSchemaWithoutType {
|
||||
* 可以组件级别用来关闭移动端样式
|
||||
*/
|
||||
useMobileUI?: boolean;
|
||||
|
||||
testIdBuilder?: TestIdBuilder;
|
||||
}
|
||||
|
||||
export type OperatorType =
|
||||
|
@ -2303,7 +2303,7 @@ export class TestIdBuilder {
|
||||
}
|
||||
|
||||
// 生成子区域的testid生成器
|
||||
getChild(childPath: string, data?: object) {
|
||||
getChild(childPath: string | number, data?: object) {
|
||||
if (this.testId == null) {
|
||||
return new TestIdBuilder();
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ import {ClassNamesFn, themeable, ThemeProps} from 'amis-core';
|
||||
import {RootClose} from 'amis-core';
|
||||
import {removeHTMLTag} from 'amis-core';
|
||||
import {Icon} from './icons';
|
||||
import type {TestIdBuilder} from 'amis-core';
|
||||
|
||||
export type ItemPlace = 'start' | 'middle' | 'end';
|
||||
export type TooltipPositionType = 'top' | 'bottom' | 'left' | 'right';
|
||||
@ -32,6 +33,7 @@ interface BreadcrumbItemProps {
|
||||
tooltipContainer?: any;
|
||||
tooltipPosition?: TooltipPositionType;
|
||||
classnames: ClassNamesFn;
|
||||
testIdBuilder?: TestIdBuilder;
|
||||
[propName: string]: any;
|
||||
}
|
||||
|
||||
@ -39,6 +41,7 @@ interface BreadcrumbProps extends ThemeProps {
|
||||
tooltipContainer?: any;
|
||||
tooltipPosition?: TooltipPositionType;
|
||||
items: Array<BreadcrumbBaseItem>;
|
||||
testIdBuilder?: TestIdBuilder;
|
||||
[propName: string]: any;
|
||||
}
|
||||
|
||||
@ -65,6 +68,7 @@ export class Breadcrumb extends React.Component<BreadcrumbProps> {
|
||||
separatorClassName,
|
||||
items,
|
||||
separator,
|
||||
testIdBuilder,
|
||||
...restProps
|
||||
} = this.props;
|
||||
|
||||
@ -75,6 +79,9 @@ export class Breadcrumb extends React.Component<BreadcrumbProps> {
|
||||
|
||||
const crumbs = items
|
||||
.map<React.ReactNode>((item, index) => {
|
||||
const itemTestIdBuilder = testIdBuilder?.getChild(
|
||||
`item-${item.label || index}`
|
||||
);
|
||||
let itemPlace: ItemPlace = 'middle';
|
||||
if (index === 0) {
|
||||
itemPlace = 'start';
|
||||
@ -88,6 +95,7 @@ export class Breadcrumb extends React.Component<BreadcrumbProps> {
|
||||
item={item}
|
||||
itemPlace={itemPlace}
|
||||
key={index}
|
||||
testIdBuilder={itemTestIdBuilder}
|
||||
></BreadcrumbItem>
|
||||
);
|
||||
})
|
||||
@ -157,7 +165,12 @@ export class BreadcrumbItem extends React.Component<
|
||||
item: BreadcrumbBaseItem,
|
||||
label?: string
|
||||
) {
|
||||
const {itemClassName, dropdownItemClassName, classnames: cx} = this.props;
|
||||
const {
|
||||
itemClassName,
|
||||
dropdownItemClassName,
|
||||
classnames: cx,
|
||||
testIdBuilder
|
||||
} = this.props;
|
||||
const baseItemClassName =
|
||||
itemType === 'default' ? itemClassName : dropdownItemClassName;
|
||||
if (showHref) {
|
||||
@ -165,6 +178,7 @@ export class BreadcrumbItem extends React.Component<
|
||||
<a
|
||||
href={item.href}
|
||||
className={cx('Breadcrumb-item-' + itemType, baseItemClassName)}
|
||||
{...testIdBuilder?.getTestId()}
|
||||
>
|
||||
{item.icon ? (
|
||||
<Icon
|
||||
@ -179,7 +193,10 @@ export class BreadcrumbItem extends React.Component<
|
||||
);
|
||||
}
|
||||
return (
|
||||
<span className={cx('Breadcrumb-item-' + itemType, baseItemClassName)}>
|
||||
<span
|
||||
className={cx('Breadcrumb-item-' + itemType, baseItemClassName)}
|
||||
{...testIdBuilder?.getTestId()}
|
||||
>
|
||||
{item.icon ? (
|
||||
<Icon
|
||||
cx={cx}
|
||||
|
@ -117,8 +117,13 @@ export class Checkbox extends React.Component<CheckboxProps, any> {
|
||||
readOnly={readOnly}
|
||||
name={name}
|
||||
/>
|
||||
<i />
|
||||
<span className={cx(labelClassName)}>{children || label}</span>
|
||||
<i {...testIdBuilder?.getChild('input').getTestId()} />
|
||||
<span
|
||||
className={cx(labelClassName)}
|
||||
{...testIdBuilder?.getChild('label').getTestId()}
|
||||
>
|
||||
{children || label}
|
||||
</span>
|
||||
{description ? (
|
||||
<div className={cx('Checkbox-desc')}>{description}</div>
|
||||
) : null}
|
||||
|
@ -27,7 +27,7 @@ import Input from './Input';
|
||||
import Button from './Button';
|
||||
|
||||
import type {Moment} from 'moment';
|
||||
import type {PlainObject, RendererEnv} from 'amis-core';
|
||||
import type {PlainObject, RendererEnv, TestIdBuilder} from 'amis-core';
|
||||
import type {ChangeEventViewMode, MutableUnitOfTime} from './calendar/Calendar';
|
||||
|
||||
const availableShortcuts: {[propName: string]: any} = {
|
||||
@ -334,6 +334,7 @@ export interface DateProps extends LocaleProps, ThemeProps {
|
||||
|
||||
// 是否为结束时间
|
||||
isEndDate?: boolean;
|
||||
testIdBuilder?: TestIdBuilder;
|
||||
|
||||
disabledDate?: (date: moment.Moment) => any;
|
||||
onClick?: (date: moment.Moment) => any;
|
||||
@ -949,6 +950,7 @@ export class DatePicker extends React.Component<DateProps, DatePickerState> {
|
||||
mobileCalendarMode,
|
||||
label,
|
||||
env,
|
||||
testIdBuilder,
|
||||
onClick,
|
||||
onMouseEnter,
|
||||
onMouseLeave,
|
||||
@ -1058,6 +1060,7 @@ export class DatePicker extends React.Component<DateProps, DatePickerState> {
|
||||
onClick={onClick}
|
||||
onMouseEnter={onMouseEnter}
|
||||
onMouseLeave={onMouseLeave}
|
||||
testIdBuilder={testIdBuilder?.getChild('calendar')}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
@ -1081,6 +1084,7 @@ export class DatePicker extends React.Component<DateProps, DatePickerState> {
|
||||
)}
|
||||
ref={this.domRef}
|
||||
onClick={this.handleClick}
|
||||
{...testIdBuilder?.getTestId()}
|
||||
>
|
||||
<Input
|
||||
className={cx('DatePicker-input')}
|
||||
@ -1092,17 +1096,25 @@ export class DatePicker extends React.Component<DateProps, DatePickerState> {
|
||||
value={this.state.inputValue || ''}
|
||||
disabled={disabled}
|
||||
readOnly={mobileUI}
|
||||
{...testIdBuilder?.getChild('input').getTestId()}
|
||||
/>
|
||||
|
||||
{clearable &&
|
||||
!disabled &&
|
||||
normalizeDate(value, valueFormat || format) ? (
|
||||
<a className={cx(`DatePicker-clear`)} onClick={this.clearValue}>
|
||||
<a
|
||||
className={cx(`DatePicker-clear`)}
|
||||
onClick={this.clearValue}
|
||||
{...testIdBuilder?.getChild('clear').getTestId()}
|
||||
>
|
||||
<Icon icon="input-clear" className="icon" />
|
||||
</a>
|
||||
) : null}
|
||||
|
||||
<a className={cx(`DatePicker-toggler`)}>
|
||||
<a
|
||||
className={cx(`DatePicker-toggler`)}
|
||||
{...testIdBuilder?.getChild('toggler').getTestId()}
|
||||
>
|
||||
<Icon
|
||||
icon={viewMode === 'time' ? 'clock' : 'date'}
|
||||
className="icon"
|
||||
@ -1151,6 +1163,7 @@ export class DatePicker extends React.Component<DateProps, DatePickerState> {
|
||||
onClick={onClick}
|
||||
onMouseEnter={onMouseEnter}
|
||||
onMouseLeave={onMouseLeave}
|
||||
testIdBuilder={testIdBuilder?.getChild('calendar')}
|
||||
// utc={utc}
|
||||
/>
|
||||
{isConfirmMode ? (
|
||||
@ -1209,6 +1222,7 @@ export class DatePicker extends React.Component<DateProps, DatePickerState> {
|
||||
onClick={onClick}
|
||||
onMouseEnter={onMouseEnter}
|
||||
onMouseLeave={onMouseLeave}
|
||||
testIdBuilder={testIdBuilder?.getChild('calendar')}
|
||||
// utc={utc}
|
||||
/>
|
||||
</PopUp>
|
||||
|
@ -2,6 +2,7 @@ import {ThemeProps, themeable} from 'amis-core';
|
||||
import React from 'react';
|
||||
import {Options, Option} from 'amis-core';
|
||||
import {LocaleProps, localeable} from 'amis-core';
|
||||
import type {TestIdBuilder} from 'amis-core';
|
||||
|
||||
export interface ListMenuProps extends ThemeProps, LocaleProps {
|
||||
options: Options;
|
||||
@ -14,6 +15,7 @@ export interface ListMenuProps extends ThemeProps, LocaleProps {
|
||||
getItemProps: (props: {item: Option; index: number}) => any;
|
||||
prefix?: JSX.Element;
|
||||
children?: React.ReactNode | Array<React.ReactNode>;
|
||||
testIdBuilder?: TestIdBuilder;
|
||||
}
|
||||
|
||||
interface RenderResult {
|
||||
@ -37,7 +39,8 @@ export class ListMenu extends React.Component<ListMenuProps> {
|
||||
highlightIndex,
|
||||
selectedOptions,
|
||||
mobileUI,
|
||||
onSelect
|
||||
onSelect,
|
||||
testIdBuilder
|
||||
} = this.props;
|
||||
|
||||
if (Array.isArray(option.children) && option.children.length) {
|
||||
@ -74,6 +77,7 @@ export class ListMenu extends React.Component<ListMenuProps> {
|
||||
)}
|
||||
key={index}
|
||||
onClick={onSelect ? (e: any) => onSelect(e, option) : undefined}
|
||||
{...testIdBuilder?.getChild(option.value || index).getTestId()}
|
||||
{...getItemProps({
|
||||
item: option,
|
||||
index: index
|
||||
|
@ -22,6 +22,7 @@ import {value2array, OptionProps, Option} from './Select';
|
||||
import chunk from 'lodash/chunk';
|
||||
import {ClassNamesFn, themeable} from 'amis-core';
|
||||
import {columnsSplit} from 'amis-core';
|
||||
import {TestIdBuilder} from 'amis-core';
|
||||
|
||||
interface RadioProps extends OptionProps {
|
||||
id?: string;
|
||||
@ -42,6 +43,7 @@ interface RadioProps extends OptionProps {
|
||||
classPrefix: string;
|
||||
classnames: ClassNamesFn;
|
||||
renderLabel?: (item: Option, props: RadioProps) => JSX.Element;
|
||||
testIdBuilder?: TestIdBuilder;
|
||||
}
|
||||
|
||||
const defaultLabelRender = (item: Option, props: RadioProps) => (
|
||||
@ -123,8 +125,10 @@ export class Radios extends React.Component<RadioProps, any> {
|
||||
level,
|
||||
btnActiveLevel,
|
||||
classPrefix: ns,
|
||||
testIdBuilder,
|
||||
renderLabel = defaultLabelRender
|
||||
} = this.props;
|
||||
const itemTestIdBuilder = testIdBuilder?.getChild(option.value || index);
|
||||
|
||||
if (optionType === 'button') {
|
||||
const active = !!~valueArray.indexOf(option);
|
||||
@ -153,6 +157,7 @@ export class Radios extends React.Component<RadioProps, any> {
|
||||
description={option.description}
|
||||
inline={inline}
|
||||
labelClassName={labelClassName}
|
||||
testIdBuilder={itemTestIdBuilder}
|
||||
>
|
||||
{renderLabel(option, this.props)}
|
||||
</Checkbox>
|
||||
|
@ -1,4 +1,4 @@
|
||||
import {ThemeProps, themeable} from 'amis-core';
|
||||
import {TestIdBuilder, ThemeProps, themeable} from 'amis-core';
|
||||
import React from 'react';
|
||||
import omit from 'lodash/omit';
|
||||
import isInteger from 'lodash/isInteger';
|
||||
@ -30,6 +30,7 @@ export interface ResultBoxProps
|
||||
showInvalidMatch?: boolean;
|
||||
popOverContainer?: any;
|
||||
showArrow?: boolean;
|
||||
testIdBuilder?: TestIdBuilder;
|
||||
}
|
||||
|
||||
export class ResultBox extends React.Component<ResultBoxProps> {
|
||||
@ -116,7 +117,8 @@ export class ResultBox extends React.Component<ResultBoxProps> {
|
||||
itemRender,
|
||||
classnames: cx,
|
||||
showInvalidMatch,
|
||||
popOverContainer
|
||||
popOverContainer,
|
||||
testIdBuilder
|
||||
} = this.props;
|
||||
|
||||
if (
|
||||
@ -143,6 +145,7 @@ export class ResultBox extends React.Component<ResultBoxProps> {
|
||||
{label: `+ ${tags.length - maxVisibleCount} ...`}
|
||||
].map((item, index) => {
|
||||
const isShowInvalid = showInvalidMatch && item?.__unmatched;
|
||||
const itemTIB = testIdBuilder?.getChild(item.value || index);
|
||||
return index === maxVisibleCount ? (
|
||||
<TooltipWrapper
|
||||
key={tags.length}
|
||||
@ -162,11 +165,16 @@ export class ResultBox extends React.Component<ResultBoxProps> {
|
||||
'is-invalid': showInvalidMatch && item?.__unmatched
|
||||
})}
|
||||
key={itemIndex}
|
||||
{...itemTIB?.getTestId()}
|
||||
>
|
||||
<span className={cx('ResultBox-valueLabel')}>
|
||||
{itemRender(item)}
|
||||
</span>
|
||||
<a data-index={itemIndex} onClick={this.removeItem}>
|
||||
<a
|
||||
data-index={itemIndex}
|
||||
onClick={this.removeItem}
|
||||
{...itemTIB?.getChild('close').getTestId()}
|
||||
>
|
||||
<Icon icon="close" className="icon" />
|
||||
</a>
|
||||
</div>
|
||||
@ -197,11 +205,16 @@ export class ResultBox extends React.Component<ResultBoxProps> {
|
||||
className={cx('ResultBox-value', {
|
||||
'is-invalid': isShowInvalid
|
||||
})}
|
||||
{...itemTIB?.getTestId()}
|
||||
>
|
||||
<span className={cx('ResultBox-valueLabel')}>
|
||||
{itemRender(item)}
|
||||
</span>
|
||||
<a data-index={index} onClick={this.removeItem}>
|
||||
<a
|
||||
data-index={index}
|
||||
onClick={this.removeItem}
|
||||
{...itemTIB?.getChild('close').getTestId()}
|
||||
>
|
||||
<Icon icon="close" className="icon" />
|
||||
</a>
|
||||
</div>
|
||||
@ -210,26 +223,36 @@ export class ResultBox extends React.Component<ResultBoxProps> {
|
||||
});
|
||||
}
|
||||
|
||||
return tags.map((item, index) => (
|
||||
<TooltipWrapper
|
||||
container={popOverContainer}
|
||||
placement={'top'}
|
||||
tooltip={item['label']}
|
||||
trigger={'hover'}
|
||||
key={index}
|
||||
>
|
||||
<div
|
||||
className={cx('ResultBox-value', {
|
||||
'is-invalid': showInvalidMatch && item?.__unmatched
|
||||
})}
|
||||
return tags.map((item, index) => {
|
||||
const itemTIB = testIdBuilder?.getChild(index);
|
||||
return (
|
||||
<TooltipWrapper
|
||||
container={popOverContainer}
|
||||
placement={'top'}
|
||||
tooltip={item['label']}
|
||||
trigger={'hover'}
|
||||
key={index}
|
||||
>
|
||||
<span className={cx('ResultBox-valueLabel')}>{itemRender(item)}</span>
|
||||
<a data-index={index} onClick={this.removeItem}>
|
||||
<Icon icon="close" className="icon" />
|
||||
</a>
|
||||
</div>
|
||||
</TooltipWrapper>
|
||||
));
|
||||
<div
|
||||
className={cx('ResultBox-value', {
|
||||
'is-invalid': showInvalidMatch && item?.__unmatched
|
||||
})}
|
||||
{...itemTIB?.getTestId()}
|
||||
>
|
||||
<span className={cx('ResultBox-valueLabel')}>
|
||||
{itemRender(item)}
|
||||
</span>
|
||||
<a
|
||||
data-index={index}
|
||||
onClick={this.removeItem}
|
||||
{...itemTIB?.getChild('close').getTestId()}
|
||||
>
|
||||
<Icon icon="close" className="icon" />
|
||||
</a>
|
||||
</div>
|
||||
</TooltipWrapper>
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
@ -265,6 +288,7 @@ export class ResultBox extends React.Component<ResultBoxProps> {
|
||||
overflowTagPopover,
|
||||
showArrow,
|
||||
popOverContainer,
|
||||
testIdBuilder,
|
||||
...rest
|
||||
} = this.props;
|
||||
const isFocused = this.state.isFocused;
|
||||
@ -286,6 +310,7 @@ export class ResultBox extends React.Component<ResultBoxProps> {
|
||||
onKeyPress={allowInput ? undefined : onKeyPress}
|
||||
onFocus={allowInput ? undefined : onFocus}
|
||||
onBlur={allowInput ? undefined : onBlur}
|
||||
{...testIdBuilder?.getTestId()}
|
||||
>
|
||||
<div className={cx('ResultBox-value-wrap')}>
|
||||
{Array.isArray(result) && result.length ? (
|
||||
@ -320,6 +345,7 @@ export class ResultBox extends React.Component<ResultBoxProps> {
|
||||
)}
|
||||
onFocus={this.handleFocus}
|
||||
onBlur={this.handleBlur}
|
||||
testIdBuilder={testIdBuilder?.getChild('input')}
|
||||
/>
|
||||
) : null}
|
||||
|
||||
@ -335,6 +361,7 @@ export class ResultBox extends React.Component<ResultBoxProps> {
|
||||
className={cx('ResultBox-clear', {
|
||||
'ResultBox-clear-with-arrow': hasDropDownArrow
|
||||
})}
|
||||
{...testIdBuilder?.getChild('clear').getTestId()}
|
||||
>
|
||||
<div className={cx('ResultBox-clear-wrap')}>
|
||||
<Icon icon="input-clear" className="icon" />
|
||||
|
@ -1060,7 +1060,7 @@ export class Select extends React.Component<SelectProps, SelectState> {
|
||||
}
|
||||
|
||||
let label = labelToString(item[labelField]);
|
||||
let optTestIdBudr = testIdBuilder?.getChild(`option-${index}`);
|
||||
let optTestIdBudr = testIdBuilder?.getChild(`option-${label || index}`);
|
||||
|
||||
return (
|
||||
<div
|
||||
@ -1405,7 +1405,10 @@ export class Select extends React.Component<SelectProps, SelectState> {
|
||||
/>
|
||||
) : null}
|
||||
|
||||
<span className={cx('Select-arrow')}>
|
||||
<span
|
||||
className={cx('Select-arrow')}
|
||||
{...testIdBuilder?.getChild('arrow').getTestId()}
|
||||
>
|
||||
<Icon icon="right-arrow-bold" className="icon" />
|
||||
</span>
|
||||
{isOpen ? this.renderOuter(options) : null}
|
||||
|
@ -1155,8 +1155,8 @@ export class TreeSelector extends React.Component<
|
||||
const disabled = this.isItemDisabled(item, checked);
|
||||
const partial = this.isItemChildrenPartialChecked(item, checked);
|
||||
const checkedInValue = !!~this.state.value.indexOf(item);
|
||||
const itemTestBildr = testIdBuilder?.getChild(
|
||||
`item-${item[labelField] || index}`
|
||||
const itemTestBuilder = testIdBuilder?.getChild(
|
||||
`item-${item[valueField] || item[labelField] || index}`
|
||||
);
|
||||
|
||||
const checkbox: JSX.Element | null = multiple ? (
|
||||
@ -1166,7 +1166,7 @@ export class TreeSelector extends React.Component<
|
||||
checked={checked || partial}
|
||||
partial={partial}
|
||||
onChange={this.handleCheck.bind(this, item, !checked)}
|
||||
{...itemTestBildr?.getChild('chekbx').getTestId()}
|
||||
{...itemTestBuilder?.getChild('chekbx').getTestId()}
|
||||
/>
|
||||
) : showRadio ? (
|
||||
<Checkbox
|
||||
@ -1174,7 +1174,7 @@ export class TreeSelector extends React.Component<
|
||||
disabled={disabled}
|
||||
checked={checked}
|
||||
onChange={this.handleSelect.bind(this, item)}
|
||||
{...itemTestBildr?.getChild('chekbx').getTestId()}
|
||||
{...itemTestBuilder?.getChild('chekbx').getTestId()}
|
||||
/>
|
||||
) : null;
|
||||
|
||||
@ -1192,11 +1192,11 @@ export class TreeSelector extends React.Component<
|
||||
let body = null;
|
||||
|
||||
if (isEditing && editingItem === item) {
|
||||
body = this.renderInput(checkbox, itemTestBildr?.getChild('edit'));
|
||||
body = this.renderInput(checkbox, itemTestBuilder?.getChild('edit'));
|
||||
} else if (item.isAdding) {
|
||||
body = this.renderInput(
|
||||
<span className={cx('Tree-itemArrowPlaceholder')} />,
|
||||
itemTestBildr?.getChild('add')
|
||||
itemTestBuilder?.getChild('add')
|
||||
);
|
||||
} else {
|
||||
const isFolded = !this.isUnfolded(item);
|
||||
@ -1219,7 +1219,7 @@ export class TreeSelector extends React.Component<
|
||||
{draggable && (
|
||||
<a
|
||||
className={cx('Tree-itemDrager drag-bar')}
|
||||
{...itemTestBildr?.getChild('drag-bar').getTestId()}
|
||||
{...itemTestBuilder?.getChild('drag-bar').getTestId()}
|
||||
>
|
||||
<Icon icon="drag-bar" className="icon" />
|
||||
</a>
|
||||
@ -1239,7 +1239,7 @@ export class TreeSelector extends React.Component<
|
||||
className={cx('Tree-itemArrow', {
|
||||
'is-folded': isFolded
|
||||
})}
|
||||
{...itemTestBildr
|
||||
{...itemTestBuilder
|
||||
?.getChild(isFolded ? 'open' : 'fold')
|
||||
.getTestId()}
|
||||
>
|
||||
@ -1253,7 +1253,7 @@ export class TreeSelector extends React.Component<
|
||||
|
||||
<div
|
||||
className={cx('Tree-itemLabel-item', {'is-mobile': mobileUI})}
|
||||
{...itemTestBildr?.getChild('content').getTestId()}
|
||||
{...itemTestBuilder?.getChild('content').getTestId()}
|
||||
>
|
||||
{showIcon ? (
|
||||
<i
|
||||
@ -1292,7 +1292,7 @@ export class TreeSelector extends React.Component<
|
||||
: this.handleSelect(item))
|
||||
}
|
||||
title={item[labelField]}
|
||||
{...itemTestBildr?.getChild('text').getTestId()}
|
||||
{...itemTestBuilder?.getChild('text').getTestId()}
|
||||
>
|
||||
{itemRender
|
||||
? itemRender(item, {
|
||||
@ -1323,7 +1323,7 @@ export class TreeSelector extends React.Component<
|
||||
>
|
||||
<a
|
||||
onClick={this.handleAdd.bind(this, item)}
|
||||
{...itemTestBildr?.getChild('add').getTestId()}
|
||||
{...itemTestBuilder?.getChild('add').getTestId()}
|
||||
>
|
||||
<Icon icon="plus" className="icon" />
|
||||
</a>
|
||||
@ -1339,7 +1339,7 @@ export class TreeSelector extends React.Component<
|
||||
>
|
||||
<a
|
||||
onClick={this.handleRemove.bind(this, item)}
|
||||
{...itemTestBildr?.getChild('remove').getTestId()}
|
||||
{...itemTestBuilder?.getChild('remove').getTestId()}
|
||||
>
|
||||
<Icon icon="minus" className="icon" />
|
||||
</a>
|
||||
@ -1355,7 +1355,7 @@ export class TreeSelector extends React.Component<
|
||||
>
|
||||
<a
|
||||
onClick={this.handleEdit.bind(this, item)}
|
||||
{...itemTestBildr?.getChild('edit').getTestId()}
|
||||
{...itemTestBuilder?.getChild('edit').getTestId()}
|
||||
>
|
||||
<Icon icon="new-edit" className="icon" />
|
||||
</a>
|
||||
@ -1379,7 +1379,7 @@ export class TreeSelector extends React.Component<
|
||||
...style,
|
||||
paddingLeft: `calc(${level} * var(--Tree-indent))`
|
||||
}}
|
||||
{...itemTestBildr?.getTestId()}
|
||||
{...itemTestBuilder?.getTestId()}
|
||||
>
|
||||
{body}
|
||||
</li>
|
||||
|
@ -15,7 +15,7 @@ import {PickerOption} from '../PickerColumn';
|
||||
import 'moment/locale/zh-cn';
|
||||
import 'moment/locale/de';
|
||||
|
||||
import type {RendererEnv} from 'amis-core';
|
||||
import type {RendererEnv, TestIdBuilder} from 'amis-core';
|
||||
import type {unitOfTime} from 'moment';
|
||||
|
||||
/** 视图模式 */
|
||||
@ -132,6 +132,7 @@ interface BaseDatePickerProps {
|
||||
timeConstraints?: any;
|
||||
timeRangeHeader?: string;
|
||||
status?: ChangeEventViewStatus;
|
||||
testIdBuilder?: TestIdBuilder;
|
||||
}
|
||||
|
||||
interface BaseDatePickerState {
|
||||
@ -456,7 +457,8 @@ class BaseDatePicker extends React.Component<
|
||||
'mobileUI',
|
||||
'showToolbar',
|
||||
'embed',
|
||||
'env'
|
||||
'env',
|
||||
'testIdBuilder'
|
||||
].forEach(key => (props[key] = (this.props as any)[key]));
|
||||
|
||||
return props;
|
||||
@ -721,8 +723,14 @@ class BaseDatePicker extends React.Component<
|
||||
}
|
||||
|
||||
render() {
|
||||
const {viewMode, timeFormat, dateFormat, timeRangeHeader, mobileUI} =
|
||||
this.props;
|
||||
const {
|
||||
viewMode,
|
||||
timeFormat,
|
||||
dateFormat,
|
||||
timeRangeHeader,
|
||||
mobileUI,
|
||||
testIdBuilder
|
||||
} = this.props;
|
||||
const Component = CustomCalendarContainer as any;
|
||||
const viewProps = this.getComponentProps();
|
||||
|
||||
@ -757,6 +765,7 @@ class BaseDatePicker extends React.Component<
|
||||
? 'rdtTime'
|
||||
: ''
|
||||
)}
|
||||
{...testIdBuilder?.getTestId()}
|
||||
>
|
||||
<div
|
||||
key="dt"
|
||||
|
@ -15,7 +15,7 @@ import {
|
||||
ClassNamesFn,
|
||||
convertArrayValueToMoment
|
||||
} from 'amis-core';
|
||||
import type {RendererEnv} from 'amis-core';
|
||||
import type {RendererEnv, TestIdBuilder} from 'amis-core';
|
||||
import Picker from '../Picker';
|
||||
import {PickerOption} from '../PickerColumn';
|
||||
import {DateType} from './Calendar';
|
||||
@ -89,6 +89,7 @@ interface CustomDaysViewProps extends LocaleProps {
|
||||
getColumns: (types: DateType[], dateBoundary: void) => any;
|
||||
getDateBoundary: (currentDate: moment.Moment) => any;
|
||||
timeConstraints?: any;
|
||||
testIdBuilder?: TestIdBuilder;
|
||||
}
|
||||
|
||||
export class CustomDaysView extends React.Component<CustomDaysViewProps> {
|
||||
@ -422,7 +423,7 @@ export class CustomDaysView extends React.Component<CustomDaysViewProps> {
|
||||
|
||||
renderDay = (props: any, currentDate: moment.Moment) => {
|
||||
const {todayActiveStyle} = props; /** 只有today才会传入这个属性 */
|
||||
const {classnames: cx, translate: __, env} = this.props;
|
||||
const {classnames: cx, translate: __, testIdBuilder} = this.props;
|
||||
const injectedProps = omit(props, ['todayActiveStyle']);
|
||||
/** 某些情况下需要用inline style覆盖动态class,需要hack important的样式 */
|
||||
const todayDomRef = (node: HTMLSpanElement | null) => {
|
||||
@ -611,7 +612,11 @@ export class CustomDaysView extends React.Component<CustomDaysViewProps> {
|
||||
|
||||
return (
|
||||
<td {...injectedProps}>
|
||||
<span style={todayActiveStyle} ref={todayDomRef}>
|
||||
<span
|
||||
style={todayActiveStyle}
|
||||
ref={todayDomRef}
|
||||
{...testIdBuilder?.getChild(props.key)?.getTestId()}
|
||||
>
|
||||
{currentDate.date()}
|
||||
</span>
|
||||
</td>
|
||||
@ -637,7 +642,8 @@ export class CustomDaysView extends React.Component<CustomDaysViewProps> {
|
||||
selectedDate,
|
||||
viewDate,
|
||||
isEndDate,
|
||||
classnames: cx
|
||||
classnames: cx,
|
||||
testIdBuilder
|
||||
} = this.props;
|
||||
|
||||
const date = selectedDate || (isEndDate ? viewDate.endOf('day') : viewDate);
|
||||
@ -685,6 +691,7 @@ export class CustomDaysView extends React.Component<CustomDaysViewProps> {
|
||||
)
|
||||
)
|
||||
});
|
||||
const itemTIB = testIdBuilder?.getChild(type);
|
||||
return (
|
||||
<div
|
||||
className={cx(
|
||||
@ -718,6 +725,7 @@ export class CustomDaysView extends React.Component<CustomDaysViewProps> {
|
||||
? option.value === date.format(formatMap[type])
|
||||
: option.value === options?.[0]?.value
|
||||
})}
|
||||
{...itemTIB?.getChild(option.value)?.getTestId()}
|
||||
onClick={() => {
|
||||
this.setTime(type, parseInt(option.value, 10));
|
||||
this.scrollToTop(
|
||||
@ -834,7 +842,8 @@ export class CustomDaysView extends React.Component<CustomDaysViewProps> {
|
||||
mobileUI,
|
||||
embed,
|
||||
timeFormat,
|
||||
classnames: cx
|
||||
classnames: cx,
|
||||
testIdBuilder
|
||||
} = this.props;
|
||||
const locale = date.localeData();
|
||||
const __ = this.props.translate;
|
||||
@ -851,6 +860,7 @@ export class CustomDaysView extends React.Component<CustomDaysViewProps> {
|
||||
<a
|
||||
className="rdtPrev"
|
||||
onClick={this.props.subtractTime(1, 'years')}
|
||||
{...testIdBuilder?.getChild('prev-year').getTestId()}
|
||||
>
|
||||
<Icon
|
||||
icon="right-double-arrow"
|
||||
@ -860,6 +870,7 @@ export class CustomDaysView extends React.Component<CustomDaysViewProps> {
|
||||
<a
|
||||
className="rdtPrev"
|
||||
onClick={this.props.subtractTime(1, 'months')}
|
||||
{...testIdBuilder?.getChild('prev-month').getTestId()}
|
||||
>
|
||||
<Icon
|
||||
icon="right-arrow"
|
||||
@ -871,12 +882,14 @@ export class CustomDaysView extends React.Component<CustomDaysViewProps> {
|
||||
<a
|
||||
className="rdtSwitch"
|
||||
onClick={this.props.showView('years')}
|
||||
{...testIdBuilder?.getChild('switch-years').getTestId()}
|
||||
>
|
||||
{date.format(__('dateformat.year'))}
|
||||
</a>
|
||||
<a
|
||||
className="rdtSwitch"
|
||||
onClick={this.props.showView('months')}
|
||||
{...testIdBuilder?.getChild('switch-months').getTestId()}
|
||||
>
|
||||
{date.format(__('MMM'))}
|
||||
</a>
|
||||
@ -885,10 +898,15 @@ export class CustomDaysView extends React.Component<CustomDaysViewProps> {
|
||||
<a
|
||||
className="rdtNext"
|
||||
onClick={this.props.addTime(1, 'months')}
|
||||
{...testIdBuilder?.getChild('next-month').getTestId()}
|
||||
>
|
||||
<Icon icon="right-arrow" className="icon date-icon-arrow" />
|
||||
</a>
|
||||
<a className="rdtNext" onClick={this.props.addTime(1, 'years')}>
|
||||
<a
|
||||
className="rdtNext"
|
||||
onClick={this.props.addTime(1, 'years')}
|
||||
{...testIdBuilder?.getChild('next-year').getTestId()}
|
||||
>
|
||||
<Icon
|
||||
icon="right-double-arrow"
|
||||
className="icon date-icon-arrow"
|
||||
|
@ -4,6 +4,7 @@ import {LocaleProps, localeable, getRange} from 'amis-core';
|
||||
import Picker from '../Picker';
|
||||
import {PickerOption} from '../PickerColumn';
|
||||
import {DateType} from './Calendar';
|
||||
import type {TestIdBuilder} from 'amis-core';
|
||||
|
||||
export interface OtherProps {
|
||||
inputFormat?: string;
|
||||
@ -47,6 +48,7 @@ export interface CustomMonthsViewProps extends LocaleProps {
|
||||
timeCell: (value: number, type: DateType) => string;
|
||||
getDateBoundary: (currentDate: moment.Moment) => any;
|
||||
mobileUI: boolean;
|
||||
testIdBuilder?: TestIdBuilder;
|
||||
}
|
||||
|
||||
export class CustomMonthsView extends React.Component<CustomMonthsViewProps> {
|
||||
@ -71,6 +73,7 @@ export class CustomMonthsView extends React.Component<CustomMonthsViewProps> {
|
||||
}
|
||||
|
||||
renderMonths() {
|
||||
const {testIdBuilder} = this.props;
|
||||
let date = this.props.selectedDate,
|
||||
month = this.props.viewDate.month(),
|
||||
year = this.props.viewDate.year(),
|
||||
@ -159,7 +162,7 @@ export class CustomMonthsView extends React.Component<CustomMonthsViewProps> {
|
||||
year: number,
|
||||
date: moment.Moment
|
||||
) => {
|
||||
const {translate: __} = this.props;
|
||||
const {translate: __, testIdBuilder} = this.props;
|
||||
const {viewDate: localMoment, ...rest} = props;
|
||||
const monthStr = localMoment.month(month).format(__('MMM'));
|
||||
const strLength = 3;
|
||||
@ -169,7 +172,9 @@ export class CustomMonthsView extends React.Component<CustomMonthsViewProps> {
|
||||
|
||||
return (
|
||||
<td {...rest}>
|
||||
<span>{monthStrFixedLength}</span>
|
||||
<span {...testIdBuilder?.getChild(props.key).getTestId()}>
|
||||
{monthStrFixedLength}
|
||||
</span>
|
||||
</td>
|
||||
);
|
||||
};
|
||||
@ -248,6 +253,7 @@ export class CustomMonthsView extends React.Component<CustomMonthsViewProps> {
|
||||
|
||||
render() {
|
||||
const __ = this.props.translate;
|
||||
const {testIdBuilder} = this.props;
|
||||
const showYearHead =
|
||||
!/^mm$/i.test(this.props.inputFormat || '') && !this.props.hideHeader;
|
||||
const canClick = /yy/i.test(this.props.inputFormat || '');
|
||||
@ -264,6 +270,7 @@ export class CustomMonthsView extends React.Component<CustomMonthsViewProps> {
|
||||
<th
|
||||
className="rdtPrev"
|
||||
onClick={this.props.subtractTime(1, 'years')}
|
||||
{...testIdBuilder?.getChild('prev-year').getTestId()}
|
||||
>
|
||||
«
|
||||
</th>
|
||||
@ -271,6 +278,7 @@ export class CustomMonthsView extends React.Component<CustomMonthsViewProps> {
|
||||
<th
|
||||
className="rdtSwitch"
|
||||
onClick={this.props.showView('years')}
|
||||
{...testIdBuilder?.getChild('switch-year').getTestId()}
|
||||
>
|
||||
{this.props.viewDate.format(__('dateformat.year'))}
|
||||
</th>
|
||||
@ -283,6 +291,7 @@ export class CustomMonthsView extends React.Component<CustomMonthsViewProps> {
|
||||
<th
|
||||
className="rdtNext"
|
||||
onClick={this.props.addTime(1, 'years')}
|
||||
{...testIdBuilder?.getChild('next-year').getTestId()}
|
||||
>
|
||||
»
|
||||
</th>
|
||||
|
@ -5,6 +5,7 @@ import Picker from '../Picker';
|
||||
import {PickerColumnItem} from '../PickerColumn';
|
||||
import {getRange} from 'amis-core';
|
||||
import {autobind} from 'amis-core';
|
||||
import type {TestIdBuilder} from 'amis-core';
|
||||
|
||||
export interface QuarterViewProps extends LocaleProps, ThemeProps {
|
||||
viewDate: moment.Moment;
|
||||
@ -29,6 +30,7 @@ export interface QuarterViewProps extends LocaleProps, ThemeProps {
|
||||
hideHeader?: boolean;
|
||||
onConfirm?: (value: number[], types?: string[]) => void;
|
||||
onClose?: () => void;
|
||||
testIdBuilder?: TestIdBuilder;
|
||||
}
|
||||
|
||||
export class QuarterView extends React.Component<QuarterViewProps> {
|
||||
@ -38,7 +40,7 @@ export class QuarterView extends React.Component<QuarterViewProps> {
|
||||
};
|
||||
|
||||
renderYear() {
|
||||
const __ = this.props.translate;
|
||||
const {translate: __, testIdBuilder} = this.props;
|
||||
const showYearHead = !/^mm$/i.test(this.props.inputFormat || '');
|
||||
|
||||
if (!showYearHead) {
|
||||
@ -54,11 +56,16 @@ export class QuarterView extends React.Component<QuarterViewProps> {
|
||||
<th
|
||||
className="rdtPrev"
|
||||
onClick={this.props.subtractTime(1, 'years')}
|
||||
{...testIdBuilder?.getChild('prev-year').getTestId()}
|
||||
>
|
||||
«
|
||||
</th>
|
||||
{canClick ? (
|
||||
<th className="rdtSwitch" onClick={this.props.showView('years')}>
|
||||
<th
|
||||
className="rdtSwitch"
|
||||
onClick={this.props.showView('years')}
|
||||
{...testIdBuilder?.getChild('switch-year').getTestId()}
|
||||
>
|
||||
{this.props.viewDate.format(__('dateformat.year'))}
|
||||
</th>
|
||||
) : (
|
||||
@ -67,7 +74,11 @@ export class QuarterView extends React.Component<QuarterViewProps> {
|
||||
</th>
|
||||
)}
|
||||
|
||||
<th className="rdtNext" onClick={this.props.addTime(1, 'years')}>
|
||||
<th
|
||||
className="rdtNext"
|
||||
onClick={this.props.addTime(1, 'years')}
|
||||
{...testIdBuilder?.getChild('next-year').getTestId()}
|
||||
>
|
||||
»
|
||||
</th>
|
||||
</tr>
|
||||
@ -135,9 +146,12 @@ export class QuarterView extends React.Component<QuarterViewProps> {
|
||||
year: number,
|
||||
date: moment.Moment
|
||||
) => {
|
||||
const {testIdBuilder} = this.props;
|
||||
return (
|
||||
<td {...props}>
|
||||
<span>Q{quartar}</span>
|
||||
<span {...testIdBuilder?.getChild(props.key).getTestId()}>
|
||||
Q{quartar}
|
||||
</span>
|
||||
</td>
|
||||
);
|
||||
};
|
||||
|
@ -14,6 +14,7 @@ import {PickerColumnItem} from '../PickerColumn';
|
||||
import Downshift from 'downshift';
|
||||
|
||||
import type {Moment} from 'moment';
|
||||
import type {TestIdBuilder} from 'amis-core';
|
||||
|
||||
interface CustomTimeViewProps extends LocaleProps {
|
||||
viewDate: moment.Moment;
|
||||
@ -52,6 +53,7 @@ interface CustomTimeViewProps extends LocaleProps {
|
||||
onChange: (value: moment.Moment) => void;
|
||||
timeConstraints?: any;
|
||||
timeRangeHeader?: string;
|
||||
testIdBuilder?: TestIdBuilder;
|
||||
}
|
||||
|
||||
interface CustomTimeViewState {
|
||||
@ -689,7 +691,8 @@ export class CustomTimeView extends React.Component<
|
||||
isEndDate,
|
||||
classnames: cx,
|
||||
timeRangeHeader,
|
||||
mobileUI
|
||||
mobileUI,
|
||||
testIdBuilder
|
||||
} = this.props;
|
||||
|
||||
const __ = this.props.translate;
|
||||
@ -745,6 +748,7 @@ export class CustomTimeView extends React.Component<
|
||||
)
|
||||
)
|
||||
});
|
||||
const itemTIB = testIdBuilder?.getChild(type);
|
||||
return (
|
||||
<div className={cx('CalendarInputWrapper')}>
|
||||
<div
|
||||
@ -767,6 +771,7 @@ export class CustomTimeView extends React.Component<
|
||||
: option.value === options?.[0]?.value &&
|
||||
!mobileUI
|
||||
})}
|
||||
{...itemTIB?.getChild(option.value).getTestId()}
|
||||
onClick={() => {
|
||||
this.setTime(type, parseInt(option.value, 10));
|
||||
this.scrollToTop(
|
||||
@ -793,7 +798,11 @@ export class CustomTimeView extends React.Component<
|
||||
inputs.length && inputs.pop();
|
||||
|
||||
const quickLists = [
|
||||
<a key="select-now" onClick={this.selectNowTime}>
|
||||
<a
|
||||
key="select-now"
|
||||
onClick={this.selectNowTime}
|
||||
{...testIdBuilder?.getChild('select-now').getTestId()}
|
||||
>
|
||||
{__('TimeNow')}
|
||||
</a>
|
||||
];
|
||||
@ -809,6 +818,7 @@ export class CustomTimeView extends React.Component<
|
||||
<a
|
||||
className={cx('Button', 'Button--primary', 'Button--size-sm')}
|
||||
onClick={this.confirm}
|
||||
{...testIdBuilder?.getChild('confirm').getTestId()}
|
||||
>
|
||||
{__('confirm')}
|
||||
</a>
|
||||
|
@ -2,6 +2,7 @@ import moment from 'moment';
|
||||
import React from 'react';
|
||||
import {LocaleProps, localeable, utils, getRange} from 'amis-core';
|
||||
import Picker from '../Picker';
|
||||
import type {TestIdBuilder} from 'amis-core';
|
||||
|
||||
interface CustomYearsViewProps extends LocaleProps {
|
||||
viewDate: moment.Moment;
|
||||
@ -31,6 +32,7 @@ interface CustomYearsViewProps extends LocaleProps {
|
||||
currentDate: moment.Moment,
|
||||
selected?: moment.Moment
|
||||
) => boolean;
|
||||
testIdBuilder?: TestIdBuilder;
|
||||
}
|
||||
|
||||
export class CustomYearsView extends React.Component<CustomYearsViewProps> {
|
||||
@ -124,9 +126,10 @@ export class CustomYearsView extends React.Component<CustomYearsViewProps> {
|
||||
}
|
||||
|
||||
renderYear = (props: any, year: number, date?: moment.Moment) => {
|
||||
const {testIdBuilder} = this.props;
|
||||
return (
|
||||
<td {...props}>
|
||||
<span>{year}</span>
|
||||
<span {...testIdBuilder?.getChild(props.key).getTestId()}>{year}</span>
|
||||
</td>
|
||||
);
|
||||
};
|
||||
@ -179,7 +182,7 @@ export class CustomYearsView extends React.Component<CustomYearsViewProps> {
|
||||
render() {
|
||||
let year = this.props.viewDate.year();
|
||||
year = year - (year % 10);
|
||||
const __ = this.props.translate;
|
||||
const {testIdBuilder, translate: __} = this.props;
|
||||
if (this.props.mobileUI) {
|
||||
return <div className="rdtYears">{this.renderYearPicker()}</div>;
|
||||
}
|
||||
@ -191,13 +194,18 @@ export class CustomYearsView extends React.Component<CustomYearsViewProps> {
|
||||
<th
|
||||
className="rdtPrev"
|
||||
onClick={this.props.subtractTime(10, 'years')}
|
||||
{...testIdBuilder?.getChild('prev-year').getTestId()}
|
||||
>
|
||||
«
|
||||
</th>
|
||||
<th className="rdtSwitch">
|
||||
{__('year-to-year', {from: year, to: year + 9})}
|
||||
</th>
|
||||
<th className="rdtNext" onClick={this.props.addTime(10, 'years')}>
|
||||
<th
|
||||
className="rdtNext"
|
||||
onClick={this.props.addTime(10, 'years')}
|
||||
{...testIdBuilder?.getChild('next-year').getTestId()}
|
||||
>
|
||||
»
|
||||
</th>
|
||||
</tr>
|
||||
|
@ -186,7 +186,11 @@ export class SubMenu extends React.Component<SubMenuProps> {
|
||||
{labelNode}
|
||||
{labelExtra}
|
||||
{!stacked && depth === 1 ? (
|
||||
<span key="expand-toggle" className={cx('Nav-Menu-submenu-arrow')}>
|
||||
<span
|
||||
key="expand-toggle"
|
||||
className={cx('Nav-Menu-submenu-arrow')}
|
||||
{...testIdBuilder?.getChild('expand-toggle').getTestId()}
|
||||
>
|
||||
<Icon icon="right-arrow-bold" className="icon" />
|
||||
</span>
|
||||
) : null}
|
||||
|
@ -543,8 +543,9 @@ export class Menu extends React.Component<MenuProps, MenuState> {
|
||||
disabled?: boolean;
|
||||
[propName: string]: any;
|
||||
}) {
|
||||
const {classnames: cx, expandIcon} = this.props;
|
||||
|
||||
const navigations = this.state.navigations;
|
||||
const {classnames: cx, expandIcon, testIdBuilder} = this.props;
|
||||
const link = findTree(navigations, item => item.id === ctx.eventKey);
|
||||
return (
|
||||
<span
|
||||
key="expand-toggle"
|
||||
@ -553,6 +554,10 @@ export class Menu extends React.Component<MenuProps, MenuState> {
|
||||
this.handleToggleExpand(ctx);
|
||||
e.preventDefault();
|
||||
}}
|
||||
{...testIdBuilder
|
||||
?.getChild(link?.link?.testid || ctx.eventKey)
|
||||
.getChild('expand-toggle')
|
||||
.getTestId()}
|
||||
>
|
||||
{!React.isValidElement(expandIcon) ? (
|
||||
<Icon
|
||||
@ -617,9 +622,7 @@ export class Menu extends React.Component<MenuProps, MenuState> {
|
||||
badge={badge}
|
||||
renderLink={renderLink}
|
||||
depth={level || 1}
|
||||
testIdBuilder={testIdBuilder?.getChild(
|
||||
link.testid || index.toString()
|
||||
)}
|
||||
testIdBuilder={testIdBuilder?.getChild(link.testid || index)}
|
||||
popupClassName={popupClassName}
|
||||
>
|
||||
{this.renderMenuContent(item.children || [], item.depth + 1)}
|
||||
@ -641,9 +644,7 @@ export class Menu extends React.Component<MenuProps, MenuState> {
|
||||
renderLink={renderLink}
|
||||
badge={badge}
|
||||
data={data}
|
||||
testIdBuilder={testIdBuilder?.getChild(
|
||||
link.testid || index.toString()
|
||||
)}
|
||||
testIdBuilder={testIdBuilder?.getChild(link.testid || index)}
|
||||
depth={level || 1}
|
||||
order={index}
|
||||
overflowedIndicator={overflowedIndicator}
|
||||
|
@ -129,7 +129,7 @@ import {
|
||||
SchemaClassName,
|
||||
SchemaExpression
|
||||
} from 'amis-core';
|
||||
import type {FormSchemaBase} from 'amis-core';
|
||||
import type {FormSchemaBase, TestIdBuilder} from 'amis-core';
|
||||
import {MultilineTextSchema} from './renderers/MultilineText';
|
||||
import {DateRangeSchema} from './renderers/DateRange';
|
||||
import {PasswordSchema} from './renderers/Password';
|
||||
|
@ -7,6 +7,7 @@ import {BaseSchema, SchemaIcon, SchemaUrlPath} from '../Schema';
|
||||
import {filter} from 'amis-core';
|
||||
import {resolveVariableAndFilter} from 'amis-core';
|
||||
import {Breadcrumb} from 'amis-ui';
|
||||
import type {TestIdBuilder} from 'amis-core';
|
||||
|
||||
export type BreadcrumbBaseItemSchema = {
|
||||
/**
|
||||
@ -101,6 +102,8 @@ export interface BreadcrumbSchema extends BaseSchema {
|
||||
* 浮窗提示位置
|
||||
*/
|
||||
tooltipPosition?: TooltipPositionType;
|
||||
|
||||
testIdBuilder?: TestIdBuilder;
|
||||
}
|
||||
|
||||
export interface BreadcrumbProps
|
||||
|
@ -2026,7 +2026,7 @@ export default class CRUD extends React.Component<CRUDProps, any> {
|
||||
'pagination',
|
||||
{
|
||||
type: 'pagination',
|
||||
testIdBuilder: testIdBuilder.getChild('pagination')
|
||||
testIdBuilder: testIdBuilder?.getChild('pagination')
|
||||
},
|
||||
{
|
||||
...extraProps,
|
||||
@ -2105,7 +2105,7 @@ export default class CRUD extends React.Component<CRUDProps, any> {
|
||||
onChange={(value: any) => this.handleChangePage(1, value.value)}
|
||||
clearable={false}
|
||||
popOverContainer={this.parentContainer}
|
||||
testIdBuilder={testIdBuilder.getChild('perPage')}
|
||||
testIdBuilder={testIdBuilder?.getChild('perPage')}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
@ -2131,7 +2131,7 @@ export default class CRUD extends React.Component<CRUDProps, any> {
|
||||
this.search({page: page + 1, loadDataMode: 'load-more'})
|
||||
}
|
||||
size="sm"
|
||||
{...testIdBuilder.getChild('loadMore').getTestId()}
|
||||
{...testIdBuilder?.getChild('loadMore').getTestId()}
|
||||
>
|
||||
{__('CRUD.loadMore')}
|
||||
</Button>
|
||||
@ -2258,7 +2258,7 @@ export default class CRUD extends React.Component<CRUDProps, any> {
|
||||
<div
|
||||
className={cx('Crud-toolbar')}
|
||||
key={index}
|
||||
{...testIdBuilder.getChild('toolbar').getTestId()}
|
||||
{...testIdBuilder?.getChild('toolbar').getTestId()}
|
||||
>
|
||||
{children.map(({toolbar, dom: child}, index) => {
|
||||
const type = (toolbar as Schema).type || toolbar;
|
||||
@ -2537,7 +2537,7 @@ export default class CRUD extends React.Component<CRUDProps, any> {
|
||||
'is-mobile': isMobile()
|
||||
})}
|
||||
style={style}
|
||||
{...testIdBuilder.getChild('wrapper').getTestId()}
|
||||
{...testIdBuilder?.getChild('wrapper').getTestId()}
|
||||
>
|
||||
{filter && (!store.filterTogggable || store.filterVisible)
|
||||
? render(
|
||||
@ -2549,7 +2549,7 @@ export default class CRUD extends React.Component<CRUDProps, any> {
|
||||
...filter,
|
||||
type: 'form',
|
||||
api: null,
|
||||
testIdBuilder: testIdBuilder.getChild('filter')
|
||||
testIdBuilder: testIdBuilder?.getChild('filter')
|
||||
},
|
||||
{
|
||||
key: 'filter',
|
||||
|
@ -240,7 +240,7 @@ export default class Dialog extends React.Component<DialogProps> {
|
||||
let ret: Array<ActionSchema> = [];
|
||||
ret.push({
|
||||
type: 'button',
|
||||
testIdBuilder: testIdBuilder.getChild('cancel'),
|
||||
testIdBuilder: testIdBuilder?.getChild('cancel'),
|
||||
actionType: 'cancel',
|
||||
label: __('cancel')
|
||||
});
|
||||
@ -248,7 +248,7 @@ export default class Dialog extends React.Component<DialogProps> {
|
||||
if (confirm) {
|
||||
ret.push({
|
||||
type: 'button',
|
||||
testIdBuilder: testIdBuilder.getChild('confirm'),
|
||||
testIdBuilder: testIdBuilder?.getChild('confirm'),
|
||||
actionType: 'confirm',
|
||||
label: __('confirm'),
|
||||
primary: true
|
||||
|
@ -266,7 +266,7 @@ export default class Drawer extends React.Component<DrawerProps> {
|
||||
let ret: Array<ActionSchema> = [];
|
||||
ret.push({
|
||||
type: 'button',
|
||||
testIdBuilder: testIdBuilder.getChild('cancel'),
|
||||
testIdBuilder: testIdBuilder?.getChild('cancel'),
|
||||
actionType: 'close',
|
||||
label: __('cancel')
|
||||
});
|
||||
@ -275,7 +275,7 @@ export default class Drawer extends React.Component<DrawerProps> {
|
||||
ret.push({
|
||||
type: 'button',
|
||||
actionType: 'confirm',
|
||||
testIdBuilder: testIdBuilder.getChild('confirm'),
|
||||
testIdBuilder: testIdBuilder?.getChild('confirm'),
|
||||
label: __('confirm'),
|
||||
primary: true
|
||||
});
|
||||
|
@ -305,7 +305,10 @@ export default class DropDownButton extends React.Component<
|
||||
...(button as any),
|
||||
className: '',
|
||||
// 防止dropdown中button没有 testid或者id
|
||||
testIdBuilder: testIdBuilder.getChild(button.label || index, data)
|
||||
testIdBuilder: testIdBuilder?.getChild(
|
||||
button.label || index,
|
||||
data
|
||||
)
|
||||
},
|
||||
{
|
||||
isMenuItem: true,
|
||||
@ -443,7 +446,6 @@ export default class DropDownButton extends React.Component<
|
||||
className
|
||||
)}
|
||||
style={style}
|
||||
{...testIdBuilder.getTestId(data)}
|
||||
onMouseEnter={trigger === 'hover' ? this.open : () => {}}
|
||||
onMouseLeave={trigger === 'hover' ? this.close : () => {}}
|
||||
ref={this.domRef}
|
||||
@ -458,6 +460,7 @@ export default class DropDownButton extends React.Component<
|
||||
<button
|
||||
onClick={this.toogle}
|
||||
disabled={disabled || btnDisabled}
|
||||
{...testIdBuilder?.getTestId(data)}
|
||||
className={cx(
|
||||
'Button',
|
||||
btnClassName,
|
||||
|
@ -4,7 +4,7 @@ import {
|
||||
OptionsControlProps,
|
||||
FormOptionsControl
|
||||
} from 'amis-core';
|
||||
import type {Option} from 'amis-core';
|
||||
import {Option, TestIdBuilder} from 'amis-core';
|
||||
import {ActionObject, isObject} from 'amis-core';
|
||||
import type {BadgeObject} from 'amis-ui';
|
||||
import {getLevelFromClassName, autobind, isEmpty} from 'amis-core';
|
||||
@ -34,6 +34,7 @@ export interface ButtonGroupProps
|
||||
| 'btnClassName'
|
||||
> {
|
||||
options: Array<Option>;
|
||||
testIdBuilder: TestIdBuilder;
|
||||
}
|
||||
|
||||
export default class ButtonGroupControl extends React.Component<
|
||||
@ -102,6 +103,7 @@ export default class ButtonGroupControl extends React.Component<
|
||||
vertical,
|
||||
tiled,
|
||||
badge,
|
||||
testIdBuilder,
|
||||
translate: __
|
||||
} = props;
|
||||
|
||||
@ -137,6 +139,9 @@ export default class ButtonGroupControl extends React.Component<
|
||||
active && 'ButtonGroup-button--active'
|
||||
),
|
||||
disabled: option.disabled || disabled,
|
||||
testIdBuilder: testIdBuilder?.getChild(
|
||||
`item-${option[labelField || 'label'] || key}`
|
||||
),
|
||||
onClick: (e: React.UIEvent<any>) => {
|
||||
if (disabled) {
|
||||
return;
|
||||
|
@ -319,6 +319,7 @@ export default class ChainedSelectControl extends React.Component<
|
||||
multiple,
|
||||
mobileUI,
|
||||
env,
|
||||
testIdBuilder,
|
||||
...rest
|
||||
} = this.props;
|
||||
const arr = Array.isArray(value)
|
||||
@ -341,6 +342,7 @@ export default class ChainedSelectControl extends React.Component<
|
||||
}
|
||||
classPrefix={ns}
|
||||
key="base"
|
||||
testIdBuilder={testIdBuilder?.getChild('base')}
|
||||
options={Array.isArray(options) ? options : []}
|
||||
value={arr[0]}
|
||||
onChange={this.handleChange.bind(this, 0)}
|
||||
@ -361,6 +363,7 @@ export default class ChainedSelectControl extends React.Component<
|
||||
}
|
||||
classPrefix={ns}
|
||||
key={`x-${index + 1}`}
|
||||
testIdBuilder={testIdBuilder?.getChild(`x-${index + 1}`)}
|
||||
options={Array.isArray(options) ? options : []}
|
||||
value={arr[index + 1]}
|
||||
onChange={this.handleChange.bind(this, index + 1)}
|
||||
|
@ -12,6 +12,7 @@ import {autobind, createObject} from 'amis-core';
|
||||
import {ActionObject} from 'amis-core';
|
||||
import {BaseSchema, FormBaseControlSchema} from '../../Schema';
|
||||
import {supportStatic} from './StaticHoc';
|
||||
import type {TestIdBuilder} from 'amis-core';
|
||||
|
||||
export interface SchemaMap {
|
||||
checkbox: CheckboxControlSchema;
|
||||
@ -49,6 +50,7 @@ export interface CheckboxControlSchema extends FormBaseControlSchema {
|
||||
partial?: boolean;
|
||||
optionType?: 'default' | 'button';
|
||||
checked?: boolean;
|
||||
testIdBuilder?: TestIdBuilder;
|
||||
}
|
||||
|
||||
export interface CheckboxProps
|
||||
@ -139,6 +141,7 @@ export default class CheckboxControl extends React.Component<
|
||||
optionType,
|
||||
checked,
|
||||
labelClassName,
|
||||
testIdBuilder,
|
||||
classPrefix: ns
|
||||
} = this.props;
|
||||
|
||||
@ -155,6 +158,7 @@ export default class CheckboxControl extends React.Component<
|
||||
optionType={optionType}
|
||||
checked={checked}
|
||||
labelClassName={labelClassName}
|
||||
testIdBuilder={testIdBuilder}
|
||||
>
|
||||
{option ? render('option', option) : null}
|
||||
</Checkbox>
|
||||
|
@ -12,6 +12,7 @@ import type {ActionObject, Api, OptionsControlProps, Option} from 'amis-core';
|
||||
import {Checkbox, Icon, Spinner} from 'amis-ui';
|
||||
import {FormOptionsSchema} from '../../Schema';
|
||||
import {supportStatic} from './StaticHoc';
|
||||
import type {TestIdBuilder} from 'amis-core';
|
||||
|
||||
/**
|
||||
* 复选框
|
||||
@ -43,6 +44,7 @@ export interface CheckboxesControlSchema extends FormOptionsSchema {
|
||||
* 自定义选项展示
|
||||
*/
|
||||
menuTpl?: string;
|
||||
testIdBuilder?: TestIdBuilder;
|
||||
}
|
||||
|
||||
export interface CheckboxesProps
|
||||
@ -258,10 +260,14 @@ export default class CheckboxesControl extends React.Component<
|
||||
translate: __,
|
||||
optionType,
|
||||
menuTpl,
|
||||
data
|
||||
data,
|
||||
testIdBuilder
|
||||
} = this.props;
|
||||
const labelText = String(option[labelField || 'label']);
|
||||
const optionLabelClassName = option['labelClassName'];
|
||||
const itemTestIdBuilder = testIdBuilder?.getChild(
|
||||
'item-' + labelText || index
|
||||
);
|
||||
|
||||
return (
|
||||
<Checkbox
|
||||
@ -274,6 +280,7 @@ export default class CheckboxesControl extends React.Component<
|
||||
labelClassName={optionLabelClassName || labelClassName}
|
||||
description={option.description}
|
||||
optionType={optionType}
|
||||
testIdBuilder={itemTestIdBuilder}
|
||||
>
|
||||
{menuTpl
|
||||
? render(`checkboxes/${index}`, menuTpl, {
|
||||
|
@ -1,6 +1,8 @@
|
||||
import React from 'react';
|
||||
import {findDOMNode} from 'react-dom';
|
||||
import cloneDeep from 'lodash/cloneDeep';
|
||||
import isNumber from 'lodash/isNumber';
|
||||
import get from 'lodash/get';
|
||||
import {
|
||||
FormItem,
|
||||
FormControlProps,
|
||||
@ -57,6 +59,8 @@ import type {SchemaTokenizeableString} from '../../Schema';
|
||||
import isPlainObject from 'lodash/isPlainObject';
|
||||
import isEqual from 'lodash/isEqual';
|
||||
|
||||
import type {TestIdBuilder} from 'amis-core';
|
||||
|
||||
export type ComboCondition = {
|
||||
test: string;
|
||||
items: Array<ComboSubControl>;
|
||||
@ -75,6 +79,7 @@ export type ComboSubControl = SchemaObject & {
|
||||
* 列类名,可以用来修改这类宽度。
|
||||
*/
|
||||
columnClassName?: SchemaClassName;
|
||||
testid?: string;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -283,6 +288,7 @@ export interface ComboControlSchema extends FormBaseControlSchema {
|
||||
maxLengthValidateFailed?: string;
|
||||
};
|
||||
updatePristineAfterStoreDataReInit?: boolean;
|
||||
testIdBuilder?: TestIdBuilder;
|
||||
}
|
||||
|
||||
export type ComboRendererEvent = 'add' | 'delete' | 'tabsChange';
|
||||
@ -1390,9 +1396,10 @@ export default class ComboControl extends React.Component<ComboProps> {
|
||||
removable,
|
||||
deleteBtn,
|
||||
mobileUI,
|
||||
data
|
||||
data,
|
||||
testIdBuilder
|
||||
} = this.props;
|
||||
|
||||
const delTestIdBuilder = testIdBuilder?.getChild(`delete-btn-${index}`);
|
||||
const finnalRemovable =
|
||||
store.removable !== false && // minLength ?
|
||||
!disabled && // 控件自身是否禁用
|
||||
@ -1419,6 +1426,7 @@ export default class ComboControl extends React.Component<ComboProps> {
|
||||
'Combo-delController',
|
||||
deleteBtn ? deleteBtn.className : ''
|
||||
),
|
||||
testIdBuilder: delTestIdBuilder,
|
||||
onClick: (e: any) => {
|
||||
if (!deleteBtn.onClick) {
|
||||
this.deleteItem(index);
|
||||
@ -1456,7 +1464,8 @@ export default class ComboControl extends React.Component<ComboProps> {
|
||||
type: 'button',
|
||||
className: cx('Combo-delController'),
|
||||
label: deleteBtn,
|
||||
onClick: this.deleteItem.bind(this, index)
|
||||
onClick: this.deleteItem.bind(this, index),
|
||||
testIdBuilder: delTestIdBuilder
|
||||
});
|
||||
}
|
||||
|
||||
@ -1468,6 +1477,7 @@ export default class ComboControl extends React.Component<ComboProps> {
|
||||
className={cx(`Combo-delBtn ${!store.removable ? 'is-disabled' : ''}`)}
|
||||
data-tooltip={!mobileUI ? __('delete') : null}
|
||||
data-position="bottom"
|
||||
{...delTestIdBuilder?.getTestId()}
|
||||
>
|
||||
{deleteIcon ? (
|
||||
<i className={deleteIcon} />
|
||||
@ -1495,10 +1505,12 @@ export default class ComboControl extends React.Component<ComboProps> {
|
||||
addIcon,
|
||||
conditions,
|
||||
translate: __,
|
||||
tabsMode
|
||||
tabsMode,
|
||||
testIdBuilder
|
||||
} = this.props;
|
||||
|
||||
const hasConditions = Array.isArray(conditions) && conditions.length;
|
||||
const addBtnTestIdBuilder = testIdBuilder?.getChild('add-button');
|
||||
return (
|
||||
<>
|
||||
{store.addable &&
|
||||
@ -1513,7 +1525,8 @@ export default class ComboControl extends React.Component<ComboProps> {
|
||||
level: 'info',
|
||||
size: 'sm',
|
||||
closeOnClick: true,
|
||||
btnClassName: addButtonClassName
|
||||
btnClassName: addButtonClassName,
|
||||
testIdBuilder: addBtnTestIdBuilder
|
||||
},
|
||||
{
|
||||
buttons: conditions?.map(item => ({
|
||||
@ -1534,12 +1547,14 @@ export default class ComboControl extends React.Component<ComboProps> {
|
||||
render('add-button', {
|
||||
...addBtn,
|
||||
type: 'button',
|
||||
testIdBuilder: addBtnTestIdBuilder,
|
||||
onClick: () => this.addItem()
|
||||
})
|
||||
) : (
|
||||
<Button
|
||||
className={cx(`Combo-addBtn`, addButtonClassName)}
|
||||
onClick={this.addItem}
|
||||
testIdBuilder={addBtnTestIdBuilder}
|
||||
>
|
||||
{addIcon ? <Icon icon="plus-fine" className="icon" /> : null}
|
||||
<span>{__(addButtonText || 'add')}</span>
|
||||
@ -1799,8 +1814,19 @@ export default class ComboControl extends React.Component<ComboProps> {
|
||||
lazyLoad,
|
||||
translate: __,
|
||||
static: isStatic,
|
||||
testIdBuilder,
|
||||
updatePristineAfterStoreDataReInit
|
||||
} = this.props;
|
||||
const finnalItems = Array.isArray(finnalControls)
|
||||
? finnalControls.map(item => {
|
||||
const indexKey = index !== undefined && index >= 0 ? `-${index}` : '';
|
||||
const key = `item-${item.testid || item.id}` + indexKey;
|
||||
return {
|
||||
...item,
|
||||
testIdBuilder: testIdBuilder?.getChild(key)
|
||||
};
|
||||
})
|
||||
: finnalControls;
|
||||
|
||||
// 单个
|
||||
if (!multiple) {
|
||||
@ -1808,7 +1834,7 @@ export default class ComboControl extends React.Component<ComboProps> {
|
||||
'single',
|
||||
{
|
||||
type: 'form',
|
||||
body: finnalControls,
|
||||
body: finnalItems,
|
||||
wrapperComponent: 'div',
|
||||
wrapWithPanel: false,
|
||||
mode: multiLine ? subFormMode || 'normal' : 'row',
|
||||
@ -1835,7 +1861,7 @@ export default class ComboControl extends React.Component<ComboProps> {
|
||||
`multiple/${index}`,
|
||||
{
|
||||
type: 'form',
|
||||
body: finnalControls,
|
||||
body: finnalItems,
|
||||
wrapperComponent: 'div',
|
||||
wrapWithPanel: false,
|
||||
mode: tabsMode ? subFormMode : multiLine ? subFormMode : 'row',
|
||||
|
@ -16,6 +16,8 @@ import {localeable, LocaleProps} from 'amis-core';
|
||||
import {FormBaseControlSchema} from '../../Schema';
|
||||
import {supportStatic} from './StaticHoc';
|
||||
|
||||
import type {TestIdBuilder} from 'amis-core';
|
||||
|
||||
/**
|
||||
* City 城市选择框。
|
||||
* 文档:https://aisuda.bce.baidu.com/amis/zh-CN/components/form/city
|
||||
@ -86,6 +88,7 @@ export interface CityPickerProps
|
||||
[propName: string]: any;
|
||||
};
|
||||
popOverContainer?: any;
|
||||
testIdBuilder?: TestIdBuilder;
|
||||
}
|
||||
|
||||
export interface CityDb {
|
||||
@ -419,7 +422,8 @@ export class CityPicker extends React.Component<
|
||||
translate: __,
|
||||
loadingConfig,
|
||||
popOverContainer,
|
||||
itemClassName
|
||||
itemClassName,
|
||||
testIdBuilder
|
||||
} = this.props;
|
||||
|
||||
const {provinceCode, cityCode, districtCode, street, db} = this.state;
|
||||
@ -437,6 +441,7 @@ export class CityPicker extends React.Component<
|
||||
value={provinceCode || ''}
|
||||
onChange={this.handleProvinceChange}
|
||||
popOverContainer={popOverContainer}
|
||||
testIdBuilder={testIdBuilder?.getChild('province')}
|
||||
/>
|
||||
|
||||
{allowCity && db.city[provinceCode] && db.city[provinceCode].length ? (
|
||||
@ -451,6 +456,7 @@ export class CityPicker extends React.Component<
|
||||
value={cityCode || ''}
|
||||
onChange={this.handleCityChange}
|
||||
popOverContainer={popOverContainer}
|
||||
testIdBuilder={testIdBuilder?.getChild('city')}
|
||||
/>
|
||||
) : null}
|
||||
|
||||
@ -470,6 +476,7 @@ export class CityPicker extends React.Component<
|
||||
value={districtCode || ''}
|
||||
onChange={this.handleDistrictChange}
|
||||
popOverContainer={popOverContainer}
|
||||
testIdBuilder={testIdBuilder?.getChild('district')}
|
||||
/>
|
||||
) : null}
|
||||
|
||||
@ -481,6 +488,7 @@ export class CityPicker extends React.Component<
|
||||
onBlur={this.handleStreetEnd}
|
||||
placeholder={__('City.street')}
|
||||
disabled={disabled}
|
||||
{...testIdBuilder?.getChild('street').getTestId()}
|
||||
/>
|
||||
) : null}
|
||||
</div>
|
||||
@ -578,7 +586,8 @@ export class LocationControl extends React.Component<LocationControlProps> {
|
||||
env,
|
||||
mobileUI,
|
||||
popOverContainer,
|
||||
itemClassName
|
||||
itemClassName,
|
||||
testIdBuilder
|
||||
} = this.props;
|
||||
|
||||
return mobileUI ? (
|
||||
@ -607,6 +616,7 @@ export class LocationControl extends React.Component<LocationControlProps> {
|
||||
joinValues={joinValues}
|
||||
allowStreet={allowStreet}
|
||||
disabled={disabled}
|
||||
testIdBuilder={testIdBuilder}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
@ -1416,7 +1416,7 @@ export default class FileControl extends React.Component<FileProps, FileState> {
|
||||
disabled={disabled}
|
||||
{...getInputProps()}
|
||||
capture={capture as any}
|
||||
{...testIdBuilder.getChild('input').getTestId()}
|
||||
{...testIdBuilder?.getChild('input').getTestId()}
|
||||
/>
|
||||
|
||||
{drag || isDragActive ? (
|
||||
@ -1461,7 +1461,7 @@ export default class FileControl extends React.Component<FileProps, FileState> {
|
||||
: ''
|
||||
}
|
||||
onClick={this.handleSelect}
|
||||
testIdBuilder={testIdBuilder.getChild('select')}
|
||||
testIdBuilder={testIdBuilder?.getChild('select')}
|
||||
>
|
||||
<Icon icon="upload" className="icon" />
|
||||
<span>
|
||||
@ -1591,7 +1591,7 @@ export default class FileControl extends React.Component<FileProps, FileState> {
|
||||
{!autoUpload && !hideUploadButton && files.length ? (
|
||||
<Button
|
||||
level="default"
|
||||
testIdBuilder={testIdBuilder.getChild('upload')}
|
||||
testIdBuilder={testIdBuilder?.getChild('upload')}
|
||||
disabled={!hasPending}
|
||||
className={cx('FileControl-uploadBtn', btnUploadClassName)}
|
||||
onClick={this.toggleUpload}
|
||||
|
@ -978,7 +978,7 @@ export default class FormTable extends React.Component<TableProps, TableState> {
|
||||
isCreateMode = false,
|
||||
editRowIndex?: number
|
||||
): Array<any> {
|
||||
const {env, enableStaticTransform} = this.props;
|
||||
const {env, enableStaticTransform, testIdBuilder} = this.props;
|
||||
let columns: Array<any> = Array.isArray(props.columns)
|
||||
? props.columns.concat()
|
||||
: [];
|
||||
@ -1014,6 +1014,9 @@ export default class FormTable extends React.Component<TableProps, TableState> {
|
||||
tooltipContainer={props.popOverContainer || env.getModalContainer}
|
||||
disabled={disabled}
|
||||
onClick={this.addItem.bind(this, rowIndex + offset, undefined)}
|
||||
testIdBuilder={testIdBuilder?.getChild(
|
||||
`addRow-${rowIndex + offset}`
|
||||
)}
|
||||
>
|
||||
{props.addBtnIcon ? (
|
||||
<Icon
|
||||
@ -1049,6 +1052,9 @@ export default class FormTable extends React.Component<TableProps, TableState> {
|
||||
tooltipContainer={props.popOverContainer || env.getModalContainer}
|
||||
disabled={disabled}
|
||||
onClick={this.copyItem.bind(this, rowIndex + offset, undefined)}
|
||||
testIdBuilder={testIdBuilder?.getChild(
|
||||
`copyRow-${rowIndex + offset}`
|
||||
)}
|
||||
>
|
||||
{props.copyBtnIcon ? (
|
||||
<Icon
|
||||
@ -1147,6 +1153,9 @@ export default class FormTable extends React.Component<TableProps, TableState> {
|
||||
}
|
||||
disabled={disabled}
|
||||
onClick={() => this.editItem(rowIndex + offset)}
|
||||
testIdBuilder={testIdBuilder?.getChild(
|
||||
`editRow-${rowIndex + offset}`
|
||||
)}
|
||||
>
|
||||
{/* 兼容之前的写法 */}
|
||||
{typeof props.updateBtnIcon !== 'undefined' ? (
|
||||
@ -1193,6 +1202,9 @@ export default class FormTable extends React.Component<TableProps, TableState> {
|
||||
props.popOverContainer || env.getModalContainer
|
||||
}
|
||||
onClick={this.confirmEdit}
|
||||
testIdBuilder={testIdBuilder?.getChild(
|
||||
`confirmRow-${rowIndex + offset}`
|
||||
)}
|
||||
>
|
||||
{props.confirmBtnIcon ? (
|
||||
<Icon
|
||||
@ -1230,6 +1242,9 @@ export default class FormTable extends React.Component<TableProps, TableState> {
|
||||
props.popOverContainer || env.getModalContainer
|
||||
}
|
||||
onClick={this.cancelEdit}
|
||||
testIdBuilder={testIdBuilder?.getChild(
|
||||
`cancelRow-${rowIndex + offset}`
|
||||
)}
|
||||
>
|
||||
{props.cancelBtnIcon ? (
|
||||
<Icon
|
||||
@ -1285,6 +1300,9 @@ export default class FormTable extends React.Component<TableProps, TableState> {
|
||||
tooltipContainer={props.popOverContainer || env.getModalContainer}
|
||||
disabled={disabled}
|
||||
onClick={this.removeItem.bind(this, rowIndex + offset)}
|
||||
testIdBuilder={testIdBuilder?.getChild(
|
||||
`delRow-${rowIndex + offset}`
|
||||
)}
|
||||
>
|
||||
{props.deleteBtnIcon ? (
|
||||
<Icon
|
||||
@ -1604,7 +1622,8 @@ export default class FormTable extends React.Component<TableProps, TableState> {
|
||||
showFooterAddBtn,
|
||||
footerAddBtn,
|
||||
toolbarClassName,
|
||||
onEvent
|
||||
onEvent,
|
||||
testIdBuilder
|
||||
} = this.props;
|
||||
const maxLength = this.resolveVariableProps(this.props, 'maxLength');
|
||||
|
||||
@ -1664,7 +1683,8 @@ export default class FormTable extends React.Component<TableProps, TableState> {
|
||||
offset,
|
||||
rowClassName,
|
||||
rowClassNameExpr,
|
||||
onPristineChange: this.handlePristineChange
|
||||
onPristineChange: this.handlePristineChange,
|
||||
testIdBuilder: testIdBuilder?.getChild('table')
|
||||
}
|
||||
)}
|
||||
{(!isStatic &&
|
||||
@ -1687,7 +1707,8 @@ export default class FormTable extends React.Component<TableProps, TableState> {
|
||||
},
|
||||
{
|
||||
disabled: this.computedAddBtnDisabled(),
|
||||
onClick: () => this.addItem(this.state.items.length)
|
||||
onClick: () => this.addItem(this.state.items.length),
|
||||
testIdBuilder: testIdBuilder?.getChild('add')
|
||||
}
|
||||
)
|
||||
: null}
|
||||
@ -1703,7 +1724,8 @@ export default class FormTable extends React.Component<TableProps, TableState> {
|
||||
perPage,
|
||||
total: this.state.items.length,
|
||||
onPageChange: this.handlePageChange,
|
||||
className: 'InputTable-pager'
|
||||
className: 'InputTable-pager',
|
||||
testIdBuilder: testIdBuilder?.getChild('page')
|
||||
}
|
||||
)
|
||||
: null}
|
||||
|
@ -575,7 +575,8 @@ export default class TagControl extends React.PureComponent<
|
||||
valueField,
|
||||
env,
|
||||
mobileUI,
|
||||
labelField
|
||||
labelField,
|
||||
testIdBuilder
|
||||
} = this.props;
|
||||
|
||||
const term = this.state.inputValue;
|
||||
@ -633,6 +634,7 @@ export default class TagControl extends React.PureComponent<
|
||||
popOverContainer={popOverContainer || env.getModalContainer}
|
||||
allowInput={!mobileUI || (mobileUI && !options?.length)}
|
||||
mobileUI={mobileUI}
|
||||
testIdBuilder={testIdBuilder?.getChild('resule-box')}
|
||||
>
|
||||
{loading ? (
|
||||
<Spinner loadingConfig={loadingConfig} size="sm" />
|
||||
@ -714,6 +716,7 @@ export default class TagControl extends React.PureComponent<
|
||||
options={finnalOptions}
|
||||
itemRender={this.renderItem}
|
||||
highlightIndex={highlightedIndex}
|
||||
testIdBuilder={testIdBuilder?.getChild('options')}
|
||||
getItemProps={({
|
||||
item,
|
||||
index
|
||||
|
@ -801,7 +801,7 @@ export default class TextControl extends React.PureComponent<
|
||||
}
|
||||
)}
|
||||
onClick={this.handleClick}
|
||||
{...testIdBuilder.getTestId()}
|
||||
{...testIdBuilder?.getTestId()}
|
||||
>
|
||||
<>
|
||||
{filteredPlaceholder &&
|
||||
@ -1008,7 +1008,7 @@ export default class TextControl extends React.PureComponent<
|
||||
inputControlClassName,
|
||||
inputOnly ? className : ''
|
||||
)}
|
||||
{...testIdBuilder.getTestId()}
|
||||
{...testIdBuilder?.getTestId()}
|
||||
>
|
||||
{prefix ? (
|
||||
<span className={cx('TextControl-inputPrefix')}>
|
||||
@ -1036,7 +1036,7 @@ export default class TextControl extends React.PureComponent<
|
||||
className={cx(nativeInputClassName, {
|
||||
'TextControl-input-password': type === 'password' && revealPassword
|
||||
})}
|
||||
{...testIdBuilder.getChild('input').getTestId()}
|
||||
{...testIdBuilder?.getChild('input').getTestId()}
|
||||
/>
|
||||
{clearable && !disabled && !readOnly && value ? (
|
||||
<a onClick={this.clearValue} className={cx('TextControl-clear')}>
|
||||
|
@ -536,7 +536,7 @@ export default class TreeControl extends React.Component<TreeProps, TreeState> {
|
||||
itemRender={menuTpl ? this.renderOptionItem : undefined}
|
||||
enableDefaultIcon={enableDefaultIcon}
|
||||
mobileUI={mobileUI}
|
||||
testIdBuilder={testIdBuilder.getChild('tree')}
|
||||
testIdBuilder={testIdBuilder?.getChild('tree')}
|
||||
/>
|
||||
);
|
||||
|
||||
@ -546,7 +546,7 @@ export default class TreeControl extends React.Component<TreeProps, TreeState> {
|
||||
'is-sticky': searchable && searchConfig?.sticky,
|
||||
'h-auto': heightAuto
|
||||
})}
|
||||
{...testIdBuilder.getChild('control').getTestId()}
|
||||
{...testIdBuilder?.getChild('control').getTestId()}
|
||||
>
|
||||
<Spinner
|
||||
size="sm"
|
||||
@ -567,7 +567,7 @@ export default class TreeControl extends React.Component<TreeProps, TreeState> {
|
||||
{...omit(searchConfig, 'className', 'sticky')}
|
||||
onSearch={this.handleSearch}
|
||||
mobileUI={mobileUI}
|
||||
testIdBuilder={testIdBuilder.getChild('search')}
|
||||
testIdBuilder={testIdBuilder?.getChild('search')}
|
||||
/>
|
||||
{TreeCmpt}
|
||||
</>
|
||||
|
@ -180,7 +180,8 @@ export default class ListControl extends React.Component<ListProps, any> {
|
||||
data,
|
||||
labelField,
|
||||
listClassName,
|
||||
translate: __
|
||||
translate: __,
|
||||
testIdBuilder
|
||||
} = this.props;
|
||||
|
||||
let body: JSX.Element | null = null;
|
||||
@ -202,6 +203,9 @@ export default class ListControl extends React.Component<ListProps, any> {
|
||||
? this.handleDBClick.bind(this, option)
|
||||
: undefined
|
||||
}
|
||||
{...testIdBuilder
|
||||
?.getChild(`options-${option.value || key}`)
|
||||
.getTestId()}
|
||||
>
|
||||
{itemSchema
|
||||
? render(
|
||||
|
@ -629,7 +629,8 @@ export default class PickerControl extends React.PureComponent<
|
||||
valueField,
|
||||
embed,
|
||||
source,
|
||||
strictMode
|
||||
strictMode,
|
||||
testIdBuilder
|
||||
} = this.props;
|
||||
const {maxTagCount, overflowTagPopoverInCRUD, displayPosition} =
|
||||
this.getOverflowConfig();
|
||||
@ -641,6 +642,7 @@ export default class PickerControl extends React.PureComponent<
|
||||
options: source ? [] : options,
|
||||
multiple,
|
||||
strictMode,
|
||||
testIdBuilder: testIdBuilder?.getChild('body-schema'),
|
||||
onSelect: embed
|
||||
? (selectedItems: Array<any>, unSelectedItems: Array<any>) => {
|
||||
// 选择行后,crud 会给出连续多次事件,且selectedItems会变化,会导致初始化和点击无效
|
||||
@ -712,7 +714,8 @@ export default class PickerControl extends React.PureComponent<
|
||||
themeCss,
|
||||
css,
|
||||
id,
|
||||
classPrefix: ns
|
||||
classPrefix: ns,
|
||||
testIdBuilder
|
||||
} = this.props;
|
||||
return (
|
||||
<div className={cx(`PickerControl`, {'is-mobile': mobileUI}, className)}>
|
||||
@ -753,7 +756,10 @@ export default class PickerControl extends React.PureComponent<
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
<div className={cx('Picker-valueWrap')}>
|
||||
<div
|
||||
className={cx('Picker-valueWrap')}
|
||||
{...testIdBuilder?.getTestId()}
|
||||
>
|
||||
{this.renderValues()}
|
||||
|
||||
<input
|
||||
@ -773,7 +779,11 @@ export default class PickerControl extends React.PureComponent<
|
||||
</a>
|
||||
) : null}
|
||||
|
||||
<span onClick={this.open} className={cx('Picker-btn')}>
|
||||
<span
|
||||
onClick={this.open}
|
||||
className={cx('Picker-btn')}
|
||||
{...testIdBuilder?.getChild('picker-btn').getTestId()}
|
||||
>
|
||||
<Icon
|
||||
icon="window-restore"
|
||||
className={cx(
|
||||
@ -802,7 +812,8 @@ export default class PickerControl extends React.PureComponent<
|
||||
className: modalClassName,
|
||||
body: {
|
||||
children: this.renderBody
|
||||
}
|
||||
},
|
||||
testIdBuilder: testIdBuilder?.getChild('modal')
|
||||
},
|
||||
{
|
||||
key: 'modal',
|
||||
|
@ -6,7 +6,8 @@ import {
|
||||
OptionsControlProps,
|
||||
Option,
|
||||
FormOptionsControl,
|
||||
resolveEventData
|
||||
resolveEventData,
|
||||
TestIdBuilder
|
||||
} from 'amis-core';
|
||||
import {autobind, isEmpty, createObject} from 'amis-core';
|
||||
import {ActionObject} from 'amis-core';
|
||||
@ -37,6 +38,7 @@ export interface RadiosProps extends OptionsControlProps {
|
||||
labelClassName?: string;
|
||||
/** 选项CSS类名 */
|
||||
optionClassName?: string;
|
||||
testIdBuilder?: TestIdBuilder;
|
||||
}
|
||||
|
||||
export default class RadiosControl extends React.Component<RadiosProps, any> {
|
||||
@ -126,7 +128,8 @@ export default class RadiosControl extends React.Component<RadiosProps, any> {
|
||||
data,
|
||||
translate: __,
|
||||
optionType,
|
||||
level
|
||||
level,
|
||||
testIdBuilder
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
@ -151,6 +154,7 @@ export default class RadiosControl extends React.Component<RadiosProps, any> {
|
||||
itemClassName={itemClassName}
|
||||
optionType={optionType}
|
||||
level={level}
|
||||
testIdBuilder={testIdBuilder}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
@ -418,7 +418,9 @@ export default class SelectControl extends React.Component<SelectProps, any> {
|
||||
showNativeTitle: true,
|
||||
className: cx('Select-option-content', optionClassName),
|
||||
data: createObject(createObject(data, state), option),
|
||||
testIdBuilder: testIdBuilder?.getChild('option-' + state.index)
|
||||
testIdBuilder: testIdBuilder?.getChild(
|
||||
'option-' + option.value || state.index
|
||||
)
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -33,6 +33,7 @@ import {FormOptionsSchema, SchemaApi} from '../../Schema';
|
||||
import {supportStatic} from './StaticHoc';
|
||||
import {TooltipWrapperSchema} from '../TooltipWrapper';
|
||||
import type {ItemRenderStates} from 'amis-ui/lib/components/Selection';
|
||||
import type {TestIdBuilder} from 'amis-core';
|
||||
|
||||
/**
|
||||
* Tree 下拉选择框。
|
||||
@ -130,6 +131,7 @@ export interface TreeSelectControlSchema extends FormOptionsSchema {
|
||||
* 是否为选项添加默认的Icon,默认值为true
|
||||
*/
|
||||
enableDefaultIcon?: boolean;
|
||||
testIdBuilder?: TestIdBuilder;
|
||||
}
|
||||
|
||||
export interface TreeSelectProps
|
||||
@ -786,7 +788,7 @@ export default class TreeSelectControl extends React.Component<
|
||||
<div
|
||||
ref={this.container}
|
||||
className={cx(`TreeSelectControl`, className)}
|
||||
{...testIdBuilder.getTestId()}
|
||||
{...testIdBuilder?.getTestId()}
|
||||
>
|
||||
<ResultBox
|
||||
popOverContainer={popOverContainer || env.getModalContainer}
|
||||
@ -824,6 +826,7 @@ export default class TreeSelectControl extends React.Component<
|
||||
hasDropDownArrow
|
||||
readOnly={mobileUI}
|
||||
mobileUI={mobileUI}
|
||||
testIdBuilder={testIdBuilder?.getChild('result-box')}
|
||||
>
|
||||
{loading ? (
|
||||
<Spinner loadingConfig={loadingConfig} size="sm" />
|
||||
|
@ -953,7 +953,8 @@ export default class List extends React.Component<ListProps, object> {
|
||||
checkOnItemClick,
|
||||
itemAction,
|
||||
classnames: cx,
|
||||
translate: __
|
||||
translate: __,
|
||||
testIdBuilder
|
||||
} = this.props;
|
||||
const hasClickActions =
|
||||
onEvent &&
|
||||
@ -973,6 +974,7 @@ export default class List extends React.Component<ListProps, object> {
|
||||
'is-modified': item.modified,
|
||||
'is-moved': item.moved
|
||||
}),
|
||||
testIdBuilder: testIdBuilder?.getChild(index),
|
||||
selectable: store.selectable,
|
||||
checkable: item.checkable,
|
||||
multiple,
|
||||
@ -1174,7 +1176,8 @@ export class ListItem extends React.Component<ListItemProps> {
|
||||
hideCheckToggler,
|
||||
checkOnItemClick,
|
||||
classnames: cx,
|
||||
classPrefix: ns
|
||||
classPrefix: ns,
|
||||
testIdBuilder
|
||||
} = this.props;
|
||||
|
||||
if (dragging) {
|
||||
@ -1193,6 +1196,7 @@ export class ListItem extends React.Component<ListItemProps> {
|
||||
checked={selected}
|
||||
onChange={this.handleCheck}
|
||||
inline
|
||||
testIdBuilder={testIdBuilder?.getChild('checkbox')}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
@ -34,7 +34,7 @@ export interface CellProps extends ThemeProps {
|
||||
quickEditFormRef: any;
|
||||
onImageEnlarge?: any;
|
||||
translate: (key: string, ...args: Array<any>) => string;
|
||||
testIdBuilder: TestIdBuilder;
|
||||
testIdBuilder?: TestIdBuilder;
|
||||
}
|
||||
|
||||
export default function Cell({
|
||||
@ -80,7 +80,7 @@ export default function Cell({
|
||||
<td
|
||||
style={style}
|
||||
className={cx(column.pristine.className, stickyClassName)}
|
||||
{...testIdBuilder.getTestId()}
|
||||
{...testIdBuilder?.getTestId()}
|
||||
>
|
||||
<Checkbox
|
||||
classPrefix={ns}
|
||||
@ -89,7 +89,7 @@ export default function Cell({
|
||||
checked={item.checked || item.partial}
|
||||
disabled={item.checkdisable || !item.checkable}
|
||||
onChange={onCheckboxChange}
|
||||
testIdBuilder={testIdBuilder.getChild('chekbx')}
|
||||
testIdBuilder={testIdBuilder?.getChild('chekbx')}
|
||||
/>
|
||||
</td>
|
||||
);
|
||||
@ -100,7 +100,7 @@ export default function Cell({
|
||||
className={cx(column.pristine.className, stickyClassName, {
|
||||
'is-dragDisabled': !item.draggable
|
||||
})}
|
||||
{...testIdBuilder.getChild('drag').getTestId()}
|
||||
{...testIdBuilder?.getChild('drag').getTestId()}
|
||||
>
|
||||
{item.draggable ? <Icon icon="drag" className="icon" /> : null}
|
||||
</td>
|
||||
@ -118,7 +118,7 @@ export default function Cell({
|
||||
// data-position="top"
|
||||
onClick={item.toggleExpanded}
|
||||
{...testIdBuilder
|
||||
.getChild(item.expanded ? 'fold' : 'expand')
|
||||
?.getChild(item.expanded ? 'fold' : 'expand')
|
||||
.getTestId()}
|
||||
>
|
||||
<Icon icon="right-arrow-bold" className="icon" />
|
||||
@ -151,7 +151,7 @@ export default function Cell({
|
||||
key="retryBtn"
|
||||
onClick={item.resetDefered}
|
||||
data-tooltip={__('Options.retry', {reason: item.error})}
|
||||
{...testIdBuilder.getChild('retry').getTestId()}
|
||||
{...testIdBuilder?.getChild('retry').getTestId()}
|
||||
>
|
||||
<Icon icon="retry" className="icon" />
|
||||
</a>
|
||||
@ -163,7 +163,7 @@ export default function Cell({
|
||||
// data-position="top"
|
||||
onClick={item.toggleExpanded}
|
||||
{...testIdBuilder
|
||||
.getChild(item.expanded ? 'fold' : 'expand')
|
||||
?.getChild(item.expanded ? 'fold' : 'expand')
|
||||
.getTestId()}
|
||||
>
|
||||
<Icon icon="right-arrow-bold" className="icon" />
|
||||
@ -187,7 +187,7 @@ export default function Cell({
|
||||
draggable
|
||||
onDragStart={onDragStart}
|
||||
className={cx('Table-dragBtn')}
|
||||
{...testIdBuilder.getChild('drag').getTestId()}
|
||||
{...testIdBuilder?.getChild('drag').getTestId()}
|
||||
>
|
||||
<Icon icon="drag" className="icon" />
|
||||
</a>
|
||||
@ -250,7 +250,8 @@ export default function Cell({
|
||||
column.pristine.className,
|
||||
stickyClassName,
|
||||
addtionalClassName
|
||||
)
|
||||
),
|
||||
testIdBuilder: testIdBuilder?.getChild(column.name || column.value)
|
||||
};
|
||||
delete subProps.label;
|
||||
|
||||
@ -259,8 +260,7 @@ export default function Cell({
|
||||
{
|
||||
...column.pristine,
|
||||
column: column.pristine,
|
||||
type: 'cell',
|
||||
testid: testIdBuilder.getTestIdValue()
|
||||
type: 'cell'
|
||||
},
|
||||
subProps
|
||||
);
|
||||
|
@ -1,5 +1,5 @@
|
||||
import React from 'react';
|
||||
import {ClassNamesFn, RendererEvent} from 'amis-core';
|
||||
import {ClassNamesFn, RendererEvent, autobind} from 'amis-core';
|
||||
|
||||
import {SchemaNode, ActionObject} from 'amis-core';
|
||||
import TableRow from './TableRow';
|
||||
@ -69,6 +69,11 @@ export class TableBody extends React.Component<TableBodyProps> {
|
||||
this.props.store.initTableWidth();
|
||||
}
|
||||
|
||||
@autobind
|
||||
testIdBuilder(rowPath: string) {
|
||||
return this.props.testIdBuilder?.getChild(`row-${rowPath}`);
|
||||
}
|
||||
|
||||
renderRows(
|
||||
rows: Array<any>,
|
||||
columns = this.props.columns,
|
||||
@ -94,19 +99,17 @@ export class TableBody extends React.Component<TableBodyProps> {
|
||||
onRowDbClick,
|
||||
onRowMouseEnter,
|
||||
onRowMouseLeave,
|
||||
store,
|
||||
testIdBuilder
|
||||
store
|
||||
} = this.props;
|
||||
|
||||
return rows.map((item: IRow, rowIndex: number) => {
|
||||
const itemProps = buildItemProps ? buildItemProps(item, rowIndex) : null;
|
||||
const rowPath = `${indexPath ? indexPath + '/' : ''}${rowIndex}`;
|
||||
const rowTestBuidr = testIdBuilder?.getChild(`row-${rowPath}`);
|
||||
|
||||
const doms = [
|
||||
<TableRow
|
||||
{...itemProps}
|
||||
testIdBuilder={rowTestBuidr}
|
||||
testIdBuilder={this.testIdBuilder}
|
||||
store={store}
|
||||
itemAction={itemAction}
|
||||
classnames={cx}
|
||||
@ -173,7 +176,7 @@ export class TableBody extends React.Component<TableBodyProps> {
|
||||
onQuickChange={onQuickChange}
|
||||
ignoreFootableContent={ignoreFootableContent}
|
||||
{...rowProps}
|
||||
testIdBuilder={rowTestBuidr}
|
||||
testIdBuilder={this.testIdBuilder}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
@ -10,10 +10,13 @@ import {Badge} from 'amis-ui';
|
||||
import {ColorScale} from 'amis-core';
|
||||
import {isPureVariable, resolveVariableAndFilter} from 'amis-core';
|
||||
|
||||
import type {TestIdBuilder} from 'amis-core';
|
||||
|
||||
export interface TableCellProps extends RendererProps {
|
||||
wrapperComponent?: React.ElementType;
|
||||
column: any;
|
||||
contentsOnly?: boolean;
|
||||
testIdBuilder?: TestIdBuilder;
|
||||
}
|
||||
|
||||
export class TableCell extends React.Component<TableCellProps> {
|
||||
@ -158,7 +161,7 @@ export class TableCell extends React.Component<TableCellProps> {
|
||||
className={cx(className)}
|
||||
tabIndex={tabIndex}
|
||||
onKeyUp={onKeyUp}
|
||||
{...testIdBuilder.getTestId()}
|
||||
{...testIdBuilder?.getChild('cell').getTestId()}
|
||||
>
|
||||
{showBadge ? (
|
||||
<Badge
|
||||
|
@ -44,7 +44,7 @@ interface TableRowProps extends Pick<RendererProps, 'render'> {
|
||||
regionPrefix?: string;
|
||||
checkOnItemClick?: boolean;
|
||||
ignoreFootableContent?: boolean;
|
||||
testIdBuilder?: TestIdBuilder;
|
||||
testIdBuilder?: (key: string) => TestIdBuilder;
|
||||
rowPath: string; // 整体行的路径,树形时需要父行序号/当前展开层级下的行序号
|
||||
[propName: string]: any;
|
||||
}
|
||||
@ -323,7 +323,7 @@ export class TableRow extends React.PureComponent<
|
||||
},
|
||||
`Table-tr--${depth}th`
|
||||
)}
|
||||
{...testIdBuilder?.getTestId()}
|
||||
{...testIdBuilder?.(rowPath).getTestId()}
|
||||
>
|
||||
{columns.map(column =>
|
||||
appeard ? (
|
||||
|
@ -810,7 +810,7 @@ export default class Tabs extends React.Component<TabsProps, TabsState> {
|
||||
: unmountOnExit
|
||||
}
|
||||
onSelect={this.handleSelect}
|
||||
testIdBuilder={testIdBuilder.getChild(
|
||||
testIdBuilder={testIdBuilder?.getChild(
|
||||
`tab-${typeof tab.title === 'string' ? tab.title : index}`
|
||||
)}
|
||||
>
|
||||
@ -854,7 +854,7 @@ export default class Tabs extends React.Component<TabsProps, TabsState> {
|
||||
: unmountOnExit
|
||||
}
|
||||
onSelect={this.handleSelect}
|
||||
testIdBuilder={testIdBuilder.getChild(
|
||||
testIdBuilder={testIdBuilder?.getChild(
|
||||
`tab-${typeof tab.title === 'string' ? tab.title : index}`
|
||||
)}
|
||||
>
|
||||
|
Loading…
Reference in New Issue
Block a user