UNPKG

@adaptabletools/adaptable-cjs

Version:

Powerful data-agnostic HTML5 AG Grid extension which provides advanced, cutting-edge functionality to meet all DataGrid requirements

225 lines (224 loc) 13.1 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.QueryPredicateBuilder = void 0; const tslib_1 = require("tslib"); const react_1 = tslib_1.__importDefault(require("react")); const dnd_1 = require("../../dnd"); const rebass_1 = require("rebass"); const predicate_1 = require("../../../parser/src/predicate"); const adaptableQlUtils_1 = require("../../../Utilities/adaptableQlUtils"); const booleanExpressionFunctions_1 = require("../../../Utilities/ExpressionFunctions/booleanExpressionFunctions"); const AdaptableContext_1 = require("../../../View/AdaptableContext"); const DropdownButton_1 = tslib_1.__importDefault(require("../../DropdownButton")); const ErrorBox_1 = tslib_1.__importDefault(require("../../ErrorBox")); const icons_1 = require("../../icons"); const SimpleButton_1 = tslib_1.__importDefault(require("../../SimpleButton")); const QueryBuilderInputs_1 = require("./QueryBuilderInputs"); const utils_1 = require("./utils"); const ITEM_HEIGHT = 40; const BASE_CLASS_NAME = 'ab-QueryBuilder-predicate-editor'; const Handle = (props) => (react_1.default.createElement(rebass_1.Flex, { className: `${BASE_CLASS_NAME}__handle`, height: ITEM_HEIGHT, alignItems: "center", mr: 1, ...props }, react_1.default.createElement(icons_1.Icon, { name: "drag" }))); const QueryPredicateButtons = (props) => { return (react_1.default.createElement(react_1.default.Fragment, null, !props.hideAdd && (react_1.default.createElement(DropdownButton_1.default, { listMinWidth: 150, columns: ['label'], items: [ { label: 'Condition', onClick: () => props.onNewPredicate('filter') }, { label: 'AND / OR Group', onClick: () => props.onNewPredicate('group') }, ], variant: "text" }, react_1.default.createElement(icons_1.Icon, { name: "plus" }))), !props.hideDelete && (react_1.default.createElement(SimpleButton_1.default, { icon: "delete", variant: "text", onClick: () => { props.onChange(null); } })))); }; const LogicalFunctionEditor = (props) => { const level = props.id.split('/').length - 1; const className = ` ${BASE_CLASS_NAME} ${BASE_CLASS_NAME}-level-${level} ${BASE_CLASS_NAME}-combinator ${props.lastChild ? `${BASE_CLASS_NAME}--last-child` : ''} ${props.isRoot ? `${BASE_CLASS_NAME}--root` : `${BASE_CLASS_NAME}--child`} `; const getCombinatorEl = (handleProps, className) => (react_1.default.createElement(dnd_1.Droppable, { droppableId: props.id, type: props.id }, (provided, snapshot) => { return (react_1.default.createElement("div", { ...provided.droppableProps, ref: provided.innerRef, className: className }, react_1.default.createElement(rebass_1.Flex, null, props.isRoot ? null : react_1.default.createElement(Handle, { ...handleProps }), react_1.default.createElement(rebass_1.Flex, { flex: 1, alignItems: "center", height: ITEM_HEIGHT }, react_1.default.createElement(QueryBuilderInputs_1.CombinatorSelector, { value: props.predicate.operator, onChange: (combinator) => { props.onChange({ ...props.predicate, operator: combinator, }); } }), react_1.default.createElement(rebass_1.Box, { flex: 1 }), react_1.default.createElement(QueryPredicateButtons, { hideDelete: props.isRoot, hideAdd: true, ...props }))), react_1.default.createElement(rebass_1.Box, { className: `${BASE_CLASS_NAME}__children-wrapper` }, props.predicate.args.map((arg, index) => { const id = `${props.id}/${index}`; return (react_1.default.createElement(exports.QueryPredicateBuilder, { key: id, lastChild: index === props.predicate.args.length - 1, index: index, id: id, predicate: arg, onNewPredicate: (type) => { const newPredicate = { operator: type === 'filter' ? undefined : 'AND', args: [], }; if (typeof arg === 'object' && 'operator' in arg && (0, predicate_1.isQlLogicalOperator)(arg.operator)) { // add as a child const newArg = { ...arg, args: [...arg.args, newPredicate], }; const args = [...props.predicate.args]; args[index] = newArg; props.onChange({ ...props.predicate, args, }); } else { // add as a sibling const prevArgs = [...props.predicate.args]; prevArgs.splice(index + 1, 0, newPredicate); props.onChange({ ...props.predicate, args: prevArgs, }); } }, onChange: (predicate) => { const args = [...props.predicate.args]; if (predicate) { args[index] = predicate; } else { args.splice(index, 1); } props.onChange({ ...props.predicate, args, }); } })); }), provided.placeholder, react_1.default.createElement("div", { className: `${BASE_CLASS_NAME}__root-actions` }, react_1.default.createElement(QueryPredicateButtons, { ...props, hideDelete: true }))))); })); if (props.isRoot) { return getCombinatorEl({ className: className }); } else { return (react_1.default.createElement(dnd_1.Draggable, { key: props.id, draggableId: props.id, index: props.index }, (provided, snapshot) => { return (react_1.default.createElement("div", { ...provided.draggableProps, ref: provided.innerRef, className: className }, getCombinatorEl(provided.dragHandleProps))); })); } }; const PrimitiveFunctionEditor = (props) => { // [handle] [column] [operator-dropdown] [...args] [delete-button] [plus-button] const adaptable = (0, AdaptableContext_1.useAdaptable)(); const [columnOrFieldExpression, ...restOfArgs] = props.predicate.args; const columnOrField = columnOrFieldExpression; let columnOrFieldId = null; let columnOrFieldDataType = null; let columnInputDataType = null; let functionInputInputDataTypes = null; // Thsese are the type of inputs ommiting the column // [[column-data-type], number, number] let restOfFunctionInputDataTypes = []; if (columnOrField) { if (!(0, predicate_1.isArgumentColumnOrField)(columnOrField)) { return react_1.default.createElement(ErrorBox_1.default, null, "Expression must start with a column or a filed!"); } if (columnOrField.includes('FIELD')) { // we let the full expression so we can difirienciate between column and field columnOrFieldId = columnOrField; const fieldValue = (0, utils_1.mapExpressionToFieldValue)(columnOrField); columnOrFieldDataType = adaptable.api.expressionApi.internalApi.getFieldType(fieldValue); } else if (columnOrField.includes('[')) { columnOrFieldId = columnOrField; const columnId = columnOrField.replace(/[\[\]]/g, ''); columnOrFieldDataType = adaptable.api.columnApi.getColumnDataTypeForColumnId(columnId); } columnInputDataType = (0, adaptableQlUtils_1.mapColumnDataTypeToExpressionFunctionType)(columnOrFieldDataType); functionInputInputDataTypes = booleanExpressionFunctions_1.booleanExpressionFunctions[props.predicate.operator]?.inputs; restOfFunctionInputDataTypes = functionInputInputDataTypes ? (0, utils_1.getOperatorMatchingInputs)(columnInputDataType, functionInputInputDataTypes) : []; } const level = props.id.split('/').length - 1; return (react_1.default.createElement(dnd_1.Draggable, { key: props.id, draggableId: props.id, index: props.index }, (provided) => { return (react_1.default.createElement(rebass_1.Flex, { className: ` ${BASE_CLASS_NAME} ${BASE_CLASS_NAME}-level-${level} ${BASE_CLASS_NAME}-primitive ${props.lastChild ? `${BASE_CLASS_NAME}--last-child` : ''} `, pb: 2, ref: provided.innerRef, ...provided.draggableProps, style: { ...provided.draggableProps.style, minHeight: ITEM_HEIGHT } }, react_1.default.createElement(Handle, { ...provided.dragHandleProps }), react_1.default.createElement(rebass_1.Flex, { alignItems: "center", height: ITEM_HEIGHT }, react_1.default.createElement(rebass_1.Box, { mr: 2 }, react_1.default.createElement(QueryBuilderInputs_1.PrimitiveColumnOrFieldSelector, { onChange: (colOrField) => { props.onChange({ ...props.predicate, args: [colOrField], operator: null, }); }, fieldOrColumn: columnOrFieldId })), columnOrFieldId && columnOrFieldDataType && (react_1.default.createElement(QueryBuilderInputs_1.ExpressionSelector, { dataType: columnOrFieldDataType, onExpressionChange: (operator) => { let args = [props.predicate.args[0]]; if (columnOrFieldDataType === 'boolean' && operator !== 'NOT') { args = [props.predicate.args[0], 'TRUE']; } props.onChange({ ...props.predicate, operator, // discard arguments args, }); }, value: props.predicate.operator })), react_1.default.createElement(rebass_1.Flex, { flex: 1, ml: 2 }, restOfFunctionInputDataTypes.map((type, index) => { const key = type + index; const commonProps = { lefthandColumnIdParam: columnOrFieldId, inputType: type, }; if (type.includes('[]')) { return (react_1.default.createElement(QueryBuilderInputs_1.PrimitiveMultiValueInput, { ...commonProps, key: key, value: restOfArgs, onChange: (values) => { const args = [...props.predicate.args.slice(0, 1), ...values]; props.onChange({ ...props.predicate, args, }); } })); } return (react_1.default.createElement(QueryBuilderInputs_1.PrimiteValueInput, { ...commonProps, key: key, value: restOfArgs[index] ?? null, onChange: (value) => { const args = [...props.predicate.args]; // +1 because col is the first argument args[index + 1] = value; props.onChange({ ...props.predicate, args, }); } })); }))), react_1.default.createElement(rebass_1.Box, { flex: 1 }), react_1.default.createElement(QueryPredicateButtons, { ...props }))); })); }; /** * Two types: * - combinatory operator * - can contain both expressons and combinators * [handle] [combinator-dropdown] * [children] * * - boolean function: ars do not contain other combinators * [handle] [column] [operator-dropdown] [...args] [delete-button] [plus-button] */ const QueryPredicateBuilder = (props) => { if ((0, predicate_1.isQlLogicalOperator)(props.predicate.operator)) { return react_1.default.createElement(LogicalFunctionEditor, { ...props }); } else { return react_1.default.createElement(PrimitiveFunctionEditor, { ...props }); } }; exports.QueryPredicateBuilder = QueryPredicateBuilder;