条件组合控件支持远程拉取 fields 配置 (#1758)

This commit is contained in:
liaoxuezhi 2021-04-08 13:37:28 +08:00 committed by GitHub
parent aaa554b893
commit c03c943ae6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 371 additions and 223 deletions

View File

@ -355,3 +355,23 @@ type Value = ValueGroup;
]
}
```
## 字段选项远程拉取
- 方式 1 配置 `source` 接口返回的数据对象 `data` 中存在 fields 变量即可。
- 方式 2 关联上下文变量如 `source: "${xxxxField}"`
```schema: scope="body"
{
"type": "form",
"controls": [
{
"type": "condition-builder",
"label": "条件组件",
"name": "conditions",
"description": "适合让用户自己拼查询条件,然后后端根据数据生成 query where",
"source": "/api/mock2/condition-fields?a=${a}&waitSeconds=2"
}
]
}
```

View File

@ -27,7 +27,7 @@ import {Api} from '../types';
import {LocaleProps, localeable} from '../locale';
import Spinner from './Spinner';
import {Option, Options} from '../Schema';
import {withRemoteOptions} from './WithRemoteOptions';
import {RemoteOptionsProps, withRemoteConfig} from './WithRemoteConfig';
export {Option, Options};
@ -1012,7 +1012,7 @@ export class Select extends React.Component<SelectProps, SelectState> {
}
}
const enhancedSelect = themeable(
const EnhancedSelect = themeable(
localeable(
uncontrollable(Select, {
value: 'onChange'
@ -1020,13 +1020,32 @@ const enhancedSelect = themeable(
)
);
export default enhancedSelect;
export const SelectWithRemoteOptions = withRemoteOptions(
enhancedSelect
) as React.ComponentType<
React.ComponentProps<typeof enhancedSelect> & {
source?: any;
options?: Options;
data?: any;
export default EnhancedSelect;
export const SelectWithRemoteOptions = withRemoteConfig<Array<Options>>({
adaptor: data => data.options || data.items || data.rows || data,
normalizeConfig: (options: any, origin) => {
options = normalizeOptions(options);
if (Array.isArray(options)) {
return options.concat();
}
return origin;
}
>;
})(
class extends React.Component<
RemoteOptionsProps<Array<Options>> &
React.ComponentProps<typeof EnhancedSelect>
> {
render() {
const {loading, config, ...rest} = this.props;
return (
<EnhancedSelect
{...rest}
options={config || rest.options || []}
loading={loading}
/>
);
}
}
);

View File

@ -0,0 +1,213 @@
/**
* HOC
*
*/
import React from 'react';
import hoistNonReactStatic from 'hoist-non-react-statics';
import {Api, Payload} from '../types';
import {SchemaApi, SchemaTokenizeableString} from '../Schema';
import {withStore} from './WithStore';
import {EnvContext, RendererEnv} from '../env';
import {flow, Instance, types} from 'mobx-state-tree';
import {buildApi, isEffectiveApi, normalizeApi} from '../utils/api';
import {
isPureVariable,
resolveVariableAndFilter,
tokenize
} from '../utils/tpl-builtin';
import {reaction} from 'mobx';
export const Store = types
.model('OptionsStore')
.props({
fetching: false,
errorMsg: '',
config: types.frozen(),
data: types.frozen({})
})
.actions(self => {
const load: (
env: RendererEnv,
api: Api,
data: any,
config: WithRemoteConfigSettings
) => Promise<any> = flow(function* (env, api, data, config = {}) {
try {
self.fetching = true;
const ret: Payload = yield env.fetcher(api, data);
if (ret.ok) {
const data = ret.data || {};
let options = config.adaptor ? config.adaptor(data) : data;
(self as any).setConfig(options, config);
} else {
throw new Error(ret.msg || 'fetch error');
}
} catch (e) {
self.errorMsg = e.message;
} finally {
self.fetching = false;
}
});
return {
load,
setData(data: any) {
self.data = data || {};
},
setConfig(options: any, config: WithRemoteConfigSettings) {
if (config.normalizeConfig) {
options = config.normalizeConfig(options, self.config) || options;
}
self.config = options;
}
};
});
export type IStore = Instance<typeof Store>;
export interface OutterProps {
env?: RendererEnv;
data: any;
source?: SchemaApi | SchemaTokenizeableString;
}
export interface RemoteOptionsProps<T = any> {
config: T;
loading?: boolean;
}
export interface WithRemoteConfigSettings {
configField?: string;
adaptor?: (json: any) => any;
normalizeConfig?: (config: any, origin: any) => any;
}
export function withRemoteConfig<P = any>(
config: WithRemoteConfigSettings = {}
) {
return function <
T extends React.ComponentType<
React.ComponentProps<T> & RemoteOptionsProps<P>
>
>(ComposedComponent: T) {
type FinalOutterProps = JSX.LibraryManagedAttributes<
T,
Omit<React.ComponentProps<T>, keyof RemoteOptionsProps<P>>
> &
OutterProps;
const result = hoistNonReactStatic(
withStore(() => Store.create())(
class extends React.Component<
FinalOutterProps & {
store: IStore;
}
> {
static displayName = `WithRemoteConfig(${
ComposedComponent.displayName || ComposedComponent.name
})`;
static ComposedComponent = ComposedComponent;
static contextType = EnvContext;
toDispose: Array<() => void> = [];
componentDidMount() {
const env: RendererEnv = this.props.env || this.context;
const {store, source, data} = this.props;
store.setData(data);
if (isPureVariable(source)) {
this.syncOptions();
this.toDispose.push(
reaction(
() =>
resolveVariableAndFilter(
source as string,
store.data,
'| raw'
),
() => this.syncOptions()
)
);
} else if (env && isEffectiveApi(source, data)) {
this.loadOptions();
this.toDispose.push(
reaction(
() => {
const api = normalizeApi(source as string);
return api.trackExpression
? tokenize(api.trackExpression, store.data)
: buildApi(api, store.data, {
ignoreData: true
}).url;
},
() => this.loadOptions()
)
);
}
}
componentDidUpdate(prevProps: any) {
const props = this.props;
if (props.data !== prevProps.data) {
props.store.setData(props.data);
}
}
componentWillUnmount() {
this.toDispose.forEach(fn => fn());
this.toDispose = [];
}
loadOptions() {
const env: RendererEnv = this.props.env || this.context;
const {store, source, data} = this.props;
if (env && isEffectiveApi(source, data)) {
store.load(env, source, data, config);
}
}
syncOptions() {
const {store, source, data} = this.props;
if (isPureVariable(source)) {
store.setConfig(
resolveVariableAndFilter(source as string, data, '| raw') || [],
config
);
}
}
render() {
const store = this.props.store;
const injectedProps: RemoteOptionsProps<P> = {
config: store.config,
loading: store.fetching
};
return (
<ComposedComponent
{...(this.props as JSX.LibraryManagedAttributes<
T,
React.ComponentProps<T>
>)}
{...injectedProps}
/>
);
}
}
),
ComposedComponent
);
return result as typeof result & {
ComposedComponent: T;
};
};
}

View File

@ -1,195 +0,0 @@
/**
*
*
* renderer/form/options
*
* hoc
*/
import React from 'react';
import hoistNonReactStatic from 'hoist-non-react-statics';
import {Api, Payload} from '../types';
import {Option, SchemaApi, SchemaTokenizeableString} from '../Schema';
import {withStore} from './WithStore';
import {EnvContext, RendererEnv} from '../env';
import {flow, Instance, types} from 'mobx-state-tree';
import {buildApi, isEffectiveApi} from '../utils/api';
import {isPureVariable, resolveVariableAndFilter} from '../utils/tpl-builtin';
import {normalizeOptions} from './Select';
import {reaction} from 'mobx';
export const Store = types
.model('OptionsStore')
.props({
fetching: false,
errorMsg: '',
options: types.frozen<Array<Option>>([]),
data: types.frozen({})
})
.actions(self => {
const load: (env: RendererEnv, api: Api, data: any) => Promise<any> = flow(
function* (env, api, data) {
try {
self.fetching = true;
const ret: Payload = yield env.fetcher(api, data);
if (ret.ok) {
const data = ret.data || {};
let options = data.options || data.items || data.rows || data;
(self as any).setOptions(options);
} else {
throw new Error(ret.msg || 'fetch error');
}
} catch (e) {
self.errorMsg = e.message;
} finally {
self.fetching = false;
}
}
);
return {
load,
setData(data: any) {
self.data = data || {};
},
setOptions(options: any) {
options = normalizeOptions(options);
if (Array.isArray(options)) {
self.options = options.concat();
}
}
};
});
export type IStore = Instance<typeof Store>;
export interface RemoteOptionsProps {
options: Array<Option>;
loading?: boolean;
}
export interface OutterProps {
env?: RendererEnv;
data: any;
source?: SchemaApi | SchemaTokenizeableString;
options?: Array<Option>;
}
export function withRemoteOptions<
T extends React.ComponentType<React.ComponentProps<T> & RemoteOptionsProps>
>(ComposedComponent: T) {
type FinalOutterProps = JSX.LibraryManagedAttributes<
T,
Omit<React.ComponentProps<T>, keyof RemoteOptionsProps>
> &
OutterProps;
const result = hoistNonReactStatic(
withStore(() => Store.create())(
class extends React.Component<
FinalOutterProps & {
store: IStore;
}
> {
static displayName = `WithRemoteOptions(${
ComposedComponent.displayName || ComposedComponent.name
})`;
static ComposedComponent = ComposedComponent;
static contextType = EnvContext;
toDispose: Array<() => void> = [];
componentDidMount() {
const env: RendererEnv = this.props.env || this.context;
const {store, source, data, options} = this.props;
store.setData(data);
options && store.setOptions(options);
if (isPureVariable(source)) {
this.syncOptions();
this.toDispose.push(
reaction(
() =>
resolveVariableAndFilter(
source as string,
store.data,
'| raw'
),
() => this.syncOptions()
)
);
} else if (env && isEffectiveApi(source, data)) {
this.loadOptions();
this.toDispose.push(
reaction(
() =>
buildApi(source as string, store.data, {
ignoreData: true
}).url,
() => this.loadOptions()
)
);
}
}
componentDidUpdate(prevProps: any) {
const props = this.props;
if (props.data !== prevProps.data) {
props.store.setData(props.data);
}
}
componentWillUnmount() {
this.toDispose.forEach(fn => fn());
this.toDispose = [];
}
loadOptions() {
const env: RendererEnv = this.props.env || this.context;
const {store, source, data, options} = this.props;
if (env && isEffectiveApi(source, data)) {
store.load(env, source, data);
}
}
syncOptions() {
const {store, source, data} = this.props;
if (isPureVariable(source)) {
store.setOptions(
resolveVariableAndFilter(source as string, data, '| raw') || []
);
}
}
render() {
const store = this.props.store;
const injectedProps: RemoteOptionsProps = {
options: store.options,
loading: store.fetching
};
return (
<ComposedComponent
{...(this.props as JSX.LibraryManagedAttributes<
T,
React.ComponentProps<T>
>)}
{...injectedProps}
/>
);
}
}
),
ComposedComponent
);
return result as typeof result & {
ComposedComponent: T;
};
}

View File

@ -40,6 +40,7 @@ export interface ExpressionProps extends ThemeProps {
allowedTypes?: Array<'value' | 'field' | 'func' | 'formula'>;
op?: OperatorType;
config: Config;
disabled?: boolean;
}
const fieldMap = {
@ -126,7 +127,8 @@ export class Expression extends React.Component<ExpressionProps> {
op,
classnames: cx,
config,
data
data,
disabled
} = this.props;
const inputType =
((value as any)?.type === 'field'
@ -156,6 +158,7 @@ export class Expression extends React.Component<ExpressionProps> {
onChange={this.handleValueChange}
op={op}
data={data}
disabled={disabled}
/>
) : null}
@ -163,6 +166,7 @@ export class Expression extends React.Component<ExpressionProps> {
<ConditionField
value={(value as any)?.field}
onChange={this.handleFieldChange}
disabled={disabled}
options={
valueField
? filterTree(
@ -184,6 +188,7 @@ export class Expression extends React.Component<ExpressionProps> {
funcs={funcs}
fields={fields}
allowedTypes={allowedTypes}
disabled={disabled}
/>
) : null}
@ -191,11 +196,13 @@ export class Expression extends React.Component<ExpressionProps> {
<Formula
value={(value as any)?.value}
onChange={this.handleFormulaChange}
disabled={disabled}
/>
) : null}
{types.length > 1 ? (
<InputSwitch
disabled={disabled}
value={inputType}
onChange={this.handleInputTypeChange}
options={types.map(item => ({

View File

@ -10,6 +10,7 @@ export interface ConditionFieldProps extends ThemeProps {
options: Array<any>;
value: any;
onChange: (value: any) => void;
disabled?: boolean;
}
const option2value = (item: any) => item.name;
@ -18,7 +19,8 @@ export function ConditionField({
options,
onChange,
value,
classnames: cx
classnames: cx,
disabled
}: ConditionFieldProps) {
return (
<PopOverContainer
@ -45,6 +47,7 @@ export function ConditionField({
onResultChange={noop}
onResultClick={onClick}
placeholder="请选择字段"
disabled={disabled}
>
<span className={cx('CBGroup-fieldCaret')}>
<Icon icon="caret" className="icon" />

View File

@ -5,15 +5,17 @@ import InputBox from '../InputBox';
export interface FormulaProps extends ThemeProps {
value: any;
onChange: (value: any) => void;
disabled?: boolean;
}
export class Formula extends React.Component<FormulaProps> {
render() {
const {classnames: cx, value, onChange} = this.props;
const {classnames: cx, value, onChange, disabled} = this.props;
return (
<div className={cx('CBFormula')}>
<InputBox
disabled={disabled}
value={value}
onChange={onChange}
placeholder="请输入公式"

View File

@ -12,6 +12,7 @@ import {Config} from './config';
export interface ConditionFuncProps extends ThemeProps {
value: ExpressionFunc;
onChange: (value: ExpressionFunc) => void;
disabled?: boolean;
config: Config;
fields?: Field[];
funcs?: Funcs;
@ -37,7 +38,7 @@ export class ConditionFunc extends React.Component<ConditionFuncProps> {
}
renderFunc(func: Func) {
const {classnames: cx, fields, value, funcs, config} = this.props;
const {classnames: cx, fields, value, funcs, config, disabled} = this.props;
return (
<div className={cx('CBFunc-args')}>
@ -54,6 +55,7 @@ export class ConditionFunc extends React.Component<ConditionFuncProps> {
valueField={{type: item.type} as any}
onChange={this.handleArgChange}
funcs={funcs}
disabled={disabled}
// allowedTypes={allowedTypes}
/>
))}
@ -65,7 +67,7 @@ export class ConditionFunc extends React.Component<ConditionFuncProps> {
}
render() {
const {value, classnames: cx, funcs} = this.props;
const {value, classnames: cx, funcs, disabled} = this.props;
const func = value
? findTree(funcs!, item => (item as Func).type === value.func)
: null;
@ -97,6 +99,7 @@ export class ConditionFunc extends React.Component<ConditionFuncProps> {
onResultChange={noop}
onResultClick={onClick}
placeholder="请选择字段"
disabled={disabled}
>
<span className={cx('CBGroup-fieldCaret')}>
<Icon icon="caret" className="icon" />

View File

@ -14,6 +14,7 @@ export interface ConditionGroupProps extends ThemeProps {
funcs?: Funcs;
showNot?: boolean;
data?: any;
disabled?: boolean;
onChange: (value: ConditionGroupValue) => void;
removeable?: boolean;
onRemove?: (e: React.MouseEvent) => void;
@ -119,7 +120,8 @@ export class ConditionGroup extends React.Component<ConditionGroupProps> {
removeable,
onRemove,
onDragStart,
showNot
showNot,
disabled
} = this.props;
return (
@ -133,6 +135,7 @@ export class ConditionGroup extends React.Component<ConditionGroupProps> {
size="xs"
active={value?.not}
level={value?.not ? 'info' : 'default'}
disabled={disabled}
>
</Button>
@ -143,6 +146,7 @@ export class ConditionGroup extends React.Component<ConditionGroupProps> {
onClick={this.handleConjunctionClick}
active={value?.conjunction !== 'or'}
level={value?.conjunction !== 'or' ? 'info' : 'default'}
disabled={disabled}
>
</Button>
@ -151,6 +155,7 @@ export class ConditionGroup extends React.Component<ConditionGroupProps> {
onClick={this.handleConjunctionClick}
active={value?.conjunction === 'or'}
level={value?.conjunction === 'or' ? 'info' : 'default'}
disabled={disabled}
>
</Button>
@ -158,11 +163,15 @@ export class ConditionGroup extends React.Component<ConditionGroupProps> {
</div>
<div className={cx('CBGroup-toolbarConditionAdd')}>
<div className={cx('ButtonGroup')}>
<Button onClick={this.handleAdd} size="xs">
<Button onClick={this.handleAdd} size="xs" disabled={disabled}>
<Icon icon="plus" className="icon" />
</Button>
<Button onClick={this.handleAddGroup} size="xs">
<Button
onClick={this.handleAddGroup}
size="xs"
disabled={disabled}
>
<Icon icon="plus-cicle" className="icon" />
</Button>
@ -190,6 +199,7 @@ export class ConditionGroup extends React.Component<ConditionGroupProps> {
funcs={funcs}
onRemove={this.handleItemRemove}
data={data}
disabled={disabled}
/>
))
) : (

View File

@ -15,6 +15,7 @@ export interface CBGroupOrItemProps extends ThemeProps {
index: number;
data?: any;
draggable?: boolean;
disabled?: boolean;
onChange: (value: ConditionGroupValue, index: number) => void;
removeable?: boolean;
onDragStart?: (e: React.MouseEvent) => void;
@ -41,6 +42,7 @@ export class CBGroupOrItem extends React.Component<CBGroupOrItemProps> {
funcs,
draggable,
data,
disabled,
onDragStart
} = this.props;
@ -59,6 +61,7 @@ export class CBGroupOrItem extends React.Component<CBGroupOrItemProps> {
{value?.conjunction ? (
<ConditionGroup
disabled={disabled}
onDragStart={onDragStart}
config={config}
fields={fields}
@ -72,6 +75,7 @@ export class CBGroupOrItem extends React.Component<CBGroupOrItemProps> {
) : (
<>
<ConditionItem
disabled={disabled}
config={config}
fields={fields}
value={value as ConditionValue}

View File

@ -6,6 +6,7 @@ import {ClassNamesFn, themeable, ThemeProps} from '../../theme';
export interface InputSwitchProps extends ThemeProps {
options: Array<any>;
disabled?: boolean;
value: any;
onChange: (value: any) => void;
}
@ -16,7 +17,8 @@ export function InputSwitch({
options,
value,
onChange,
classnames: cx
classnames: cx,
disabled
}: InputSwitchProps) {
return (
<PopOverContainer
@ -28,6 +30,7 @@ export function InputSwitch({
options={options}
value={value}
showRadio={false}
disabled={disabled}
/>
)}
>

View File

@ -30,6 +30,7 @@ export interface ConditionItemProps extends ThemeProps {
index?: number;
value: ConditionRule;
data?: any;
disabled?: boolean;
onChange: (value: ConditionRule, index?: number) => void;
}
@ -96,7 +97,7 @@ export class ConditionItem extends React.Component<ConditionItemProps> {
}
renderLeft() {
const {value, fields, funcs, config} = this.props;
const {value, fields, funcs, config, disabled} = this.props;
return (
<Expression
@ -105,6 +106,7 @@ export class ConditionItem extends React.Component<ConditionItemProps> {
value={value.left}
onChange={this.handleLeftChange}
fields={fields}
disabled={disabled}
allowedTypes={
['field', 'func'].filter(
type => type === 'field' || type === 'func'
@ -115,7 +117,7 @@ export class ConditionItem extends React.Component<ConditionItemProps> {
}
renderOperator() {
const {funcs, config, fields, value, classnames: cx} = this.props;
const {funcs, config, fields, value, classnames: cx, disabled} = this.props;
const left = value?.left;
let operators: Array<string> = [];
@ -168,6 +170,7 @@ export class ConditionItem extends React.Component<ConditionItemProps> {
result={OperationMap[value?.op as keyof typeof OperationMap]}
onResultChange={noop}
onResultClick={onClick}
disabled={disabled}
placeholder="请选择操作"
>
<span className={cx('CBGroup-operatorCaret')}>
@ -221,7 +224,15 @@ export class ConditionItem extends React.Component<ConditionItemProps> {
}
renderRightWidgets(type: string, op: OperatorType) {
const {funcs, value, data, fields, config, classnames: cx} = this.props;
const {
funcs,
value,
data,
fields,
config,
classnames: cx,
disabled
} = this.props;
let field = {
...config.types[type],
type
@ -258,6 +269,7 @@ export class ConditionItem extends React.Component<ConditionItemProps> {
field?.valueTypes ||
config.valueTypes || ['value', 'field', 'func', 'formula']
}
disabled={disabled}
/>
<span className={cx('CBSeprator')}>~</span>
@ -274,6 +286,7 @@ export class ConditionItem extends React.Component<ConditionItemProps> {
field?.valueTypes ||
config.valueTypes || ['value', 'field', 'func', 'formula']
}
disabled={disabled}
/>
</>
);
@ -293,6 +306,7 @@ export class ConditionItem extends React.Component<ConditionItemProps> {
field?.valueTypes ||
config.valueTypes || ['value', 'field', 'func', 'formula']
}
disabled={disabled}
/>
);
}

View File

@ -14,6 +14,7 @@ export interface ValueProps extends ThemeProps, LocaleProps {
onChange: (value: any) => void;
field: FieldSimple;
op?: OperatorType;
disabled?: boolean;
}
export class Value extends React.Component<ValueProps> {
@ -25,7 +26,8 @@ export class Value extends React.Component<ValueProps> {
onChange,
op,
translate: __,
data
data,
disabled
} = this.props;
let input: JSX.Element | undefined = undefined;
@ -35,6 +37,7 @@ export class Value extends React.Component<ValueProps> {
value={value ?? field.defaultValue}
onChange={onChange}
placeholder={field.placeholder}
disabled={disabled}
/>
);
} else if (field.type === 'number') {
@ -47,6 +50,7 @@ export class Value extends React.Component<ValueProps> {
precision={field.precision}
value={value ?? field.defaultValue}
onChange={onChange}
disabled={disabled}
/>
);
} else if (field.type === 'date') {
@ -58,6 +62,7 @@ export class Value extends React.Component<ValueProps> {
value={value ?? field.defaultValue}
onChange={onChange}
timeFormat=""
disabled={disabled}
/>
);
} else if (field.type === 'time') {
@ -71,6 +76,7 @@ export class Value extends React.Component<ValueProps> {
onChange={onChange}
dateFormat=""
timeFormat={field.format || 'HH:mm'}
disabled={disabled}
/>
);
} else if (field.type === 'datetime') {
@ -82,6 +88,7 @@ export class Value extends React.Component<ValueProps> {
value={value ?? field.defaultValue}
onChange={onChange}
timeFormat={field.timeFormat || 'HH:mm'}
disabled={disabled}
/>
);
} else if (field.type === 'select') {
@ -95,11 +102,16 @@ export class Value extends React.Component<ValueProps> {
data={data}
onChange={onChange}
multiple={op === 'select_any_in' || op === 'select_not_any_in'}
disabled={disabled}
/>
);
} else if (field.type === 'boolean') {
input = (
<Switch value={value ?? field.defaultValue} onChange={onChange} />
<Switch
value={value ?? field.defaultValue}
onChange={onChange}
disabled={disabled}
/>
);
}

View File

@ -24,6 +24,7 @@ export interface ConditionBuilderProps extends ThemeProps, LocaleProps {
data?: any;
onChange: (value: ConditionGroupValue) => void;
config?: Config;
disabled?: boolean;
}
export class QueryBuilder extends React.Component<ConditionBuilderProps> {
@ -197,7 +198,8 @@ export class QueryBuilder extends React.Component<ConditionBuilderProps> {
onChange,
value,
showNot,
data
data,
disabled
} = this.props;
const normalizedValue = Array.isArray(value?.children)
@ -228,6 +230,7 @@ export class QueryBuilder extends React.Component<ConditionBuilderProps> {
onDragStart={this.handleDragStart}
showNot={showNot}
data={data}
disabled={disabled}
/>
);
}

View File

@ -4,6 +4,11 @@ import ColorPicker from '../../components/ColorPicker';
import {Funcs, Fields} from '../../components/condition-builder/types';
import {Config} from '../../components/condition-builder/config';
import ConditionBuilder from '../../components/condition-builder/index';
import {SchemaApi, SchemaTokenizeableString} from '../../Schema';
import {
RemoteOptionsProps,
withRemoteConfig
} from '../../components/WithRemoteConfig';
/**
*
@ -29,6 +34,11 @@ export interface ConditionBuilderControlSchema extends FormBaseControl {
*
*/
config?: Config;
/**
*
*/
source?: SchemaApi | SchemaTokenizeableString;
}
export interface ConditionBuilderProps
@ -44,13 +54,33 @@ export default class ConditionBuilderControl extends React.PureComponent<Conditi
return (
<div className={cx(`ConditionBuilderControl`, className)}>
<ConditionBuilder {...rest} />
<ConditionBuilderWithRemoteOptions {...rest} />
</div>
);
}
}
const ConditionBuilderWithRemoteOptions = withRemoteConfig({
adaptor: data => data.fields || data
})(
class extends React.Component<
RemoteOptionsProps & React.ComponentProps<typeof ConditionBuilder>
> {
render() {
const {loading, config, ...rest} = this.props;
return (
<ConditionBuilder
{...rest}
fields={config || rest.fields}
disabled={loading}
/>
);
}
}
);
@FormItem({
type: 'condition-builder'
type: 'condition-builder',
strictMode: false
})
export class ConditionBuilderRenderer extends ConditionBuilderControl {}