UNPKG

@adaptabletools/adaptable

Version:

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

180 lines (179 loc) 12.3 kB
import { createElement as _createElement } from "react"; import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime"; import { defaultDragProxyMove, DragList } from '../../dnd'; import { cn } from '../../../lib/utils'; import { isArgumentColumnOrField, isQlLogicalOperator, } from '../../../parser/src/predicate'; import { mapColumnDataTypeToExpressionFunctionType } from '../../../Utilities/adaptableQlUtils'; import { booleanExpressionFunctions } from '../../../Utilities/ExpressionFunctions/booleanExpressionFunctions'; import { useAdaptable } from '../../../View/AdaptableContext'; import { NewDropdownButton } from '../../DropdownButton'; import ErrorBox from '../../ErrorBox'; import { Icon } from '../../icons'; import SimpleButton from '../../SimpleButton'; import { CombinatorSelector, ExpressionSelector, PrimitiveValueInput, PrimitiveColumnOrFieldSelector, PrimitiveMultiValueInput, } from './QueryBuilderInputs'; import { getOperatorMatchingInputs as getFunctionMatchingInputTypes, mapExpressionToFieldValue, } from './utils'; import { Box, Flex } from '../../Flex'; const ITEM_HEIGHT = 36; const BASE_CLASS_NAME = 'ab-QueryBuilder-predicate-editor'; const Handle = (props) => (_jsx(Flex, { className: `${BASE_CLASS_NAME}__handle twa:mr-1`, style: { height: ITEM_HEIGHT }, alignItems: "center", ...props, children: _jsx(Icon, { name: "drag" }) })); const QueryPredicateButtons = (props) => { return (_jsxs(_Fragment, { children: [!props.hideAdd && (_jsx(NewDropdownButton, { items: [ { label: 'Condition', onClick: () => props.onNewPredicate('filter') }, { label: 'AND / OR Group', onClick: () => props.onNewPredicate('group') }, ], variant: "text", children: _jsx(Icon, { name: "plus" }) })), !props.hideDelete && (_jsx(SimpleButton, { 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 handleDrop = (sortedIndexes) => { const newArgs = sortedIndexes.map((i) => props.predicate.args[i]); props.onChange({ ...props.predicate, args: newArgs }); }; const getCombinatorEl = (handleProps) => (_jsx(DragList, { dragListId: props.id, orientation: "vertical", onDrop: handleDrop, onDragProxyMove: defaultDragProxyMove, children: (listDomProps) => { return (_jsxs("div", { ...listDomProps, className: cn(listDomProps.className), children: [_jsxs(Flex, { children: [props.isRoot ? null : _jsx(Handle, { ...handleProps }), _jsxs(Flex, { className: "twa:flex-1 twa:mb-2", alignItems: "center", height: ITEM_HEIGHT, children: [_jsx(CombinatorSelector, { value: props.predicate.operator, onChange: (combinator) => { props.onChange({ ...props.predicate, operator: combinator, }); } }), _jsx(Box, { className: "twa:flex-1" }), _jsx(QueryPredicateButtons, { hideDelete: props.isRoot, hideAdd: true, ...props })] })] }), _jsxs(Box, { className: `${BASE_CLASS_NAME}__children-wrapper`, children: [props.predicate.args.map((arg, index) => { const id = `${props.id}/${index}`; return (_jsx(QueryPredicateBuilder, { 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 && isQlLogicalOperator(arg.operator)) { const newArg = { ...arg, args: [...arg.args, newPredicate], }; const args = [...props.predicate.args]; args[index] = newArg; props.onChange({ ...props.predicate, args, }); } else { 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, }); } }, id)); }), _jsx("div", { className: `${BASE_CLASS_NAME}__root-actions`, children: _jsx(QueryPredicateButtons, { ...props, hideDelete: true }) })] })] })); } })); if (props.isRoot) { return getCombinatorEl({ className }); } return (_jsx(DragList.DraggableItem, { id: props.id, children: (itemDomProps) => { const { onPointerDown, ...restDomProps } = itemDomProps; return (_jsx("div", { ...restDomProps, className: cn(className, restDomProps.className), children: getCombinatorEl({ onPointerDown }) })); } })); }; const PrimitiveFunctionEditor = (props) => { const adaptable = useAdaptable(); const [columnOrFieldExpression, ...restOfArgs] = props.predicate.args; const columnOrField = columnOrFieldExpression; let columnOrFieldId = null; let columnOrFieldDataType = null; let columnInputDataType = null; let functionInputInputDataTypes = null; let restOfFunctionInputDataTypes = []; if (columnOrField) { if (!isArgumentColumnOrField(columnOrField)) { return _jsx(ErrorBox, { children: "Expression must start with a column or a filed!" }); } if (columnOrField.includes('FIELD')) { columnOrFieldId = columnOrField; const fieldValue = 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 = mapColumnDataTypeToExpressionFunctionType(columnOrFieldDataType); functionInputInputDataTypes = booleanExpressionFunctions[props.predicate.operator]?.inputs; restOfFunctionInputDataTypes = functionInputInputDataTypes ? getFunctionMatchingInputTypes(columnInputDataType, functionInputInputDataTypes) : []; } const level = props.id.split('/').length - 1; return (_jsx(DragList.DraggableItem, { id: props.id, children: (itemDomProps) => { const { onPointerDown, ...restDomProps } = itemDomProps; return (_jsxs(Flex, { ...restDomProps, className: cn(`twa:pb-2 ${BASE_CLASS_NAME} ${BASE_CLASS_NAME}-level-${level} ${BASE_CLASS_NAME}-primitive ${props.lastChild ? `${BASE_CLASS_NAME}--last-child` : ''}`, restDomProps.className), style: { minHeight: ITEM_HEIGHT }, children: [_jsx(Handle, { onPointerDown: onPointerDown }), _jsxs(Flex, { alignItems: "center", style: { height: ITEM_HEIGHT }, className: "twa:gap-0.5 twa:w-full", children: [_jsx(Box, { children: _jsx(PrimitiveColumnOrFieldSelector, { onChange: (colOrField) => { props.onChange({ ...props.predicate, args: [colOrField], operator: null, }); }, fieldOrColumn: columnOrFieldId }) }), columnOrFieldId && columnOrFieldDataType && (_jsx(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, args, }); }, value: props.predicate.operator })), _jsx(Flex, { className: "twa:flex-1", children: restOfFunctionInputDataTypes.map((type, index) => { const key = type + index; const commonProps = { lefthandColumnIdParam: columnOrFieldId, inputType: type, }; if (type.includes('[]')) { return (_createElement(PrimitiveMultiValueInput, { ...commonProps, key: key, value: restOfArgs, onChange: (values) => { const args = [...props.predicate.args.slice(0, 1), ...values]; props.onChange({ ...props.predicate, args, }); } })); } return (_createElement(PrimitiveValueInput, { ...commonProps, key: key, value: restOfArgs[index] ?? null, onChange: (value) => { const args = [...props.predicate.args]; args[index + 1] = value; props.onChange({ ...props.predicate, args, }); } })); }) })] }), _jsx(Box, { className: "twa:flex-1" }), _jsx(QueryPredicateButtons, { ...props })] })); } })); }; export const QueryPredicateBuilder = (props) => { if (isQlLogicalOperator(props.predicate.operator)) { return _jsx(LogicalFunctionEditor, { ...props }); } else { return _jsx(PrimitiveFunctionEditor, { ...props }); } };