UNPKG

@coocoon/react-awesome-query-builder

Version:

User-friendly query builder for React. Demo: https://ukrbublik.github.io/react-awesome-query-builder

252 lines (220 loc) 7.48 kB
import React, { PureComponent } from "react"; import PropTypes from "prop-types"; import FuncSelect from "./FuncSelect"; import { getFuncConfig } from "../../utils/configUtils"; import Widget from "./Widget"; import {Col} from "../utils"; import {setFunc, setArgValue, setArgValueSrc} from "../../utils/funcUtils"; import {useOnPropsChanged} from "../../utils/reactUtils"; export default class FuncWidget extends PureComponent { static propTypes = { id: PropTypes.string, groupId: PropTypes.string, config: PropTypes.object.isRequired, field: PropTypes.string.isRequired, operator: PropTypes.string, customProps: PropTypes.object, value: PropTypes.object, //instanceOf(Immutable.Map) //with keys 'func' and `args` setValue: PropTypes.func.isRequired, readonly: PropTypes.bool, parentFuncs: PropTypes.array, }; constructor(props) { super(props); useOnPropsChanged(this); this.onPropsChanged(props); } onPropsChanged(nextProps) { const prevProps = this.props; const keysForMeta = ["config", "field", "operator", "value"]; const needUpdateMeta = !this.meta || keysForMeta.map(k => (nextProps[k] !== prevProps[k])).filter(ch => ch).length > 0; if (needUpdateMeta) { this.meta = this.getMeta(nextProps); } } getMeta({config, field, operator, value}) { const funcKey = value ? value.get("func") : null; const funcDefinition = funcKey ? getFuncConfig(config, funcKey) : null; return { funcDefinition, funcKey }; } setFunc = (funcKey) => { this.props.setValue( setFunc(this.props.value, funcKey, this.props.config) ); }; setArgValue = (argKey, argVal) => { const {config} = this.props; const {funcDefinition} = this.meta; const {args} = funcDefinition; const argDefinition = args[argKey]; this.props.setValue( setArgValue(this.props.value, argKey, argVal, argDefinition, config) ); }; setArgValueSrc = (argKey, argValSrc) => { const {config} = this.props; const {funcDefinition} = this.meta; const {args} = funcDefinition; const argDefinition = args[argKey]; this.props.setValue( setArgValueSrc(this.props.value, argKey, argValSrc, argDefinition, config) ); }; renderFuncSelect = () => { const {config, field, operator, customProps, value, readonly, parentFuncs, id, groupId} = this.props; const funcKey = value ? value.get("func") : null; const selectProps = { value: funcKey, setValue: this.setFunc, config, field, operator, customProps, readonly, parentFuncs, id, groupId, }; const {showLabels, funcLabel} = config.settings; const widgetLabel = showLabels ? <label className="rule--label">{funcLabel}</label> : null; return ( <Col key="func" className="rule--func"> {widgetLabel} <FuncSelect {...selectProps} /> </Col> ); }; renderArgLabel = (argKey, argDefinition) => { const {valueSources, type, showPrefix, label} = argDefinition; const {config} = this.props; const isConst = valueSources && valueSources.length == 1 && valueSources[0] == "const"; const forceShow = !config.settings.showLabels && (type == "boolean" || isConst) && showPrefix; if (!forceShow) return null; return ( <Col className="rule--func--arg-label"> {label || argKey} </Col> ); }; renderArgLabelSep = (argKey, argDefinition) => { const {valueSources, type, showPrefix} = argDefinition; const {config} = this.props; const isConst = valueSources && valueSources.length == 1 && valueSources[0] == "const"; const forceShow = !config.settings.showLabels && (type == "boolean" || isConst) && showPrefix; if (!forceShow) return null; return ( <Col className="rule--func--arg-label-sep"> {":"} </Col> ); }; renderArgVal = (funcKey, argKey, argDefinition) => { const {config, field, operator, value, readonly, parentFuncs, id, groupId} = this.props; const arg = value ? value.getIn(["args", argKey]) : null; const argVal = arg ? arg.get("value") : undefined; const defaultValueSource = argDefinition.valueSources.length == 1 ? argDefinition.valueSources[0] : undefined; const argValSrc = arg ? (arg.get("valueSrc") || defaultValueSource || "value") : defaultValueSource; const widgetProps = { config, fieldFunc: funcKey, fieldArg: argKey, leftField: field, operator: null, value: argVal, valueSrc: argValSrc, setValue: this.setArgValue, setValueSrc: this.setArgValueSrc, funcKey, argKey, argDefinition, readonly, parentFuncs, id, groupId, }; //tip: value & valueSrc will be converted to Immutable.List at <Widget> return ( <Col className="rule--func--arg-value"> <ArgWidget {...widgetProps} /> </Col> ); }; renderArgSep = (argKey, argDefinition, argIndex, {renderSeps}) => { if (!argIndex) return null; return ( <Col className="rule--func--arg-sep"> {renderSeps ? renderSeps[argIndex - 1] : ", "} </Col> ); }; renderBracketBefore = ({renderBrackets}) => { return ( <Col key="before_args" className="rule--func--bracket-before"> {renderBrackets ? renderBrackets[0] : "("} </Col> ); }; renderBracketAfter = ({renderBrackets}) => { return ( <Col key="after_args" className="rule--func--bracket-after"> {renderBrackets ? renderBrackets[1] : ")"} </Col> ); }; renderFuncArgs = () => { const {funcDefinition, funcKey} = this.meta; if (!funcKey) return null; const {args} = funcDefinition; if (!args) return null; return ( <> {this.renderBracketBefore(funcDefinition)} <Col key="args" className="rule--func--args"> {Object.keys(args).map((argKey, argIndex) => ( <Col key={`arg-${argKey}-${argIndex}`} className="rule--func--arg"> {this.renderArgSep(argKey, args[argKey], argIndex, funcDefinition)} {this.renderArgLabel(argKey, args[argKey])} {this.renderArgLabelSep(argKey, args[argKey])} {this.renderArgVal(funcKey, argKey, args[argKey])} </Col> ))} </Col> {this.renderBracketAfter(funcDefinition)} </> ); }; render() { return ( <Col className="rule--func--wrapper"> {this.renderFuncSelect()} {this.renderFuncArgs()} </Col> ); } } class ArgWidget extends PureComponent { static propTypes = { funcKey: PropTypes.string.isRequired, argKey: PropTypes.string.isRequired, setValue: PropTypes.func.isRequired, setValueSrc: PropTypes.func.isRequired, readonly: PropTypes.bool, parentFuncs: PropTypes.array, id: PropTypes.string, groupId: PropTypes.string, }; setValue = (_delta, value, _widgetType) => { const {setValue, argKey} = this.props; setValue(argKey, value); }; setValueSrc = (_delta, valueSrc, _widgetType) => { const {setValueSrc, argKey} = this.props; setValueSrc(argKey, valueSrc); }; render() { const {funcKey, parentFuncs} = this.props; return ( <Widget {...this.props} setValue={this.setValue} setValueSrc={this.setValueSrc} isFuncArg={true} parentFuncs={[...(parentFuncs || []), funcKey]} /> ); } }