@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
JavaScript
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 });
}
};