import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
/**
 * Copyright (c) 2020-present, Goldman Sachs
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import { useRef, useState, useCallback, forwardRef, useMemo, useEffect, } from 'react';
import { observer } from 'mobx-react-lite';
import { clsx, ContextMenu, ControlledDropdownMenu, MenuContent, MenuContentItem, BlankPanelPlaceholder, CompressIcon, ExpandIcon, TrashIcon, NewFolderIcon, CircleIcon, CaretDownIcon, PlusIcon, PlusCircleIcon, TimesIcon, PanelDropZone, DragPreviewLayer, PanelEntryDropZonePlaceholder, useDragPreviewLayer, PanelContent, MoreVerticalIcon, MenuContentItemIcon, MenuContentItemLabel, InfoCircleIcon, RefreshIcon, } from '@finos/legend-art';
import { QUERY_BUILDER_FILTER_DND_TYPE, FilterConditionState, QueryBuilderFilterTreeConditionNodeData, QueryBuilderFilterTreeBlankConditionNodeData, QueryBuilderFilterTreeGroupNodeData, QueryBuilderFilterTreeExistsNodeData, QueryBuilderFilterTreeOperationNodeData, FilterValueSpecConditionValueState, FilterPropertyExpressionStateConditionValueState, isCollectionProperty, isExistsNodeChild, } from '../../stores/filter/QueryBuilderFilterState.js';
import { useDrag, useDragLayer, useDrop } from 'react-dnd';
import { buildPropertyExpressionFromExplorerTreeNodeData, QUERY_BUILDER_EXPLORER_TREE_DND_TYPE, } from '../../stores/explorer/QueryBuilderExplorerState.js';
import { QueryBuilderPropertyExpressionBadge, QueryBuilderPropertyExpressionEditor, } from '../QueryBuilderPropertyExpressionEditor.js';
import { assertErrorThrown, assertTrue, debounce, generateEnumerableNameFromToken, guaranteeNonNullable, guaranteeType, UnsupportedOperationError, } from '@finos/legend-shared';
import { QUERY_BUILDER_TEST_ID } from '../../__lib__/QueryBuilderTesting.js';
import { ActionAlertActionType, ActionAlertType, useApplicationStore, } from '@finos/legend-application';
import { AbstractPropertyExpression, extractElementNameFromPath, matchFunctionName, Multiplicity, SimpleFunctionExpression, VariableExpression, PrimitiveType, Class, Enumeration, } from '@finos/legend-graph';
import { QueryBuilderSimpleProjectionColumnState, QUERY_BUILDER_PROJECTION_COLUMN_DND_TYPE, } from '../../stores/fetch-structure/tds/projection/QueryBuilderProjectionColumnState.js';
import { isTypeCompatibleForAssignment } from '../../stores/QueryBuilderValueSpecificationHelper.js';
import { QUERY_BUILDER_GROUP_OPERATION } from '../../stores/QueryBuilderGroupOperationHelper.js';
import { QUERY_BUILDER_VARIABLE_DND_TYPE, EditableBasicValueSpecificationEditor, } from '../shared/BasicValueSpecificationEditor.js';
import { QueryBuilderTelemetryHelper } from '../../__lib__/QueryBuilderTelemetryHelper.js';
import { QueryBuilderPropertyExpressionState, getPropertyChainName, } from '../../stores/QueryBuilderPropertyEditorState.js';
import { QUERY_BUILDER_SUPPORTED_FUNCTIONS } from '../../graph/QueryBuilderMetaModelConst.js';
import { buildPropertyExpressionChain } from '../../stores/QueryBuilderValueSpecificationBuilderHelper.js';
import { QueryBuilderPanelIssueCountBadge } from '../shared/QueryBuilderPanelIssueCountBadge.js';
import { cloneAbstractPropertyExpression, convertTextToPrimitiveInstanceValue, } from '../../stores/shared/ValueSpecificationEditorHelper.js';
import { QueryBuilderFilterOperator_In, QueryBuilderFilterOperator_NotIn, } from '../../stores/filter/operators/QueryBuilderFilterOperator_In.js';
import { renderPropertyTypeIcon } from '../fetch-structure/QueryBuilderTDSComponentHelper.js';
import { QueryBuilderPropertyInfoTooltip } from '../shared/QueryBuilderPropertyInfoTooltip.js';
import { getDNDItemType } from '../shared/QueryBuilderFilterHelper.js';
export const CAN_DROP_MAIN_GROUP_DND_TYPES_FETCH_SUPPORTED = [
    QUERY_BUILDER_EXPLORER_TREE_DND_TYPE.ENUM_PROPERTY,
    QUERY_BUILDER_EXPLORER_TREE_DND_TYPE.PRIMITIVE_PROPERTY,
    QUERY_BUILDER_PROJECTION_COLUMN_DND_TYPE,
];
export const CAN_DROP_MAIN_GROUP_DND_TYPES = [
    QUERY_BUILDER_EXPLORER_TREE_DND_TYPE.ENUM_PROPERTY,
    QUERY_BUILDER_EXPLORER_TREE_DND_TYPE.PRIMITIVE_PROPERTY,
];
export const CAN_DROP_FILTER_NODE_DND_TYPES_FETCH_SUPPORTED = [
    QUERY_BUILDER_FILTER_DND_TYPE.CONDITION,
    QUERY_BUILDER_EXPLORER_TREE_DND_TYPE.ENUM_PROPERTY,
    QUERY_BUILDER_EXPLORER_TREE_DND_TYPE.PRIMITIVE_PROPERTY,
    QUERY_BUILDER_PROJECTION_COLUMN_DND_TYPE,
];
export const CAN_DROP_FILTER_NODE_DND_TYPES = [
    QUERY_BUILDER_FILTER_DND_TYPE.CONDITION,
    QUERY_BUILDER_EXPLORER_TREE_DND_TYPE.ENUM_PROPERTY,
    QUERY_BUILDER_EXPLORER_TREE_DND_TYPE.PRIMITIVE_PROPERTY,
];
export const CAN_DROP_FILTER_VALUE_DND_TYPES = [
    QUERY_BUILDER_EXPLORER_TREE_DND_TYPE.ENUM_PROPERTY,
    QUERY_BUILDER_EXPLORER_TREE_DND_TYPE.PRIMITIVE_PROPERTY,
    QUERY_BUILDER_PROJECTION_COLUMN_DND_TYPE,
    QUERY_BUILDER_VARIABLE_DND_TYPE,
];
/**
 * This function updates the filter state when we DnD a property that can accept multiple values.
 */
export const buildFilterTreeWithExists = (propertyExpression, filterState, targetDropNode) => {
    // 1. Decompose property expression
    const expressions = [];
    let currentPropertyExpression = propertyExpression;
    while (currentPropertyExpression instanceof AbstractPropertyExpression ||
        (currentPropertyExpression instanceof SimpleFunctionExpression &&
            matchFunctionName(currentPropertyExpression.functionName, QUERY_BUILDER_SUPPORTED_FUNCTIONS.SUBTYPE))) {
        let exp;
        if (currentPropertyExpression instanceof SimpleFunctionExpression) {
            exp = new SimpleFunctionExpression(extractElementNameFromPath(QUERY_BUILDER_SUPPORTED_FUNCTIONS.SUBTYPE));
        }
        else {
            exp = new AbstractPropertyExpression('');
            exp.func = currentPropertyExpression.func;
        }
        // NOTE: we must retain the rest of the parameters as those are derived property parameters
        exp.parametersValues =
            currentPropertyExpression.parametersValues.length > 1
                ? currentPropertyExpression.parametersValues.slice(1)
                : [];
        expressions.push(exp);
        currentPropertyExpression = guaranteeNonNullable(currentPropertyExpression.parametersValues[0]);
    }
    const rootVariable = guaranteeType(currentPropertyExpression, VariableExpression);
    // 2. Traverse the list of decomposed property expression backward, every time we encounter a property of
    // multiplicity many, create a new property expression and keep track of it to later form the lambda chain
    let existsLambdaParamNames = [];
    let existsLambdaPropertyChains = [rootVariable];
    let currentParamNameIndex = 0;
    for (let i = expressions.length - 1; i >= 0; --i) {
        const exp = expressions[i];
        // just keep adding to the property chain
        exp.parametersValues.unshift(existsLambdaPropertyChains[existsLambdaPropertyChains.length - 1]);
        existsLambdaPropertyChains[existsLambdaPropertyChains.length - 1] = exp;
        // ... but if the property is of multiplicity multiple, start a new property chain
        if (exp instanceof AbstractPropertyExpression &&
            (exp.func.value.multiplicity.upperBound === undefined ||
                exp.func.value.multiplicity.upperBound > 1)) {
            // NOTE: we need to find/generate the property chain variable name
            if (currentParamNameIndex > existsLambdaParamNames.length - 1) {
                existsLambdaParamNames.push(generateEnumerableNameFromToken(existsLambdaParamNames, filterState.lambdaParameterName));
                assertTrue(currentParamNameIndex === existsLambdaParamNames.length - 1);
            }
            existsLambdaPropertyChains.push(new VariableExpression(existsLambdaParamNames[currentParamNameIndex], Multiplicity.ONE));
            currentParamNameIndex++;
        }
    }
    let parentNode = undefined;
    if (targetDropNode) {
        if (targetDropNode instanceof QueryBuilderFilterTreeExistsNodeData) {
            // Here we check if the target drop node is an exists tree node, if it is
            // then we try to check in the lambda property chains that it contains the
            // property expression of the target drop node. If we find any lambda property
            // chain we just create exists filter for the rest of the property and add it to the
            // target drop exists node, otherwise we just create exists for all the property chains.
            // For example if we find property chain we create
            // employees->exists($x.name == 'Bob' && $x.id == '1') instead of creating
            // employess->exists($x.name == 'Bob) && employess->exists($x.id == '1')
            const parentPropertyChainIndex = existsLambdaPropertyChains.findIndex((p) => p instanceof AbstractPropertyExpression &&
                p.func.value ===
                    targetDropNode.propertyExpressionState.propertyExpression.func
                        .value &&
                p.func.ownerReference.value.path ===
                    targetDropNode.propertyExpressionState.propertyExpression.func
                        .ownerReference.value.path);
            if (parentPropertyChainIndex >= 0) {
                parentNode = targetDropNode;
                existsLambdaPropertyChains = existsLambdaPropertyChains.slice(parentPropertyChainIndex + 1);
                existsLambdaParamNames = existsLambdaParamNames.slice(parentPropertyChainIndex + 1);
            }
        }
        else {
            // Here the target drop node is a group operation tree node. So we try to find if there is
            // any exists tree parent node of the target drop node. If there is any exists parent node,
            // we try to check in the lambda property chains that it contains the
            // property expression of the target drop node. If we find any lambda property
            // chain we just create exists filter for the rest of the property and add it to the
            // target drop exists node, otherwise we just create exists for all the property chains.
            // For example if we find property chain we create
            // employees->exists($x.name == 'Bob' && $x.id == '1' && $x.age == '30) instead of creating
            // employess->exists($x.name == 'Bob) && employess->exists($x.id == '1') && employess->exists($x.age == '30')
            let cn = targetDropNode;
            let parentId = targetDropNode.parentId;
            while (parentId &&
                !(cn instanceof QueryBuilderFilterTreeExistsNodeData)) {
                cn = filterState.nodes.get(parentId);
                parentId = cn?.parentId;
            }
            if (cn instanceof QueryBuilderFilterTreeExistsNodeData) {
                const parentPropertyChainIndex = existsLambdaPropertyChains.findIndex((p) => p instanceof AbstractPropertyExpression &&
                    cn instanceof QueryBuilderFilterTreeExistsNodeData &&
                    p.func.value ===
                        guaranteeType(cn, QueryBuilderFilterTreeExistsNodeData)
                            .propertyExpressionState.propertyExpression.func.value &&
                    p.func.ownerReference.value.path ===
                        cn.propertyExpressionState.propertyExpression.func.ownerReference
                            .value.path);
                if (parentPropertyChainIndex >= 0) {
                    // Here we choose parentNode based on what the type of targetDropNode
                    // 1. QueryBuilderFilterTreeConditionNodeData: In this case we would want to
                    // add a new group condition from the targetDropNode and add new exists node
                    // getting created as it's child so the parent would be the new group node
                    // 2. QueryBuilderFilterTreeGroupNodeData: Parent node would be same as
                    // targetDropNode
                    // 3. QueryBuilderFilterTreeBlankConditionNodeData: parentNode would be the
                    // parent of the targetDropNode. At the end we would deelete this blank node
                    // that got created.
                    parentNode =
                        targetDropNode instanceof QueryBuilderFilterTreeConditionNodeData
                            ? filterState.newGroupConditionFromNode(targetDropNode)
                            : targetDropNode instanceof QueryBuilderFilterTreeGroupNodeData
                                ? targetDropNode
                                : filterState.getParentNode(targetDropNode);
                    existsLambdaPropertyChains = existsLambdaPropertyChains.slice(parentPropertyChainIndex + 1);
                    existsLambdaParamNames = existsLambdaParamNames.slice(parentPropertyChainIndex + 1);
                }
            }
            else if (!parentId) {
                parentNode =
                    targetDropNode instanceof QueryBuilderFilterTreeConditionNodeData
                        ? filterState.newGroupConditionFromNode(targetDropNode)
                        : targetDropNode instanceof QueryBuilderFilterTreeGroupNodeData
                            ? targetDropNode
                            : filterState.getParentNode(targetDropNode);
            }
        }
    }
    // 3. Create exists tree node for all the property chains and add them to the filter tree
    for (let i = 0; i < existsLambdaPropertyChains.length - 1; ++i) {
        const existsNode = new QueryBuilderFilterTreeExistsNodeData(filterState, parentNode?.id);
        existsNode.setPropertyExpression(existsLambdaPropertyChains[i]);
        existsNode.lambdaParameterName = existsLambdaParamNames[i];
        filterState.nodes.set(existsNode.id, existsNode);
        filterState.addNodeFromNode(existsNode, parentNode);
        parentNode = existsNode;
    }
    // create the filter condition tree node data
    const filterConditionState = new FilterConditionState(filterState, existsLambdaPropertyChains[existsLambdaPropertyChains.length - 1]);
    const treeNode = new QueryBuilderFilterTreeConditionNodeData(undefined, filterConditionState);
    treeNode.setIsNewlyAdded(true);
    filterState.addNodeFromNode(treeNode, parentNode);
    if (targetDropNode instanceof QueryBuilderFilterTreeBlankConditionNodeData) {
        filterState.removeNodeAndPruneBranch(targetDropNode);
    }
};
export const buildPropertyExpressionFromExistsNode = (filterState, existsNode, node) => {
    let nodeParent = filterState.getParentNode(node);
    let existsLambdaExpressions = [];
    existsLambdaExpressions.push(node.condition.propertyExpressionState.propertyExpression);
    while (nodeParent && nodeParent.id !== existsNode.id) {
        if (nodeParent instanceof QueryBuilderFilterTreeExistsNodeData) {
            existsLambdaExpressions.push(nodeParent.propertyExpressionState.propertyExpression);
        }
        nodeParent = filterState.getParentNode(nodeParent);
    }
    if (nodeParent?.id === existsNode.id) {
        existsLambdaExpressions.push(existsNode.propertyExpressionState.propertyExpression);
    }
    existsLambdaExpressions = existsLambdaExpressions.reverse();
    const initialPropertyExpression = guaranteeNonNullable(existsLambdaExpressions[0]);
    existsLambdaExpressions = existsLambdaExpressions.slice(1);
    let flattenedPropertyExpressionChain = new AbstractPropertyExpression('');
    flattenedPropertyExpressionChain.func = initialPropertyExpression.func;
    flattenedPropertyExpressionChain.parametersValues = [
        ...initialPropertyExpression.parametersValues,
    ];
    for (const exp of existsLambdaExpressions) {
        // when rebuilding the property expression chain, disregard the initial variable that starts the chain
        const expressions = [];
        let currentExpression = exp;
        while (currentExpression instanceof AbstractPropertyExpression ||
            (currentExpression instanceof SimpleFunctionExpression &&
                matchFunctionName(currentExpression.functionName, QUERY_BUILDER_SUPPORTED_FUNCTIONS.SUBTYPE))) {
            if (currentExpression instanceof SimpleFunctionExpression) {
                const functionExpression = new SimpleFunctionExpression(extractElementNameFromPath(QUERY_BUILDER_SUPPORTED_FUNCTIONS.SUBTYPE));
                functionExpression.parametersValues.unshift(guaranteeNonNullable(currentExpression.parametersValues[1]));
                expressions.push(functionExpression);
            }
            else if (currentExpression instanceof AbstractPropertyExpression) {
                const propertyExp = new AbstractPropertyExpression('');
                propertyExp.func = currentExpression.func;
                // NOTE: we must retain the rest of the parameters as those are derived property parameters
                propertyExp.parametersValues =
                    currentExpression.parametersValues.length > 1
                        ? currentExpression.parametersValues.slice(1)
                        : [];
                expressions.push(propertyExp);
            }
            currentExpression = guaranteeNonNullable(currentExpression.parametersValues[0]);
        }
        assertTrue(expressions.length > 0, `Can't process exists() expression: exists() usage with non-chain property expression is not supported`);
        for (let i = 0; i < expressions.length - 1; ++i) {
            expressions[i].parametersValues.unshift(expressions[i + 1]);
        }
        expressions[expressions.length - 1].parametersValues.unshift(flattenedPropertyExpressionChain);
        flattenedPropertyExpressionChain = guaranteeType(expressions[0], AbstractPropertyExpression, `Can't process exists() expression: can't flatten to a property expression`);
    }
    return guaranteeType(buildPropertyExpressionChain(flattenedPropertyExpressionChain, filterState.queryBuilderState, existsNode.lambdaParameterName ?? filterState.lambdaParameterName), AbstractPropertyExpression);
};
/**
 * This function builds the filter tree when we DnD a node to the filter panel.
 */
const buildFilterTree = (propertyExpression, filterState, targetDropNode) => {
    if (isCollectionProperty(propertyExpression)) {
        const propertyChainName = getPropertyChainName(propertyExpression, filterState.queryBuilderState.explorerState.humanizePropertyName);
        filterState.queryBuilderState.applicationStore.alertService.setActionAlertInfo({
            message: `The property '${propertyChainName}' is a collection. As you are trying to filter on a collection, the filter created will be an exist filter. e.g. There exists at least one '${propertyChainName}' where 'Type' is the value specified.
         If you are looking to create the filter where all values in this collection equal the value specified, rather than at least one value, consider creating post filter instead.`,
            type: ActionAlertType.CAUTION,
            actions: [
                {
                    label: 'Cancel',
                    type: ActionAlertActionType.PROCEED_WITH_CAUTION,
                    default: true,
                },
                {
                    label: 'Proceed',
                    type: ActionAlertActionType.PROCEED,
                    handler: filterState.queryBuilderState.applicationStore.guardUnhandledError(async () => buildFilterTreeWithExists(propertyExpression, filterState, targetDropNode)),
                },
            ],
        });
    }
    else {
        const filterConditionState = new FilterConditionState(filterState, propertyExpression);
        const treeNode = new QueryBuilderFilterTreeConditionNodeData(undefined, filterConditionState);
        treeNode.setIsNewlyAdded(true);
        // Check if there are any exists node present in the parent nodes of the target.
        // This would change the way we build the filter tree
        let cn = targetDropNode;
        let existsNode = undefined;
        let parentId = targetDropNode?.parentId;
        while (parentId) {
            cn = filterState.nodes.get(parentId);
            parentId = cn?.parentId;
            if (cn instanceof QueryBuilderFilterTreeExistsNodeData) {
                existsNode = cn;
            }
        }
        if (cn instanceof QueryBuilderFilterTreeExistsNodeData) {
            existsNode = cn;
        }
        if (targetDropNode instanceof QueryBuilderFilterTreeGroupNodeData) {
            if (existsNode) {
                filterState.newGroupConditionFromNode(existsNode, treeNode, targetDropNode.groupOperation);
            }
            else {
                filterState.addNodeFromNode(treeNode, targetDropNode);
            }
        }
        else if (targetDropNode instanceof QueryBuilderFilterTreeBlankConditionNodeData) {
            if (existsNode) {
                filterState.queryBuilderState.applicationStore.notificationService.notifyError(`Can't drag and drop here: property expression of target and source doesn't match`);
            }
            else {
                filterState.replaceBlankNodeWithNode(treeNode, targetDropNode);
            }
        }
        else if (existsNode &&
            targetDropNode instanceof QueryBuilderFilterTreeExistsNodeData) {
            filterState.newGroupConditionFromNode(existsNode, treeNode);
        }
        else if (targetDropNode instanceof QueryBuilderFilterTreeConditionNodeData) {
            const parentNode = filterState.getParentNode(targetDropNode);
            if (existsNode &&
                parentNode instanceof QueryBuilderFilterTreeExistsNodeData &&
                parentNode.childrenIds.length === 1) {
                filterState.newGroupConditionFromNode(existsNode, treeNode, QUERY_BUILDER_GROUP_OPERATION.AND);
            }
            else if (existsNode &&
                parentNode instanceof QueryBuilderFilterTreeGroupNodeData) {
                const propertyExpression1 = buildPropertyExpressionFromExistsNode(filterState, existsNode, targetDropNode);
                filterState.removeNodeAndPruneBranch(targetDropNode);
                filterState.newGroupConditionFromNode(existsNode, treeNode, parentNode.groupOperation);
                const newParentNode = filterState.getParentNode(treeNode);
                buildFilterTreeWithExists(propertyExpression1, filterState, newParentNode);
            }
            else {
                filterState.newGroupWithConditionFromNode(treeNode, targetDropNode);
            }
        }
        else {
            filterState.addNodeFromNode(treeNode, undefined);
        }
    }
};
const QueryBuilderFilterGroupConditionEditor = observer((props) => {
    const { node, isDragOver, isDroppable } = props;
    const switchOperation = (event) => {
        event.stopPropagation(); // prevent triggering selecting the node
        node.setGroupOperation(node.groupOperation === QUERY_BUILDER_GROUP_OPERATION.AND
            ? QUERY_BUILDER_GROUP_OPERATION.OR
            : QUERY_BUILDER_GROUP_OPERATION.AND);
    };
    const operationName = node.groupOperation === QUERY_BUILDER_GROUP_OPERATION.AND ? 'AND' : 'OR';
    return (_jsx("div", { className: "dnd__entry__container", children: _jsx(PanelEntryDropZonePlaceholder, { isDragOver: isDragOver, isDroppable: isDroppable, label: operationName, className: "query-builder-filter-tree__group-node__drop-zone", children: _jsx("div", { className: "query-builder-filter-tree__group-node", title: "Switch Operation", onClick: switchOperation, children: _jsx("div", { className: "query-builder-filter-tree__group-node__label editable-value", children: node.groupOperation }) }) }) }));
});
const QueryBuilderFilterExistsConditionEditor = observer((props) => {
    const { node, humanizePropertyName, isDragOver, isDroppable } = props;
    const hasDerivedPropertyInExpression = Boolean(node.propertyExpressionState.derivedPropertyExpressionStates.length);
    const isValid = node.propertyExpressionState.isValid;
    const setDerivedPropertyArguments = () => {
        if (hasDerivedPropertyInExpression) {
            node.propertyExpressionState.setIsEditingDerivedProperty(true);
        }
    };
    return (_jsx("div", { className: "dnd__entry__container", children: _jsx(PanelEntryDropZonePlaceholder, { isDragOver: isDragOver, isDroppable: isDroppable, label: "Add to Exists Group", className: "query-builder-filter-tree__exists-node__drop-zone", children: _jsxs("div", { className: "query-builder-filter-tree__exists-node", title: "This is an exists filter on the collection property", children: [_jsx("div", { className: "query-builder-filter-tree__exists-node__label", children: getPropertyChainName(node.propertyExpressionState.propertyExpression, humanizePropertyName) }), _jsx("div", { className: "query-builder-filter-tree__exists-node__exists--label", children: "exists" }), hasDerivedPropertyInExpression && (_jsxs("button", { className: clsx('query-builder-filter-tree__exists-node__exists--label__action', {
                            'query-builder-filter-tree__exists-node__exists--label__action--error': !isValid,
                        }), tabIndex: -1, onClick: setDerivedPropertyArguments, title: "Set Derived Property Argument(s)...", children: [!isValid && _jsx(InfoCircleIcon, {}), " (...)"] })), _jsx(QueryBuilderPropertyExpressionEditor, { propertyExpressionState: node.propertyExpressionState })] }) }) }));
});
export const QueryBuilderFilterPropertyExpressionBadge = observer((props) => {
    const { rightConditionValue, resetNode } = props;
    const type = rightConditionValue.type;
    return (_jsx("div", { className: "query-builder-filter-property-expression-badge", children: _jsxs("div", { className: "query-builder-filter-property-expression-badge__content", children: [_jsx("div", { className: clsx('query-builder-filter-property-expression-badge__type', {
                        'query-builder-filter-property-expression-badge__type--class': type instanceof Class,
                        'query-builder-filter-property-expression-badge__type--enumeration': type instanceof Enumeration,
                        'query-builder-filter-property-expression-badge__type--primitive': type instanceof PrimitiveType,
                    }), children: renderPropertyTypeIcon(type) }), _jsx("div", { className: "query-builder-filter-property-expression-badge__property", title: rightConditionValue.propertyExpressionState.propertyExpression
                        .func.value.name, children: _jsx(QueryBuilderPropertyExpressionBadge, { propertyExpressionState: rightConditionValue.propertyExpressionState }) }), _jsx(QueryBuilderPropertyInfoTooltip, { title: rightConditionValue.propertyExpressionState.propertyExpression
                        .func.value.name, property: rightConditionValue.propertyExpressionState.propertyExpression
                        .func.value, path: rightConditionValue.propertyExpressionState.path, isMapped: true, placement: "bottom-end", children: _jsx("div", { className: "query-builder-filter-property-expression-badge__property__info", children: _jsx(InfoCircleIcon, {}) }) }), _jsx("button", { className: "query-builder-filter-property-expression-badge__action", name: "Reset", title: "Reset", onClick: resetNode, children: _jsx(RefreshIcon, {}) })] }) }));
});
const canDropTypeOntoNodeValue = (type, condition) => {
    const conditionOperator = condition.operator;
    const conditionValueType = condition.propertyExpressionState.propertyExpression.func.value.genericType
        .value.rawType;
    return (!(conditionOperator instanceof QueryBuilderFilterOperator_In) &&
        !(conditionOperator instanceof QueryBuilderFilterOperator_NotIn) &&
        isTypeCompatibleForAssignment(type, conditionValueType));
};
const QueryBuilderFilterConditionEditor = observer((props) => {
    const { node, isDragOver } = props;
    const graph = node.condition.filterState.queryBuilderState.graphManagerState.graph;
    const queryBuilderState = node.condition.filterState.queryBuilderState;
    const rightConditionValue = node.condition.rightConditionValue;
    const applicationStore = useApplicationStore();
    const isNodeExistsNodeChild = isExistsNodeChild(node);
    // Drag and Drop on filter condition value
    const handleDrop = useCallback((item, type) => {
        const itemType = getDNDItemType(item, type);
        if (itemType !== undefined &&
            canDropTypeOntoNodeValue(itemType, node.condition)) {
            try {
                if ((type === QUERY_BUILDER_PROJECTION_COLUMN_DND_TYPE ||
                    type === QUERY_BUILDER_EXPLORER_TREE_DND_TYPE.ENUM_PROPERTY ||
                    type ===
                        QUERY_BUILDER_EXPLORER_TREE_DND_TYPE.PRIMITIVE_PROPERTY) &&
                    isNodeExistsNodeChild) {
                    throw new UnsupportedOperationError('Collection filter does not support property for filter condition value.');
                }
                if (type === QUERY_BUILDER_PROJECTION_COLUMN_DND_TYPE) {
                    const columnState = item.columnState;
                    if (columnState instanceof QueryBuilderSimpleProjectionColumnState) {
                        const columnPropertyExpression = columnState.propertyExpressionState.propertyExpression;
                        if (isCollectionProperty(columnPropertyExpression)) {
                            throw new UnsupportedOperationError('Collection types are not supported for filter condition values.');
                        }
                        else {
                            node.condition.buildRightConditionValueFromPropertyExpressionState(new QueryBuilderPropertyExpressionState(queryBuilderState, cloneAbstractPropertyExpression(columnPropertyExpression, queryBuilderState.observerContext)));
                        }
                    }
                    else {
                        throw new UnsupportedOperationError('Derivation projection columns are not supported for filter condition values.');
                    }
                }
                else if (type === QUERY_BUILDER_EXPLORER_TREE_DND_TYPE.ENUM_PROPERTY ||
                    type === QUERY_BUILDER_EXPLORER_TREE_DND_TYPE.PRIMITIVE_PROPERTY) {
                    const explorerNode = item
                        .node;
                    const propertyExpressionState = new QueryBuilderPropertyExpressionState(queryBuilderState, buildPropertyExpressionFromExplorerTreeNodeData(explorerNode, node.condition.filterState.queryBuilderState.explorerState));
                    if (isCollectionProperty(propertyExpressionState.propertyExpression)) {
                        throw new UnsupportedOperationError('Collection types are not supported for filter condition values.');
                    }
                    else {
                        node.condition.buildRightConditionValueFromPropertyExpressionState(propertyExpressionState);
                    }
                }
                else if (type === QUERY_BUILDER_VARIABLE_DND_TYPE) {
                    const variable = item
                        .variable;
                    node.condition.buildRightConditionValueFromValueSpec(variable);
                }
                else {
                    applicationStore.notificationService.notifyWarning(`Dragging and Dropping ${type} to filter panel is not supported.`);
                }
            }
            catch (error) {
                assertErrorThrown(error);
                applicationStore.notificationService.notifyWarning(error.message);
                return;
            }
        }
        else {
            const conditionValueType = node.condition.propertyExpressionState.propertyExpression.func.value
                .genericType.value.rawType;
            applicationStore.notificationService.notifyWarning(`Incompatible parameter type ${itemType?.name}. ${itemType?.name} is not compatible with type ${conditionValueType.name}.`);
        }
    }, [
        applicationStore,
        queryBuilderState,
        isNodeExistsNodeChild,
        node.condition,
    ]);
    const [{ isFilterValueDragOver }, dropConnector] = useDrop(() => ({
        accept: CAN_DROP_FILTER_VALUE_DND_TYPES,
        canDrop: (item, monitor) => canDropTypeOntoNodeValue(getDNDItemType(item, monitor.getItemType()), node.condition),
        drop: (item, monitor) => {
            if (!monitor.didDrop()) {
                handleDrop(item, monitor.getItemType());
            } // prevent drop event propagation to accomondate for nested DnD
        },
        collect: (monitor) => ({
            isFilterValueDragOver: monitor.isOver({ shallow: true }) && monitor.canDrop(),
        }),
    }), [handleDrop]);
    const ref = useRef(null);
    dropConnector(ref);
    const { isFilterValueDroppable } = useDragLayer((monitor) => ({
        isFilterValueDroppable: monitor.isDragging() &&
            CAN_DROP_FILTER_VALUE_DND_TYPES.includes(monitor.getItemType()?.toString() ?? '') &&
            canDropTypeOntoNodeValue(getDNDItemType(monitor.getItem(), monitor.getItemType()), node.condition),
    }));
    // actions
    const changeOperator = (val) => () => node.condition.changeOperator(val);
    const resetNode = () => {
        node.condition.buildRightConditionValueFromValueSpec(node.condition.operator.getDefaultFilterConditionValue(node.condition));
    };
    const cleanUpReloadValues = () => {
        node.condition.typeaheadSearchState.complete();
    };
    const changeValueSpecification = (val) => {
        node.condition.buildRightConditionValueFromValueSpec(val);
    };
    const debouncedTypeaheadSearch = useMemo(() => debounce((inputValue) => {
        const inputValueSpec = convertTextToPrimitiveInstanceValue(PrimitiveType.STRING, inputValue, queryBuilderState.observerContext);
        return node.condition.handleTypeaheadSearch(inputValueSpec ?? undefined);
    }, 1000), [node, queryBuilderState.observerContext]);
    const selectorConfig = {
        values: node.condition.typeaheadSearchResults,
        isLoading: node.condition.typeaheadSearchState.isInProgress,
        reloadValues: debouncedTypeaheadSearch,
        cleanUpReloadValues,
    };
    const renderRightValue = () => {
        if (rightConditionValue instanceof FilterValueSpecConditionValueState &&
            rightConditionValue.value) {
            return (_jsx("div", { ref: ref, "data-testid": QUERY_BUILDER_TEST_ID.QUERY_BUILDER_FILTER_TREE_CONDITION_NODE_VALUE, className: "query-builder-filter-tree__condition-node__value", children: _jsx(PanelEntryDropZonePlaceholder, { isDragOver: isFilterValueDragOver, isDroppable: isFilterValueDroppable, label: "Change Filter Value", children: _jsx(EditableBasicValueSpecificationEditor, { valueSpecification: rightConditionValue.value, setValueSpecification: changeValueSpecification, graph: graph, observerContext: queryBuilderState.observerContext, typeCheckOption: {
                            expectedType: node.condition.propertyExpressionState.propertyExpression
                                .func.value.genericType.value.rawType,
                        }, resetValue: resetNode, selectorSearchConfig: selectorConfig, isConstant: queryBuilderState.constantState.isValueSpecConstant(rightConditionValue.value), initializeAsEditable: node.isNewlyAdded }) }) }));
        }
        else if (rightConditionValue instanceof
            FilterPropertyExpressionStateConditionValueState) {
            return (_jsx("div", { ref: ref, className: "query-builder-filter-tree__condition-node__value", children: _jsx(PanelEntryDropZonePlaceholder, { isDragOver: isFilterValueDragOver, isDroppable: isFilterValueDroppable, label: "Change Filter Value", children: _jsx(QueryBuilderFilterPropertyExpressionBadge, { rightConditionValue: rightConditionValue, resetNode: resetNode }) }) }));
        }
        return null;
    };
    useEffect(() => {
        node.setIsNewlyAdded(false);
    }, [node]);
    return (_jsx("div", { className: "dnd__entry__container", "data-testid": QUERY_BUILDER_TEST_ID.QUERY_BUILDER_FILTER_TREE_CONDITION_NODE_CONTENT, children: _jsx(PanelEntryDropZonePlaceholder, { isDragOver: isDragOver && !isFilterValueDragOver, alwaysShowChildren: true, children: _jsxs("div", { className: "query-builder-filter-tree__condition-node", children: [_jsx("div", { className: "query-builder-filter-tree__condition-node__property", children: _jsx(QueryBuilderPropertyExpressionBadge, { propertyExpressionState: node.condition.propertyExpressionState }) }), _jsxs(ControlledDropdownMenu, { className: "query-builder-filter-tree__condition-node__operator", title: "Choose Operator...", content: _jsx(MenuContent, { children: node.condition.operators.map((op) => (_jsx(MenuContentItem, { className: "query-builder-filter-tree__condition-node__operator__dropdown__option", onClick: changeOperator(op), children: op.getLabel() }, op.uuid))) }), menuProps: {
                            anchorOrigin: { vertical: 'bottom', horizontal: 'left' },
                            transformOrigin: { vertical: 'top', horizontal: 'left' },
                            elevation: 7,
                        }, children: [_jsx("div", { className: "query-builder-filter-tree__condition-node__operator__label", children: node.condition.operator.getLabel() }), _jsx("div", { className: "query-builder-filter-tree__condition-node__operator__dropdown__trigger", children: _jsx(CaretDownIcon, {}) })] }), renderRightValue()] }) }) }));
});
const QueryBuilderFilterBlankConditionEditor = observer((props) => {
    const { isDragOver, isDroppable } = props;
    return (_jsx("div", { className: "query-builder-filter-tree__node__label__content", children: _jsx(PanelEntryDropZonePlaceholder, { isDragOver: isDragOver, isDroppable: isDroppable, label: "Create Condition", children: _jsx("div", { className: "query-builder-filter-tree__blank-node", children: "blank" }) }) }));
});
const QueryBuilderFilterConditionContextMenu = observer(forwardRef(function QueryBuilderFilterConditionContextMenu(props, ref) {
    const { queryBuilderState, node } = props;
    const filterState = queryBuilderState.filterState;
    const removeNode = () => filterState.removeNodeAndPruneBranch(node);
    const createCondition = () => {
        filterState.addNodeFromNode(new QueryBuilderFilterTreeBlankConditionNodeData(undefined), node);
    };
    const createGroupCondition = () => {
        filterState.addGroupConditionNodeFromNode(node);
    };
    const newGroupWithCondition = () => {
        QueryBuilderTelemetryHelper.logEvent_FilterCreateGroupFromConditionLaunched(queryBuilderState.applicationStore.telemetryService);
        filterState.newGroupWithConditionFromNode(undefined, node);
    };
    return (_jsxs(MenuContent, { ref: ref, children: [node instanceof QueryBuilderFilterTreeGroupNodeData && (_jsx(MenuContentItem, { onClick: createCondition, children: "Add New Condition" })), node instanceof QueryBuilderFilterTreeGroupNodeData && (_jsx(MenuContentItem, { onClick: createGroupCondition, children: "Add New Logical Group" })), node instanceof QueryBuilderFilterTreeConditionNodeData && (_jsx(MenuContentItem, { onClick: newGroupWithCondition, children: "Form a New Logical Group" })), _jsx(MenuContentItem, { onClick: removeNode, children: "Remove" })] }));
}));
const QueryBuilderFilterTreeNodeContainer = observer((props) => {
    const { node, onNodeSelect, innerProps } = props;
    const { queryBuilderState } = innerProps;
    const ref = useRef(null);
    const [isSelectedFromContextMenu, setIsSelectedFromContextMenu] = useState(false);
    const applicationStore = useApplicationStore();
    const filterState = queryBuilderState.filterState;
    const selectNode = () => onNodeSelect?.(node);
    const removeNode = () => filterState.removeNodeAndPruneBranch(node);
    // Drag and Drop
    const handleDrop = useCallback((item, type) => {
        if (QUERY_BUILDER_FILTER_DND_TYPE.CONDITION === type) {
            const nodeBeingDragged = item.node;
            const newCreatedNode = new QueryBuilderFilterTreeConditionNodeData(undefined, filterState.nodes.get(nodeBeingDragged.id).condition);
            if (node instanceof QueryBuilderFilterTreeBlankConditionNodeData) {
                filterState.replaceBlankNodeWithNode(newCreatedNode, node);
                filterState.removeNodeAndPruneBranch(nodeBeingDragged);
            }
            else if (node instanceof QueryBuilderFilterTreeConditionNodeData) {
                filterState.newGroupWithConditionFromNode(newCreatedNode, node);
                filterState.removeNodeAndPruneBranch(nodeBeingDragged);
            }
            else if (node instanceof QueryBuilderFilterTreeGroupNodeData) {
                filterState.addNodeFromNode(newCreatedNode, node);
                filterState.removeNodeAndPruneBranch(nodeBeingDragged);
            }
        }
        else {
            let filterConditionState;
            try {
                let propertyExpression;
                if (type === QUERY_BUILDER_PROJECTION_COLUMN_DND_TYPE) {
                    if (item
                        .columnState instanceof
                        QueryBuilderSimpleProjectionColumnState) {
                        propertyExpression = cloneAbstractPropertyExpression(item
                            .columnState.propertyExpressionState.propertyExpression, queryBuilderState.observerContext);
                    }
                    else {
                        throw new UnsupportedOperationError(`Dragging and Dropping derivation projection column is not supported.`);
                    }
                }
                else {
                    propertyExpression =
                        buildPropertyExpressionFromExplorerTreeNodeData(item.node, filterState.queryBuilderState.explorerState);
                }
                filterConditionState = new FilterConditionState(filterState, propertyExpression);
            }
            catch (error) {
                assertErrorThrown(error);
                applicationStore.notificationService.notifyWarning(error.message);
                return;
            }
            if (node instanceof QueryBuilderFilterTreeOperationNodeData ||
                node instanceof QueryBuilderFilterTreeConditionNodeData ||
                node instanceof QueryBuilderFilterTreeBlankConditionNodeData) {
                buildFilterTree(filterConditionState.propertyExpressionState.propertyExpression, filterState, node);
            }
        }
    }, [applicationStore, filterState, node, queryBuilderState.observerContext]);
    const [{ isDragOver, deepIsDragOver }, dropConnector] = useDrop(() => ({
        accept: queryBuilderState.TEMPORARY__isDnDFetchStructureToFilterSupported
            ? CAN_DROP_FILTER_NODE_DND_TYPES_FETCH_SUPPORTED
            : CAN_DROP_FILTER_NODE_DND_TYPES,
        drop: (item, monitor) => {
            if (!monitor.didDrop()) {
                handleDrop(item, monitor.getItemType());
            } // prevent drop event propagation to accomondate for nested DnD
        },
        collect: (monitor) => ({
            isDragOver: monitor.isOver({ shallow: true }),
            deepIsDragOver: monitor.isOver({ shallow: false }),
        }),
    }), [handleDrop]);
    const [, dragConnector, dragPreviewConnector] = useDrag(() => ({
        type: node instanceof QueryBuilderFilterTreeGroupNodeData
            ? QUERY_BUILDER_FILTER_DND_TYPE.GROUP_CONDITION
            : node instanceof QueryBuilderFilterTreeConditionNodeData
                ? QUERY_BUILDER_FILTER_DND_TYPE.CONDITION
                : QUERY_BUILDER_FILTER_DND_TYPE.BLANK_CONDITION,
        item: () => ({ node }),
        end: () => filterState.setRearrangingConditions(false),
        canDrag: () => node instanceof QueryBuilderFilterTreeConditionNodeData ||
            node instanceof QueryBuilderFilterTreeBlankConditionNodeData,
    }), [node, filterState]);
    dragConnector(dropConnector(ref));
    useDragPreviewLayer(dragPreviewConnector);
    const { isDroppable } = useDragLayer((monitor) => ({
        isDroppable: monitor.isDragging() &&
            (queryBuilderState.TEMPORARY__isDnDFetchStructureToFilterSupported
                ? CAN_DROP_FILTER_NODE_DND_TYPES_FETCH_SUPPORTED
                : CAN_DROP_FILTER_NODE_DND_TYPES).includes(monitor.getItemType()?.toString() ?? ''),
    }));
    // context menu
    const onContextMenuOpen = () => setIsSelectedFromContextMenu(true);
    const onContextMenuClose = () => setIsSelectedFromContextMenu(false);
    const isEmptyExistsNode = node instanceof QueryBuilderFilterTreeExistsNodeData &&
        node.childrenIds.length === 0;
    const showRemoveButton = node instanceof QueryBuilderFilterTreeConditionNodeData ||
        node instanceof QueryBuilderFilterTreeBlankConditionNodeData ||
        isEmptyExistsNode;
    return (_jsx("div", { "data-testid": QUERY_BUILDER_TEST_ID.QUERY_BUILDER_FILTER_TREE_NODE_CONTAINER, className: clsx('query-builder-filter-tree__node__container', {
            'query-builder-filter-tree__node__container--group': node instanceof QueryBuilderFilterTreeGroupNodeData,
            'query-builder-filter-tree__node__container--condition': node instanceof QueryBuilderFilterTreeConditionNodeData ||
                node instanceof QueryBuilderFilterTreeBlankConditionNodeData,
            'query-builder-filter-tree__node__container--exists': node instanceof QueryBuilderFilterTreeExistsNodeData,
            'query-builder-filter-tree__node__container--exists--empty': isEmptyExistsNode,
            'query-builder-filter-tree__node__container--no-hover': filterState.isRearrangingConditions,
            'query-builder-filter-tree__node__container--selected': node === filterState.selectedNode,
            'query-builder-filter-tree__node__container--selected-from-context-menu': isSelectedFromContextMenu,
        }), children: _jsxs(ContextMenu, { content: _jsx(QueryBuilderFilterConditionContextMenu, { queryBuilderState: queryBuilderState, node: node }), menuProps: { elevation: 7 }, onOpen: onContextMenuOpen, onClose: onContextMenuClose, className: "query-builder-filter-tree__node__context-menu", children: [_jsxs("div", { "data-testid": QUERY_BUILDER_TEST_ID.QUERY_BUILDER_FILTER_TREE_NODE_CONTENT, className: "query-builder-filter-tree__node__content", ref: ref, onClick: node instanceof QueryBuilderFilterTreeConditionNodeData ||
                        node instanceof QueryBuilderFilterTreeBlankConditionNodeData
                        ? selectNode
                        : undefined, children: [node instanceof QueryBuilderFilterTreeGroupNodeData && (_jsx(QueryBuilderFilterGroupConditionEditor, { node: node, isDroppable: isDroppable, isDragOver: isDragOver })), node instanceof QueryBuilderFilterTreeExistsNodeData && (_jsx(QueryBuilderFilterExistsConditionEditor, { node: node, humanizePropertyName: filterState.queryBuilderState.explorerState
                                .humanizePropertyName, isDroppable: isDroppable, isDragOver: isDragOver })), node instanceof QueryBuilderFilterTreeConditionNodeData && (_jsx(QueryBuilderFilterConditionEditor, { node: node, isDragOver: deepIsDragOver })), node instanceof QueryBuilderFilterTreeBlankConditionNodeData && (_jsx(QueryBuilderFilterBlankConditionEditor, { node: node, isDragOver: isDragOver, isDroppable: isDroppable }))] }), showRemoveButton && (_jsx("div", { className: "query-builder-filter-tree__node__actions", children: _jsx("button", { className: "query-builder-filter-tree__node__action", tabIndex: -1, title: "Remove", onClick: removeNode, children: _jsx(TimesIcon, {}) }) }))] }) }));
});
const QueryBuilderFilterTreeNodeView = observer((props) => {
    const { node, level, onNodeSelect, getChildNodes, stepPaddingInRem, innerProps, } = props;
    return (_jsxs("div", { "data-testid": QUERY_BUILDER_TEST_ID.QUERY_BUILDER_FILTER_TREE_NODE_BLOCK, className: clsx('query-builder-filter-tree__node__block', {
            'query-builder-filter-tree__node__block--group': node instanceof QueryBuilderFilterTreeGroupNodeData,
            'query-builder-filter-tree__node__block--exists': node instanceof QueryBuilderFilterTreeExistsNodeData,
        }), children: [_jsx(QueryBuilderFilterTreeNodeContainer, { node: node, level: level + 1, stepPaddingInRem: stepPaddingInRem, onNodeSelect: onNodeSelect, innerProps: innerProps }), node.isOpen && getChildNodes(node).length > 0 && (_jsx("div", { "data-testid": QUERY_BUILDER_TEST_ID.QUERY_BUILDER_FILTER_TREE_NODE_CHILDREN, className: "query-builder-filter-tree__node__children", children: getChildNodes(node).map((childNode) => (_jsx(QueryBuilderFilterTreeNodeView, { node: childNode, level: level + 1, onNodeSelect: onNodeSelect, getChildNodes: getChildNodes, innerProps: innerProps }, childNode.id))) }))] }));
});
const QueryBuilderFilterTree = observer((props) => {
    const { queryBuilderState } = props;
    const filterState = queryBuilderState.filterState;
    const rootNodes = filterState.rootIds.map((rootId) => filterState.getNode(rootId));
    const onNodeSelect = (node) => {
        filterState.setSelectedNode(filterState.selectedNode !== node ? node : undefined);
    };
    const getChildNodes = (node) => node instanceof QueryBuilderFilterTreeOperationNodeData
        ? node.childrenIds.map((id) => filterState.getNode(id))
        : [];
    return (_jsx("div", { "data-testid": QUERY_BUILDER_TEST_ID.QUERY_BUILDER_FILTER_TREE, className: "tree-view__node__root query-builder-filter-tree__root", children: rootNodes.map((node) => (_jsx(QueryBuilderFilterTreeNodeView, { level: 0, node: node, getChildNodes: getChildNodes, onNodeSelect: onNodeSelect, innerProps: {
                queryBuilderState,
            } }, node.id))) }));
});
export const QueryBuilderFilterPanel = observer((props) => {
    const { queryBuilderState } = props;
    const applicationStore = useApplicationStore();
    const filterState = queryBuilderState.filterState;
    const rootNode = filterState.getRootNode();
    const collapseTree = () => {
        QueryBuilderTelemetryHelper.logEvent_FilterCollapseTreeLaunched(queryBuilderState.applicationStore.telemetryService);
        filterState.setSelectedNode(undefined);
        filterState.collapseTree();
    };
    const expandTree = () => {
        QueryBuilderTelemetryHelper.logEvent_FilterExpandTreeLaunched(queryBuilderState.applicationStore.telemetryService);
        filterState.setSelectedNode(undefined);
        filterState.expandTree();
    };
    const pruneTree = () => {
        QueryBuilderTelemetryHelper.logEvent_FilterCleanupTreeLaunched(queryBuilderState.applicationStore.telemetryService);
        filterState.pruneTree();
    };
    const simplifyTree = () => {
        QueryBuilderTelemetryHelper.logEvent_FilterSimplifyTreeLaunched(queryBuilderState.applicationStore.telemetryService);
        filterState.simplifyTree();
    };
    const createCondition = () => {
        QueryBuilderTelemetryHelper.logEvent_FilterCreateConditionLaunched(queryBuilderState.applicationStore.telemetryService);
        filterState.addNodeFromNode(new QueryBuilderFilterTreeBlankConditionNodeData(undefined), filterState.selectedNode);
    };
    const allowGroupCreation = filterState.isEmpty || // either the tree is empty
        (filterState.selectedNode && // or a node is currently selected which is...
            (filterState.selectedNode !== rootNode || // either not a root node
                rootNode instanceof QueryBuilderFilterTreeGroupNodeData)); // or if it is the root note, it has to be a group node
    const createGroupCondition = () => {
        QueryBuilderTelemetryHelper.logEvent_FilterCreateLogicalGroupLaunched(queryBuilderState.applicationStore.telemetryService);
        if (allowGroupCreation) {
            filterState.addGroupConditionNodeFromNode(filterState.selectedNode);
        }
    };
    const newGroupWithCondition = () => {
        QueryBuilderTelemetryHelper.logEvent_FilterCreateLogicalGroupLaunched(applicationStore.telemetryService);
        if (filterState.selectedNode instanceof
            QueryBuilderFilterTreeConditionNodeData) {
            filterState.newGroupWithConditionFromNode(undefined, filterState.selectedNode);
        }
    };
    const { isDroppable } = useDragLayer((monitor) => ({
        isDroppable: monitor.isDragging() &&
            (queryBuilderState.TEMPORARY__isDnDFetchStructureToFilterSupported
                ? CAN_DROP_MAIN_GROUP_DND_TYPES_FETCH_SUPPORTED
                : CAN_DROP_MAIN_GROUP_DND_TYPES).includes(monitor.getItemType()?.toString() ?? ''),
    }));
    // Drag and Drop
    const handleDrop = useCallback((item, type) => {
        try {
            let propertyExpression;
            if (type === QUERY_BUILDER_PROJECTION_COLUMN_DND_TYPE) {
                if (item
                    .columnState instanceof QueryBuilderSimpleProjectionColumnState) {
                    propertyExpression = cloneAbstractPropertyExpression(item
                        .columnState.propertyExpressionState.propertyExpression, queryBuilderState.observerContext);
                }
                else {
                    throw new UnsupportedOperationError(`Dragging and Dropping derivation projection column is not supported.`);
                }
            }
            else {
                propertyExpression =
                    buildPropertyExpressionFromExplorerTreeNodeData(item.node, filterState.queryBuilderState.explorerState);
            }
            // NOTE: unfocus the current node when DnD a new node to the tree
            filterState.setSelectedNode(undefined);
            buildFilterTree(propertyExpression, filterState);
        }
        catch (error) {
            assertErrorThrown(error);
            applicationStore.notificationService.notifyWarning(error.message);
            return;
        }
    }, [applicationStore, filterState, queryBuilderState.observerContext]);
    const [{ isDragOver }, dropConnector] = useDrop(() => ({
        accept: queryBuilderState.TEMPORARY__isDnDFetchStructureToFilterSupported
            ? CAN_DROP_MAIN_GROUP_DND_TYPES_FETCH_SUPPORTED
            : CAN_DROP_MAIN_GROUP_DND_TYPES,
        drop: (item, monitor) => {
            if (!monitor.didDrop()) {
                handleDrop(item, monitor.getItemType());
            } // prevent drop event propagation to accomondate for nested DnD
        },
        collect: (monitor) => ({
            isDragOver: monitor.isOver({ shallow: true }),
        }),
    }), [handleDrop]);
    const ref = useRef(null);
    dropConnector(ref);
    return (_jsxs("div", { "data-testid": QUERY_BUILDER_TEST_ID.QUERY_BUILDER_FILTER_PANEL, className: "panel", children: [_jsxs("div", { className: "panel__header", children: [_jsxs("div", { className: "panel__header__title", children: [_jsx("div", { className: "panel__header__title__label", children: "filter" }), filterState.allValidationIssues.length !== 0 && (_jsx(QueryBuilderPanelIssueCountBadge, { issues: filterState.allValidationIssues }))] }), _jsx("div", { className: "panel__header__actions", children: _jsx(ControlledDropdownMenu, { className: "panel__header__action", title: "Show Filter Options Menu...", content: _jsxs(MenuContent, { children: [_jsxs(MenuContentItem, { onClick: createCondition, children: [_jsx(MenuContentItemIcon, { children: _jsx(PlusIcon, {}) }), _jsx(MenuContentItemLabel, { children: "Create Condition" })] }), _jsxs(MenuContentItem, { disabled: !(filterState.selectedNode instanceof
                                            QueryBuilderFilterTreeConditionNodeData), onClick: newGroupWithCondition, children: [_jsx(MenuContentItemIcon, { children: _jsx(PlusCircleIcon, {}) }), _jsx(MenuContentItemLabel, { children: "Create Group From Condition" })] }), _jsxs(MenuContentItem, { disabled: !allowGroupCreation, title: !allowGroupCreation
                                            ? 'Please select a filter node first to create logical group'
                                            : '', onClick: createGroupCondition, children: [_jsx(MenuContentItemIcon, { children: _jsx(NewFolderIcon, {}) }), _jsx(MenuContentItemLabel, { children: "Create Logical Group" })] }), _jsxs(MenuContentItem, { onClick: pruneTree, children: [_jsx(MenuContentItemIcon, { children: _jsx(TrashIcon, {}) }), _jsx(MenuContentItemLabel, { children: "Cleanup Tree" })] }), _jsxs(MenuContentItem, { onClick: simplifyTree, children: [_jsx(MenuContentItemIcon, { children: _jsx(CircleIcon, {}) }), _jsx(MenuContentItemLabel, { children: "Simplify Tree" })] }), _jsxs(MenuContentItem, { onClick: collapseTree, children: [_jsx(MenuContentItemIcon, { children: _jsx(CompressIcon, {}) }), _jsx(MenuContentItemLabel, { children: "Collapse Tree" })] }), _jsxs(MenuContentItem, { onClick: expandTree, children: [_jsx(MenuContentItemIcon, { children: _jsx(ExpandIcon, {}) }), _jsx(MenuContentItemLabel, { children: "Expand Tree" })] })] }), children: _jsx(MoreVerticalIcon, { className: "query-builder__icon__more-options" }) }) })] }), _jsx(PanelContent, { children: _jsxs(PanelDropZone, { isDragOver: isDragOver && filterState.isEmpty, isDroppable: isDroppable && filterState.isEmpty, dropTargetConnector: dropConnector, children: [filterState.isEmpty && (_jsx(BlankPanelPlaceholder, { text: "Add a filter condition", tooltipText: "Drag and drop properties here" })), !filterState.isEmpty && (_jsxs(_Fragment, { children: [_jsx(DragPreviewLayer, { labelGetter: (item) => item.node.dragPreviewLabel, types: Object.values(QUERY_BUILDER_FILTER_DND_TYPE) }), _jsx(QueryBuilderFilterTree, { queryBuilderState: queryBuilderState })] })), isDroppable && !filterState.isEmpty && (_jsx("div", { ref: ref, className: "query-builder-filter-tree__free-drop-zone__container", children: _jsx(PanelEntryDropZonePlaceholder, { isDragOver: isDragOver, isDroppable: isDroppable, className: "query-builder-filter-tree__free-drop-zone", label: "Add filter to main group", children: _jsx(_Fragment, {}) }) }))] }) })] }));
});
//# sourceMappingURL=QueryBuilderFilterPanel.js.map