mirror of
https://gitee.com/baidu/amis.git
synced 2024-12-02 20:09:08 +08:00
fix: 修复部分表单嵌套报错, 将错误的嵌套用法提示改成不那么激进的 warning 提示 (#2636)
* fix: 修复部分表单嵌套报错, 将错误的嵌套用法提示改成不那么激进的 warning 提示 * 更新用例 & 修复 dropdown-button 报错
This commit is contained in:
parent
c7f460a373
commit
137cbcb461
@ -195,65 +195,123 @@ exports[`factory:definitions 1`] = `
|
||||
class="cxd-Combo-itemInner"
|
||||
>
|
||||
<div
|
||||
class="cxd-Alert cxd-Alert--danger"
|
||||
class="cxd-Form cxd-Form--normal cxd-Combo-form"
|
||||
novalidate=""
|
||||
>
|
||||
<p>
|
||||
Error: 不允许在表单及表单按钮组中直接嵌套表单
|
||||
</p>
|
||||
<p>
|
||||
Path:
|
||||
page/body/0/form/1/combo/multiple/0/form
|
||||
</p>
|
||||
<pre>
|
||||
<code>
|
||||
{
|
||||
"type": "form",
|
||||
"body": [
|
||||
{
|
||||
"label": "combo 1",
|
||||
"type": "input-text",
|
||||
"name": "key"
|
||||
},
|
||||
{
|
||||
"type": "input-text",
|
||||
"name": "value",
|
||||
"value": "ref value",
|
||||
"remark": "通过<code>\\\\$ref</code>引入的组件",
|
||||
"label": "combo 2"
|
||||
},
|
||||
{
|
||||
"type": "combo",
|
||||
"multiple": true,
|
||||
"multiLine": true,
|
||||
"remark": "<code>combo</code>中的子项引入自身,实现嵌套的效果",
|
||||
"controls": [
|
||||
{
|
||||
"label": "combo 1",
|
||||
"type": "text",
|
||||
"name": "key"
|
||||
},
|
||||
{
|
||||
"label": "combo 2",
|
||||
"name": "value",
|
||||
"$ref": "aa"
|
||||
},
|
||||
{
|
||||
"name": "children",
|
||||
"label": "children",
|
||||
"$ref": "bb"
|
||||
}
|
||||
],
|
||||
"name": "children",
|
||||
"label": "children"
|
||||
}
|
||||
],
|
||||
"wrapperComponent": "div",
|
||||
"wrapWithPanel": false,
|
||||
"mode": "normal",
|
||||
"className": "cxd-Combo-form"
|
||||
}
|
||||
</code>
|
||||
</pre>
|
||||
<input
|
||||
style="display: none;"
|
||||
type="submit"
|
||||
/>
|
||||
<div
|
||||
class="cxd-Form-item cxd-Form-item--normal"
|
||||
data-role="form-item"
|
||||
>
|
||||
<label
|
||||
class="cxd-Form-label"
|
||||
>
|
||||
<span>
|
||||
<span
|
||||
class="cxd-TplField"
|
||||
>
|
||||
<span>
|
||||
combo 1
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</label>
|
||||
<div
|
||||
class="cxd-Form-control cxd-TextControl"
|
||||
>
|
||||
<div
|
||||
class="cxd-TextControl-input"
|
||||
>
|
||||
<input
|
||||
autocomplete="off"
|
||||
name="key"
|
||||
placeholder=""
|
||||
size="10"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="cxd-Form-item cxd-Form-item--normal"
|
||||
data-role="form-item"
|
||||
>
|
||||
<label
|
||||
class="cxd-Form-label"
|
||||
>
|
||||
<span>
|
||||
<span
|
||||
class="cxd-TplField"
|
||||
>
|
||||
<span>
|
||||
combo 2
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</label>
|
||||
<div
|
||||
class="cxd-Form-control cxd-TextControl"
|
||||
>
|
||||
<div
|
||||
class="cxd-TextControl-input"
|
||||
>
|
||||
<input
|
||||
autocomplete="off"
|
||||
name="value"
|
||||
placeholder=""
|
||||
size="10"
|
||||
type="text"
|
||||
value="ref value"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="cxd-Remark cxd-Form-remark"
|
||||
>
|
||||
<span
|
||||
class="cxd-Remark-icon"
|
||||
>
|
||||
<icon-mock
|
||||
classname=" icon-warning-mark"
|
||||
icon="warning-mark"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="cxd-Form-item cxd-Form-item--normal"
|
||||
data-role="form-item"
|
||||
>
|
||||
<label
|
||||
class="cxd-Form-label"
|
||||
>
|
||||
<span>
|
||||
<span
|
||||
class="cxd-TplField"
|
||||
>
|
||||
<span>
|
||||
children
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</label>
|
||||
<div
|
||||
class="cxd-Remark cxd-Form-remark"
|
||||
>
|
||||
<span
|
||||
class="cxd-Remark-icon"
|
||||
>
|
||||
<icon-mock
|
||||
classname=" icon-warning-mark"
|
||||
icon="warning-mark"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<a
|
||||
|
@ -796,6 +796,59 @@ exports[`Renderer:Page handleAction actionType=drawer 1`] = `
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="amis-dialog-widget cxd-Drawer cxd-Drawer--right cxd-Drawer--md cxd-Modal--1th"
|
||||
role="dialog"
|
||||
>
|
||||
<div
|
||||
class="cxd-Drawer-overlay in"
|
||||
/>
|
||||
<div
|
||||
class="cxd-Drawer-content in"
|
||||
>
|
||||
<a
|
||||
class="cxd-Drawer-close"
|
||||
>
|
||||
<icon-mock
|
||||
classname="icon icon-close"
|
||||
icon="close"
|
||||
/>
|
||||
</a>
|
||||
<div
|
||||
class="cxd-Drawer-header"
|
||||
/>
|
||||
<div
|
||||
class="cxd-Drawer-body"
|
||||
>
|
||||
<div
|
||||
class="cxd-Spinner-overlay in"
|
||||
/>
|
||||
<div
|
||||
class="cxd-Spinner in cxd-Spinner--overlay cxd-Spinner--lg"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="cxd-Drawer-footer"
|
||||
>
|
||||
<button
|
||||
class="cxd-Button cxd-Button--default"
|
||||
type="button"
|
||||
>
|
||||
<span>
|
||||
取消
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
class="cxd-Button cxd-Button--primary"
|
||||
type="button"
|
||||
>
|
||||
<span>
|
||||
确认
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@ -868,6 +921,92 @@ exports[`Renderer:Page handleAction actionType=drawer mergeData 1`] = `
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="amis-dialog-widget cxd-Drawer cxd-Drawer--right cxd-Drawer--md cxd-Modal--1th"
|
||||
role="dialog"
|
||||
>
|
||||
<div
|
||||
class="cxd-Drawer-overlay in"
|
||||
/>
|
||||
<div
|
||||
class="cxd-Drawer-content in"
|
||||
>
|
||||
<a
|
||||
class="cxd-Drawer-close"
|
||||
>
|
||||
<icon-mock
|
||||
classname="icon icon-close"
|
||||
icon="close"
|
||||
/>
|
||||
</a>
|
||||
<div
|
||||
class="cxd-Drawer-header"
|
||||
/>
|
||||
<div
|
||||
class="cxd-Drawer-body"
|
||||
>
|
||||
<form
|
||||
class="cxd-Form cxd-Form--horizontal"
|
||||
novalidate=""
|
||||
>
|
||||
<input
|
||||
style="display: none;"
|
||||
type="submit"
|
||||
/>
|
||||
<div
|
||||
class="cxd-Form-item cxd-Form-item--horizontal"
|
||||
data-role="form-item"
|
||||
>
|
||||
<label
|
||||
class="cxd-Form-label cxd-Form-itemColumn--normal"
|
||||
>
|
||||
<span>
|
||||
<span
|
||||
class="cxd-TplField"
|
||||
>
|
||||
<span>
|
||||
A
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</label>
|
||||
<div
|
||||
class="cxd-Form-value"
|
||||
>
|
||||
<div
|
||||
class="cxd-Form-control cxd-TextControl"
|
||||
>
|
||||
<div
|
||||
class="cxd-TextControl-input"
|
||||
>
|
||||
<input
|
||||
autocomplete="off"
|
||||
name="a"
|
||||
placeholder=""
|
||||
size="10"
|
||||
type="text"
|
||||
value="3"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div
|
||||
class="cxd-Drawer-footer"
|
||||
>
|
||||
<button
|
||||
class="cxd-Button cxd-Button--default"
|
||||
type="submit"
|
||||
>
|
||||
<span>
|
||||
确认
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@ -1442,6 +1581,92 @@ exports[`Renderer:Page initApi reload by Drawer action 2`] = `
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="amis-dialog-widget cxd-Drawer cxd-Drawer--right cxd-Drawer--md cxd-Modal--1th"
|
||||
role="dialog"
|
||||
>
|
||||
<div
|
||||
class="cxd-Drawer-overlay in"
|
||||
/>
|
||||
<div
|
||||
class="cxd-Drawer-content in"
|
||||
>
|
||||
<a
|
||||
class="cxd-Drawer-close"
|
||||
>
|
||||
<icon-mock
|
||||
classname="icon icon-close"
|
||||
icon="close"
|
||||
/>
|
||||
</a>
|
||||
<div
|
||||
class="cxd-Drawer-header"
|
||||
/>
|
||||
<div
|
||||
class="cxd-Drawer-body"
|
||||
>
|
||||
<form
|
||||
class="cxd-Form cxd-Form--horizontal"
|
||||
novalidate=""
|
||||
>
|
||||
<input
|
||||
style="display: none;"
|
||||
type="submit"
|
||||
/>
|
||||
<div
|
||||
class="cxd-Form-item cxd-Form-item--horizontal"
|
||||
data-role="form-item"
|
||||
>
|
||||
<label
|
||||
class="cxd-Form-label cxd-Form-itemColumn--normal"
|
||||
>
|
||||
<span />
|
||||
</label>
|
||||
<div
|
||||
class="cxd-Form-value"
|
||||
>
|
||||
<div
|
||||
class="cxd-Form-control cxd-TextControl"
|
||||
>
|
||||
<div
|
||||
class="cxd-TextControl-input"
|
||||
>
|
||||
<input
|
||||
autocomplete="off"
|
||||
name="a"
|
||||
placeholder=""
|
||||
size="10"
|
||||
type="text"
|
||||
value="1"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div
|
||||
class="cxd-Drawer-footer"
|
||||
>
|
||||
<button
|
||||
class="cxd-Button cxd-Button--default"
|
||||
type="button"
|
||||
>
|
||||
<span>
|
||||
取消
|
||||
</span>
|
||||
</button>
|
||||
<button
|
||||
class="cxd-Button cxd-Button--primary"
|
||||
type="button"
|
||||
>
|
||||
<span>
|
||||
确认
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
|
@ -67,6 +67,20 @@ export class Drawer extends React.Component<DrawerProps, DrawerState> {
|
||||
document.body.addEventListener('click', this.handleRootClick);
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps: DrawerProps) {
|
||||
// jest 里面没有触发 entered 导致后续的逻辑错误,
|
||||
// 所以直接 300 ms 后触发
|
||||
if (
|
||||
typeof jest !== 'undefined' &&
|
||||
prevProps.show !== this.props.show &&
|
||||
this.props.show
|
||||
) {
|
||||
setTimeout(() => {
|
||||
this.handleEntered();
|
||||
}, 300);
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
if (this.props.show) {
|
||||
this.handleExited();
|
||||
|
@ -46,6 +46,13 @@ export default class LazyComponent extends React.Component<
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
// jest 里面有点异常,先手动让它总是可见
|
||||
if (typeof jest !== 'undefined') {
|
||||
this.handleVisibleChange(true);
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.mounted = false;
|
||||
}
|
||||
|
@ -102,6 +102,7 @@ register('de-DE', {
|
||||
'Form.title': 'Formular',
|
||||
'Form.unique': 'Aktueller Wert ist nicht eindeutig',
|
||||
'Form.validateFailed': 'Fehler bei der Überprüfung der Formulareingabe',
|
||||
'Form.nestedError': 'Form kann nicht als Nachkomme von Form erscheinen',
|
||||
'Image.configError': 'Es können nur eine Beschneidung oder mehrere festgelegt werden',
|
||||
'Image.crop': 'Bild beschneiden',
|
||||
'Image.dragDrop': 'Bilder per Drag & Drop hier ablegen',
|
||||
|
@ -103,6 +103,7 @@ register('en-US', {
|
||||
'Form.title': 'Form',
|
||||
'Form.unique': 'Current value is not unique',
|
||||
'Form.validateFailed': 'Form input validation failed',
|
||||
'Form.nestedError': 'Form cannot appear as a descendant of form',
|
||||
'Image.configError': 'Can only set one of crop or multiple',
|
||||
'Image.crop': 'Crop image',
|
||||
'Image.dragDrop': `Drag 'n' drop some photos here`,
|
||||
|
@ -105,6 +105,7 @@ register('zh-CN', {
|
||||
'Form.title': '表单',
|
||||
'Form.unique': '当前值不唯一',
|
||||
'Form.validateFailed': '依赖的部分字段没有通过验证',
|
||||
'Form.nestedError': '表单不要直接嵌套在表单下面',
|
||||
'Image.configError': '图片多选配置和裁剪配置只能设置一个',
|
||||
'Image.crop': '裁剪图片',
|
||||
'Image.dragDrop': '将图片拖拽到此处',
|
||||
|
@ -375,7 +375,8 @@ export default class CRUD extends React.Component<CRUDProps, any> {
|
||||
'onChange',
|
||||
'onInit',
|
||||
'onSaved',
|
||||
'onQuery'
|
||||
'onQuery',
|
||||
'formStore'
|
||||
];
|
||||
static defaultProps = {
|
||||
toolbarInline: true,
|
||||
|
@ -334,7 +334,8 @@ export default class ComboControl extends React.Component<ComboProps> {
|
||||
'strictMode',
|
||||
'items',
|
||||
'conditions',
|
||||
'messages'
|
||||
'messages',
|
||||
'formStore'
|
||||
];
|
||||
|
||||
subForms: Array<any> = [];
|
||||
@ -367,15 +368,8 @@ export default class ComboControl extends React.Component<ComboProps> {
|
||||
...props.scaffold
|
||||
};
|
||||
|
||||
const {
|
||||
store,
|
||||
value,
|
||||
multiple,
|
||||
minLength,
|
||||
maxLength,
|
||||
formItem,
|
||||
addHook
|
||||
} = props;
|
||||
const {store, value, multiple, minLength, maxLength, formItem, addHook} =
|
||||
props;
|
||||
|
||||
store.config({
|
||||
multiple,
|
||||
@ -451,14 +445,8 @@ export default class ComboControl extends React.Component<ComboProps> {
|
||||
}
|
||||
|
||||
addItemWith(condition: ComboCondition) {
|
||||
const {
|
||||
flat,
|
||||
joinValues,
|
||||
delimiter,
|
||||
scaffold,
|
||||
disabled,
|
||||
submitOnChange
|
||||
} = this.props;
|
||||
const {flat, joinValues, delimiter, scaffold, disabled, submitOnChange} =
|
||||
this.props;
|
||||
|
||||
if (disabled) {
|
||||
return;
|
||||
@ -483,14 +471,8 @@ export default class ComboControl extends React.Component<ComboProps> {
|
||||
}
|
||||
|
||||
addItem() {
|
||||
const {
|
||||
flat,
|
||||
joinValues,
|
||||
delimiter,
|
||||
scaffold,
|
||||
disabled,
|
||||
submitOnChange
|
||||
} = this.props;
|
||||
const {flat, joinValues, delimiter, scaffold, disabled, submitOnChange} =
|
||||
this.props;
|
||||
|
||||
if (disabled) {
|
||||
return;
|
||||
@ -562,14 +544,8 @@ export default class ComboControl extends React.Component<ComboProps> {
|
||||
}
|
||||
|
||||
handleChange(values: any, diff: any, {index}: any) {
|
||||
const {
|
||||
flat,
|
||||
store,
|
||||
joinValues,
|
||||
delimiter,
|
||||
disabled,
|
||||
submitOnChange
|
||||
} = this.props;
|
||||
const {flat, store, joinValues, delimiter, disabled, submitOnChange} =
|
||||
this.props;
|
||||
|
||||
if (disabled) {
|
||||
return;
|
||||
@ -781,8 +757,8 @@ export default class ComboControl extends React.Component<ComboProps> {
|
||||
[propName: number]: any;
|
||||
} = {};
|
||||
|
||||
makeFormRef = memoize((index: number) => (ref: any) =>
|
||||
this.formRef(ref, index)
|
||||
makeFormRef = memoize(
|
||||
(index: number) => (ref: any) => this.formRef(ref, index)
|
||||
);
|
||||
|
||||
formRef(ref: any, index: number = 0) {
|
||||
|
@ -142,6 +142,8 @@ export default class SubFormControl extends React.PureComponent<
|
||||
placeholder: 'placeholder.empty'
|
||||
};
|
||||
|
||||
static propsList: Array<string> = ['form', 'formStore'];
|
||||
|
||||
state: SubFormState = {};
|
||||
dragTip?: HTMLElement;
|
||||
sortable?: Sortable;
|
||||
|
@ -187,7 +187,8 @@ export default class FormTable extends React.Component<TableProps, TableState> {
|
||||
'updateApi',
|
||||
'deleteApi',
|
||||
'needConfirm',
|
||||
'canAccessSuperData'
|
||||
'canAccessSuperData',
|
||||
'formStore'
|
||||
];
|
||||
|
||||
entries: SimpleMap<any, number>;
|
||||
|
@ -1019,7 +1019,8 @@ export class FormItemWrap extends React.Component<FormItemProps> {
|
||||
show: model.dialogOpen,
|
||||
onClose: this.handleDialogClose,
|
||||
onConfirm: this.handleDialogConfirm,
|
||||
data: model.dialogData
|
||||
data: model.dialogData,
|
||||
formStore: undefined
|
||||
}
|
||||
)
|
||||
: null}
|
||||
|
@ -1519,20 +1519,19 @@ export default class Form extends React.Component<FormProps, object> {
|
||||
|
||||
let body: JSX.Element = this.renderBody();
|
||||
|
||||
// 表单组件限制
|
||||
const isFormInFormActions: boolean = /panel\/action\/form$/.test($path);
|
||||
// props有formStore 说明是嵌套表单 || 不允许在表单的按钮组中再直接套表单
|
||||
if (formStore || isFormInFormActions) {
|
||||
if (formStore) {
|
||||
body = (
|
||||
<Alert level="danger">
|
||||
<p>Error: 不允许在表单及表单按钮组中直接嵌套表单</p>
|
||||
<p>Path: {$path}</p>
|
||||
<pre>
|
||||
<code>{JSON.stringify($schema, null, 2)}</code>
|
||||
</pre>
|
||||
</Alert>
|
||||
<>
|
||||
<Alert level="warning" showCloseButton>
|
||||
<p>{__('Form.nestedError')}</p>
|
||||
</Alert>
|
||||
{body}
|
||||
</>
|
||||
);
|
||||
} else if (wrapWithPanel) {
|
||||
}
|
||||
|
||||
if (wrapWithPanel) {
|
||||
body = render(
|
||||
'body',
|
||||
{
|
||||
@ -1541,6 +1540,7 @@ export default class Form extends React.Component<FormProps, object> {
|
||||
},
|
||||
{
|
||||
className: cx(panelClassName, 'Panel--form'),
|
||||
formStore: this.props.store,
|
||||
children: body,
|
||||
actions: this.buildActions(),
|
||||
onAction: this.handleAction,
|
||||
|
@ -98,6 +98,8 @@ export interface PanelProps
|
||||
export default class Panel extends React.Component<PanelProps> {
|
||||
static propsList: Array<string> = [
|
||||
'header',
|
||||
'actions',
|
||||
'children',
|
||||
'headerClassName',
|
||||
'footerClassName',
|
||||
'footerWrapClassName',
|
||||
|
@ -8,5 +8,5 @@ import useRootClose from 'react-overlays/useRootClose';
|
||||
export const RootClose = ({children, onRootClose, ...props}: any) => {
|
||||
const [rootElement, attachRef] = useState(null);
|
||||
useRootClose(rootElement, onRootClose, props);
|
||||
return children(attachRef);
|
||||
return typeof children === 'function' ? children(attachRef) : children;
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user