@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
JavaScript
"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;