/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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 { Action, BeeTableHeaderVisibility, BeeTableOperation, BeeTableOperationConfig, BeeTableProps, BoxedFor, BoxedIterator, DmnBuiltInDataType, ExpressionChangedArgs, generateUuid, Normalized, } from "../../api"; import { BeeTable, BeeTableColumnUpdate, BeeTableRef } from "../../table/BeeTable"; import { ResizerStopBehavior } from "../../resizing/ResizingWidthsContext"; import React, { useCallback, useMemo, useRef } from "react"; import { DMN_LATEST__tChildExpression, DMN_LATEST__tTypedChildExpression } from "@kie-tools/dmn-marshaller"; import * as ReactTable from "react-table"; import { useBoxedExpressionEditorI18n } from "../../i18n"; import { BeeTableReadOnlyCell } from "../../table/BeeTable/BeeTableReadOnlyCell"; import { IteratorExpressionCell } from "./IteratorExpressionCell"; import { useBoxedExpressionEditor, useBoxedExpressionEditorDispatch } from "../../BoxedExpressionEditorContext"; import { NestedExpressionContainerContext } from "../../resizing/NestedExpressionContainerContext"; import { useNestedExpressionContainerWithNestedExpressions } from "../../resizing/Hooks"; import { ITERATOR_EXPRESSION_CLAUSE_COLUMN_MIN_WIDTH, ITERATOR_EXPRESSION_EXTRA_WIDTH, ITERATOR_EXPRESSION_LABEL_COLUMN_WIDTH, } from "../../resizing/WidthConstants"; import { DEFAULT_EXPRESSION_VARIABLE_NAME } from "../../expressionVariable/ExpressionVariableMenu"; import { IteratorExpressionVariableCell } from "./IteratorExpressionVariableCell"; type ROWTYPE = Normalized; export type IteratorClause = { child: DMN_LATEST__tTypedChildExpression | DMN_LATEST__tChildExpression | string | undefined; label: string; }; export function IteratorExpressionComponent({ isNested, parentElementId, expression: expression, }: { expression: Normalized; isNested: boolean; parentElementId: string; }) { const { i18n } = useBoxedExpressionEditorI18n(); const { expressionHolderId, widthsById, isReadOnly } = useBoxedExpressionEditor(); const { setExpression } = useBoxedExpressionEditorDispatch(); const id = expression["@_id"]!; const tableColumns = useMemo[]>(() => { return [ { accessor: expressionHolderId as any, // FIXME: https://github.com/kiegroup/kie-issues/issues/169 label: expression["@_label"] ?? DEFAULT_EXPRESSION_VARIABLE_NAME, isRowIndexColumn: false, dataType: expression["@_typeRef"] ?? DmnBuiltInDataType.Undefined, width: undefined, columns: [ { accessor: "label", label: i18n.label, width: ITERATOR_EXPRESSION_LABEL_COLUMN_WIDTH, minWidth: ITERATOR_EXPRESSION_LABEL_COLUMN_WIDTH, isInlineEditable: false, isRowIndexColumn: false, isWidthPinned: true, isWidthConstant: true, dataType: undefined as any, }, { accessor: "child", label: i18n.child, width: undefined, minWidth: ITERATOR_EXPRESSION_CLAUSE_COLUMN_MIN_WIDTH, isInlineEditable: false, isRowIndexColumn: false, dataType: undefined as any, }, ], }, ]; }, [expression, expressionHolderId, i18n.child, i18n.label]); const headerVisibility = useMemo(() => { return isNested ? BeeTableHeaderVisibility.None : BeeTableHeaderVisibility.SecondToLastLevel; }, [isNested]); const beeTableOperationConfig = useMemo(() => { return [ { group: i18n.contextEntry, items: [{ name: i18n.rowOperations.reset, type: BeeTableOperation.RowReset }], }, { group: i18n.terms.selection.toUpperCase(), items: [{ name: i18n.terms.copy, type: BeeTableOperation.SelectionCopy }], }, ]; }, [i18n]); const getIterableRowLabel = useCallback( (rowNumber: number) => { if (rowNumber === 0) { if (expression.__$$element === "for") { return i18n.iterableRowLabel.for; } else if (expression.__$$element === "some") { return i18n.iterableRowLabel.some; } else if (expression.__$$element === "every") { return i18n.iterableRowLabel.every; } else { throw new Error("Unknown IteratorExpression element"); } } else if (rowNumber === 1) { return i18n.iterableRowLabel.in; } else if (rowNumber === 2) { if (expression.__$$element === "for") { return i18n.iterableRowLabel.return; } else if (expression.__$$element === "some" || expression.__$$element === "every") { return i18n.iterableRowLabel.satisfies; } else { throw new Error("Unknown IteratorExpression element"); } } else { throw new Error("IteratorExpression can't have more than 3 rows."); } }, [expression.__$$element, i18n.iterableRowLabel] ); const getIterableRowElement = useCallback( (rowNumber: number) => { if (rowNumber === 0) { return expression["@_iteratorVariable"] ?? ""; } else if (rowNumber === 1) { return expression.in; } else { switch (expression.__$$element) { case "for": return expression.return; case "every": case "some": return expression.satisfies; } } }, [expression] ); const tableRows = useMemo(() => { return [ { label: getIterableRowLabel(0), child: getIterableRowElement(0) }, { label: getIterableRowLabel(1), child: getIterableRowElement(1) }, { label: getIterableRowLabel(2), child: getIterableRowElement(2) }, ]; }, [getIterableRowElement, getIterableRowLabel]); const allowedOperations = useCallback(() => { return [BeeTableOperation.SelectionCopy, BeeTableOperation.RowReset]; }, []); const beeTableRef = useRef(null); const cellComponentByColumnAccessor: BeeTableProps["cellComponentByColumnAccessor"] = useMemo(() => { return { label: (props) => { return ; }, child: (props) => { if (props.rowIndex === 0) { return ( ); } else if (props.rowIndex === 1 || props.rowIndex === 2) { return ( ); } else { throw new Error("IteratorExpression can't have more than 3 rows."); } }, }; }, [id, parentElementId]); const { nestedExpressionContainerValue, onColumnResizingWidthChange } = useNestedExpressionContainerWithNestedExpressions( useMemo(() => { const nestedExpressions = [ expression.in.expression, expression.__$$element === "for" ? expression.return.expression : expression.satisfies.expression, ]; return { nestedExpressions: nestedExpressions, fixedColumnActualWidth: ITERATOR_EXPRESSION_LABEL_COLUMN_WIDTH, fixedColumnResizingWidth: { value: ITERATOR_EXPRESSION_LABEL_COLUMN_WIDTH, isPivoting: false }, fixedColumnMinWidth: ITERATOR_EXPRESSION_LABEL_COLUMN_WIDTH, nestedExpressionMinWidth: ITERATOR_EXPRESSION_CLAUSE_COLUMN_MIN_WIDTH, extraWidth: ITERATOR_EXPRESSION_EXTRA_WIDTH, expression: expression, flexibleColumnIndex: 2, widthsById: widthsById, }; }, [expression, widthsById]) ); const onColumnUpdates = useCallback( ([{ name, typeRef }]: BeeTableColumnUpdate[]) => { const expressionChangedArgs: ExpressionChangedArgs = { action: Action.VariableChanged, variableUuid: expressionHolderId, typeChange: typeRef !== expression["@_typeRef"] ? { from: expression["@_typeRef"] ?? "", to: typeRef, } : undefined, nameChange: name !== expression["@_label"] ? { from: expression["@_label"] ?? "", to: name, } : undefined, }; setExpression({ setExpressionAction: (prev: Normalized) => { // Do not inline this variable for type safety. See https://github.com/microsoft/TypeScript/issues/241 const ret: Normalized = { ...prev, "@_label": name, "@_typeRef": typeRef, }; return ret; }, expressionChangedArgs, }); }, [expression, expressionHolderId, setExpression] ); const onRowReset = useCallback( (args: { rowIndex: number }) => { setExpression({ setExpressionAction: (prev: Normalized) => { if (args.rowIndex === 0) { // Do not inline this variable for type safety. See https://github.com/microsoft/TypeScript/issues/241 const ret: Normalized = { ...prev, "@_iteratorVariable": undefined, }; return ret; } else if (args.rowIndex === 1) { // Do not inline this variable for type safety. See https://github.com/microsoft/TypeScript/issues/241 const ret: Normalized = { ...prev, in: { "@_id": generateUuid(), expression: undefined!, }, // SPEC DISCREPANCY }; return ret; } else if (args.rowIndex === 2) { if (prev.__$$element === "for") { // Do not inline this variable for type safety. See https://github.com/microsoft/TypeScript/issues/241 const ret: Normalized = { ...prev, return: { "@_id": generateUuid(), expression: undefined!, }, // SPEC DISCREPANCY }; return ret; } else if (prev.__$$element === "some" || prev.__$$element === "every") { // Do not inline this variable for type safety. See https://github.com/microsoft/TypeScript/issues/241 const iterator: Normalized = { ...prev, satisfies: { "@_id": generateUuid(), expression: undefined!, }, // SPEC DISCREPANCY }; return iterator; } else { throw new Error("Nested expression type not supported in IteratorExpression."); } } else { throw new Error("IteratorExpression shouldn't have more than 3 rows."); } }, expressionChangedArgs: { action: Action.RowReset, rowIndex: args.rowIndex }, }); }, [setExpression] ); return (
isReadOnly={isReadOnly} isEditableHeader={!isReadOnly} forwardRef={beeTableRef} resizerStopBehavior={ResizerStopBehavior.SET_WIDTH_WHEN_SMALLER} tableId={id} headerLevelCountForAppendingRowIndexColumn={1} headerVisibility={headerVisibility} cellComponentByColumnAccessor={cellComponentByColumnAccessor} columns={tableColumns} rows={tableRows} operationConfig={beeTableOperationConfig} allowedOperations={allowedOperations} onColumnUpdates={onColumnUpdates} onRowReset={onRowReset} onColumnResizingWidthChange={onColumnResizingWidthChange} shouldRenderRowIndexColumn={false} shouldShowRowsInlineControls={false} shouldShowColumnsInlineControls={false} />
); }