mirror of
https://gitee.com/nocobase/nocobase.git
synced 2024-12-05 21:57:45 +08:00
fix(variable-input): fix style (#1761)
* fix(variable-input): fix style * refactor: avoid lint error * feat: add invariable * fix: fix the default value variable of the expression is empty
This commit is contained in:
parent
9101bbbb1b
commit
95e4e7e7b0
@ -175,4 +175,5 @@ export const linkTo: IField = {
|
||||
// },
|
||||
],
|
||||
},
|
||||
invariable: true,
|
||||
};
|
||||
|
@ -282,4 +282,5 @@ export const m2m: IField = {
|
||||
// },
|
||||
],
|
||||
},
|
||||
invariable: true,
|
||||
};
|
||||
|
@ -214,4 +214,5 @@ export const m2o: IField = {
|
||||
// },
|
||||
],
|
||||
},
|
||||
invariable: true,
|
||||
};
|
||||
|
@ -273,4 +273,5 @@ export const o2m: IField = {
|
||||
// },
|
||||
],
|
||||
},
|
||||
invariable: true,
|
||||
};
|
||||
|
@ -252,6 +252,7 @@ export const o2o: IField = {
|
||||
// },
|
||||
],
|
||||
},
|
||||
invariable: true,
|
||||
};
|
||||
|
||||
export const oho: IField = {
|
||||
@ -422,6 +423,7 @@ export const oho: IField = {
|
||||
// },
|
||||
],
|
||||
},
|
||||
invariable: true,
|
||||
};
|
||||
|
||||
export const obo: IField = {
|
||||
@ -605,4 +607,5 @@ export const obo: IField = {
|
||||
// },
|
||||
],
|
||||
},
|
||||
invariable: true,
|
||||
};
|
||||
|
@ -10,5 +10,7 @@ export interface IField extends ISchema {
|
||||
default?: IDefault;
|
||||
operators?: any[];
|
||||
filterable?: any;
|
||||
/** 不支持使用变量的值进行设置 */
|
||||
invariable?: boolean;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
@ -18,9 +18,16 @@ import { SchemaComponent } from '../../core';
|
||||
import { useCompile, useDesignable, useFieldComponentOptions } from '../../hooks';
|
||||
import { BlockItem } from '../block-item';
|
||||
import { HTMLEncode } from '../input/shared';
|
||||
import { isInvariable } from '../variable';
|
||||
import { FilterFormDesigner } from './FormItem.FilterFormDesigner';
|
||||
import { useEnsureOperatorsValid } from './SchemaSettingOptions';
|
||||
|
||||
const defaultInputStyle = css`
|
||||
& > .nb-form-item {
|
||||
flex: 1;
|
||||
}
|
||||
`;
|
||||
|
||||
const divWrap = (schema: ISchema) => {
|
||||
return {
|
||||
type: 'void',
|
||||
@ -420,8 +427,7 @@ FormItem.Designer = function Designer() {
|
||||
type: 'object',
|
||||
title: t('Set default value'),
|
||||
properties: {
|
||||
// 关系字段不支持设置变量
|
||||
default: collectionField?.target
|
||||
default: isInvariable(interfaceConfig)
|
||||
? {
|
||||
...(fieldSchema || {}),
|
||||
'x-decorator': 'FormItem',
|
||||
@ -434,6 +440,12 @@ FormItem.Designer = function Designer() {
|
||||
service: {
|
||||
resource: collectionField?.target,
|
||||
},
|
||||
// for DynamicExpression
|
||||
sourceCollection: form?.values.sourceCollection,
|
||||
style: {
|
||||
width: '100%',
|
||||
verticalAlign: 'top',
|
||||
},
|
||||
},
|
||||
name: 'default',
|
||||
title: t('Default value'),
|
||||
@ -447,6 +459,7 @@ FormItem.Designer = function Designer() {
|
||||
...(fieldSchema?.['x-component-props'] || {}),
|
||||
collectionName: collectionField?.collectionName,
|
||||
schema: collectionField?.uiSchema,
|
||||
className: defaultInputStyle,
|
||||
renderSchemaComponent: function Com(props) {
|
||||
const s = _.cloneDeep(fieldSchema) || ({} as Schema);
|
||||
s.title = '';
|
||||
@ -464,6 +477,7 @@ FormItem.Designer = function Designer() {
|
||||
defaultValue: getFieldDefaultValue(s, collectionField),
|
||||
style: {
|
||||
width: '100%',
|
||||
verticalAlign: 'top',
|
||||
},
|
||||
},
|
||||
}}
|
||||
|
@ -6,6 +6,7 @@ import moment from 'moment';
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import classNames from 'classnames';
|
||||
import { useCompile } from '../..';
|
||||
import { XButton } from './XButton';
|
||||
|
||||
@ -51,7 +52,7 @@ const ConstantTypes = {
|
||||
boolean: {
|
||||
label: `{{t("Boolean")}}`,
|
||||
value: 'boolean',
|
||||
component({ onChange, value }) {
|
||||
component: function Com({ onChange, value }) {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<Select
|
||||
@ -88,7 +89,7 @@ const ConstantTypes = {
|
||||
null: {
|
||||
label: `{{t("Null")}}`,
|
||||
value: 'null',
|
||||
component() {
|
||||
component: function Com() {
|
||||
const { t } = useTranslation();
|
||||
return <AntInput readOnly placeholder={t('Null')} className="null-value" />;
|
||||
},
|
||||
@ -115,12 +116,12 @@ export function Input(props) {
|
||||
const compile = useCompile();
|
||||
const form = useForm();
|
||||
|
||||
const { value = '', scope, onChange, children, button, useTypedConstant, style } = props;
|
||||
const { value = '', scope, onChange, children, button, useTypedConstant, style, className } = props;
|
||||
const parsed = parseValue(value);
|
||||
const isConstant = typeof parsed === 'string';
|
||||
const type = isConstant ? parsed : '';
|
||||
const variable = isConstant ? null : parsed;
|
||||
const varialbeOptions = typeof scope === 'function' ? scope() : scope ?? [];
|
||||
const variableOptions = typeof scope === 'function' ? scope() : scope ?? [];
|
||||
|
||||
const { component: ConstantComponent, ...constantOption }: VariableOptions & { component?: React.FC<any> } = children
|
||||
? {
|
||||
@ -134,7 +135,7 @@ export function Input(props) {
|
||||
label: '{{t("Null")}}',
|
||||
component: ConstantTypes.null.component,
|
||||
};
|
||||
const options: VariableOptions[] = compile([constantOption, ...varialbeOptions]);
|
||||
const options: VariableOptions[] = compile([constantOption, ...variableOptions]);
|
||||
|
||||
function onSwitch(next) {
|
||||
if (next[0] === '') {
|
||||
@ -166,86 +167,88 @@ export function Input(props) {
|
||||
<AntInput.Group
|
||||
compact
|
||||
style={style}
|
||||
className={css`
|
||||
width: auto;
|
||||
display: flex !important;
|
||||
.ant-input-disabled {
|
||||
.ant-tag {
|
||||
color: #bfbfbf;
|
||||
border-color: #d9d9d9;
|
||||
className={classNames(
|
||||
className,
|
||||
css`
|
||||
width: auto;
|
||||
display: flex !important;
|
||||
.ant-input-disabled {
|
||||
.ant-tag {
|
||||
color: #bfbfbf;
|
||||
border-color: #d9d9d9;
|
||||
}
|
||||
}
|
||||
}
|
||||
.ant-input.null-value {
|
||||
width: 4em;
|
||||
min-width: 4em;
|
||||
}
|
||||
`}
|
||||
.ant-input.null-value {
|
||||
width: 4em;
|
||||
min-width: 4em;
|
||||
}
|
||||
`,
|
||||
)}
|
||||
>
|
||||
<div style={{ flex: 1 }}>
|
||||
{variable ? (
|
||||
{variable ? (
|
||||
<div
|
||||
className={css`
|
||||
position: relative;
|
||||
line-height: 0;
|
||||
|
||||
&:hover {
|
||||
.ant-select-clear {
|
||||
opacity: 0.8;
|
||||
}
|
||||
}
|
||||
|
||||
.ant-input {
|
||||
overflow: auto;
|
||||
white-space: nowrap;
|
||||
${disabled ? '' : 'padding-right: 28px;'}
|
||||
|
||||
.ant-tag {
|
||||
display: inline;
|
||||
line-height: 19px;
|
||||
margin: 0;
|
||||
padding: 2px 7px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
}
|
||||
`}
|
||||
>
|
||||
<div
|
||||
className={css`
|
||||
position: relative;
|
||||
line-height: 0;
|
||||
|
||||
&:hover {
|
||||
.ant-select-clear {
|
||||
opacity: 0.8;
|
||||
}
|
||||
onInput={(e) => e.preventDefault()}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key !== 'Backspace') {
|
||||
e.preventDefault();
|
||||
return;
|
||||
}
|
||||
|
||||
.ant-input {
|
||||
overflow: auto;
|
||||
white-space: nowrap;
|
||||
${disabled ? '' : 'padding-right: 28px;'}
|
||||
|
||||
.ant-tag {
|
||||
display: inline;
|
||||
line-height: 19px;
|
||||
margin: 0;
|
||||
padding: 2px 7px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
}
|
||||
`}
|
||||
onChange(null);
|
||||
}}
|
||||
className={cx('ant-input', { 'ant-input-disabled': disabled })}
|
||||
contentEditable={!disabled}
|
||||
suppressContentEditableWarning
|
||||
>
|
||||
<div
|
||||
onInput={(e) => e.preventDefault()}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key !== 'Backspace') {
|
||||
e.preventDefault();
|
||||
return;
|
||||
}
|
||||
onChange(null);
|
||||
}}
|
||||
className={cx('ant-input', { 'ant-input-disabled': disabled })}
|
||||
contentEditable={!disabled}
|
||||
suppressContentEditableWarning
|
||||
>
|
||||
<Tag contentEditable={false} color="blue">
|
||||
{variableText}
|
||||
</Tag>
|
||||
</div>
|
||||
{!disabled ? (
|
||||
<span
|
||||
className={cx(
|
||||
'ant-select-clear',
|
||||
css`
|
||||
user-select: 'none';
|
||||
`,
|
||||
)}
|
||||
unselectable="on"
|
||||
aria-hidden
|
||||
onClick={() => onChange(null)}
|
||||
>
|
||||
<CloseCircleFilled />
|
||||
</span>
|
||||
) : null}
|
||||
<Tag contentEditable={false} color="blue">
|
||||
{variableText}
|
||||
</Tag>
|
||||
</div>
|
||||
) : (
|
||||
children ?? <ConstantComponent value={value} onChange={onChange} />
|
||||
)}
|
||||
</div>
|
||||
{!disabled ? (
|
||||
<span
|
||||
className={cx(
|
||||
'ant-select-clear',
|
||||
css`
|
||||
user-select: 'none';
|
||||
`,
|
||||
)}
|
||||
// eslint-disable-next-line react/no-unknown-property
|
||||
unselectable="on"
|
||||
aria-hidden
|
||||
onClick={() => onChange(null)}
|
||||
>
|
||||
<CloseCircleFilled />
|
||||
</span>
|
||||
) : null}
|
||||
</div>
|
||||
) : (
|
||||
children ?? <ConstantComponent value={value} onChange={onChange} />
|
||||
)}
|
||||
{options.length > 1 ? (
|
||||
<Cascader
|
||||
options={options}
|
||||
|
@ -1,8 +1,9 @@
|
||||
import { connect, mapReadPretty } from '@formily/react';
|
||||
|
||||
import { IField } from '../../../collection-manager';
|
||||
import { Input } from './Input';
|
||||
import { TextArea } from './TextArea';
|
||||
import { JSONInput } from './JSONInput';
|
||||
import { TextArea } from './TextArea';
|
||||
|
||||
export function Variable() {
|
||||
return null;
|
||||
@ -15,3 +16,7 @@ Variable.TextArea = connect(TextArea, mapReadPretty(TextArea.ReadPretty));
|
||||
Variable.JSON = connect(JSONInput);
|
||||
|
||||
export default Variable;
|
||||
|
||||
export function isInvariable(value: IField) {
|
||||
return !!value?.invariable;
|
||||
}
|
||||
|
@ -7,14 +7,15 @@ type Props = {
|
||||
onChange: (value: any) => void;
|
||||
collectionName: string;
|
||||
renderSchemaComponent?: (props: any) => any;
|
||||
style: React.CSSProperties;
|
||||
schema: any;
|
||||
operator: any;
|
||||
children: any;
|
||||
children?: any;
|
||||
className?: string;
|
||||
style?: React.CSSProperties;
|
||||
};
|
||||
|
||||
export const VariableInput = (props: Props) => {
|
||||
const { value, onChange, renderSchemaComponent: RenderSchemaComponent, style, schema } = props;
|
||||
const { value, onChange, renderSchemaComponent: RenderSchemaComponent, style, schema, className } = props;
|
||||
const compile = useCompile();
|
||||
const userVariable = useUserVariable({ schema, level: 1 });
|
||||
const scope = useMemo(() => {
|
||||
@ -37,7 +38,7 @@ export const VariableInput = (props: Props) => {
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Variable.Input value={value} onChange={onChange} scope={scope} style={style}>
|
||||
<Variable.Input className={className} value={value} onChange={onChange} scope={scope} style={style}>
|
||||
<RenderSchemaComponent value={value} onChange={onChange} />
|
||||
</Variable.Input>
|
||||
);
|
||||
|
@ -1,7 +1,7 @@
|
||||
import React, { useState, useMemo } from 'react';
|
||||
import { onFieldInputValueChange, onFormInitialValuesChange } from '@formily/core';
|
||||
import { useForm, observer, connect, mapReadPretty, useFormEffects } from '@formily/react';
|
||||
import { connect, mapReadPretty, observer, useForm, useFormEffects } from '@formily/react';
|
||||
import { Tag } from 'antd';
|
||||
import React, { useMemo, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { useRecord, Variable } from '@nocobase/client';
|
||||
@ -10,7 +10,7 @@ import { NAMESPACE } from '../locale';
|
||||
import { useCollectionFieldOptions } from '../variable';
|
||||
|
||||
const InternalExpression = observer((props: any) => {
|
||||
const { onChange } = props;
|
||||
const { onChange, sourceCollection } = props;
|
||||
const { values } = useForm();
|
||||
const [collection, setCollection] = useState(values?.sourceCollection);
|
||||
|
||||
@ -24,17 +24,18 @@ const InternalExpression = observer((props: any) => {
|
||||
});
|
||||
});
|
||||
|
||||
const options = useCollectionFieldOptions({ collection });
|
||||
const options = useCollectionFieldOptions({ collection: sourceCollection || collection });
|
||||
|
||||
return <Variable.TextArea {...props} scope={options} />;
|
||||
});
|
||||
|
||||
function Result(props) {
|
||||
const { sourceCollection } = props;
|
||||
const { t } = useTranslation();
|
||||
const values = useRecord();
|
||||
const options = useMemo(
|
||||
() => useCollectionFieldOptions({ collection: values.sourceCollection }),
|
||||
[values.sourceCollection, values.sourceCollection],
|
||||
() => useCollectionFieldOptions({ collection: sourceCollection || values.sourceCollection }),
|
||||
[values.sourceCollection, values.sourceCollection, sourceCollection],
|
||||
);
|
||||
return props.value ? (
|
||||
<Variable.TextArea {...props} scope={options} />
|
||||
|
@ -21,4 +21,5 @@ export default {
|
||||
properties: {
|
||||
...defaultProps,
|
||||
},
|
||||
invariable: true,
|
||||
} as IField;
|
||||
|
Loading…
Reference in New Issue
Block a user