Skip to content

Commit

Permalink
kie-issues#1547: DMN Editor: Render evaluation highlights in the Boxe…
Browse files Browse the repository at this point in the history
…d Expression Editor (#2681)

Co-authored-by: Luiz João Motta <[email protected]>
  • Loading branch information
jomarko and ljmotta authored Dec 18, 2024
1 parent 37d7322 commit 74659fd
Show file tree
Hide file tree
Showing 12 changed files with 411 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ export interface BoxedExpressionEditorProps {
isReadOnly?: boolean;
/** PMML models available to use on Boxed PMML Function */
pmmlDocuments?: PmmlDocument[];
evaluationHitsCountById?: Map<string, number>;
/** The containing HTMLElement which is scrollable */
scrollableParentRef: React.RefObject<HTMLElement>;
/** Parsed variables used for syntax coloring and auto-complete */
Expand All @@ -79,6 +80,7 @@ export function BoxedExpressionEditor({
isResetSupportedOnRootExpression,
scrollableParentRef,
pmmlDocuments,
evaluationHitsCountById,
onRequestFeelVariables,
widthsById,
onWidthsChange,
Expand All @@ -103,6 +105,7 @@ export function BoxedExpressionEditor({
isReadOnly={isReadOnly}
dataTypes={dataTypes}
pmmlDocuments={pmmlDocuments}
evaluationHitsCountById={evaluationHitsCountById}
onRequestFeelVariables={onRequestFeelVariables}
widthsById={widthsById}
hideDmn14BoxedExpressions={hideDmn14BoxedExpressions}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ export interface BoxedExpressionEditorContextType {
pmmlDocuments?: PmmlDocument[];
dataTypes: DmnDataType[];
isReadOnly?: boolean;
evaluationHitsCountById?: Map<string, number>;

// State
currentlyOpenContextMenu: string | undefined;
Expand Down Expand Up @@ -74,6 +75,7 @@ export function BoxedExpressionEditorContextProvider({
beeGwtService,
children,
pmmlDocuments,
evaluationHitsCountById,
scrollableParentRef,
onRequestFeelVariables,
widthsById,
Expand Down Expand Up @@ -114,6 +116,7 @@ export function BoxedExpressionEditorContextProvider({
dataTypes,
isReadOnly,
pmmlDocuments,
evaluationHitsCountById,

//state // FIXME: Move to a separate context (https://github.com/apache/incubator-kie-issues/issues/168)
currentlyOpenContextMenu,
Expand Down
2 changes: 2 additions & 0 deletions packages/boxed-expression-component/src/api/BeeTable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,8 @@ export interface BeeTableProps<R extends object> {
shouldShowColumnsInlineControls: boolean;
resizerStopBehavior: ResizerStopBehavior;
lastColumnMinWidth?: number;
/** Method should return true for table rows, that can display evaluation hits count, false otherwise. If not set, BeeTableBody defaults to false. */
supportsEvaluationHitsCount?: (row: ReactTable.Row<R>) => boolean;
}

/** Possible status for the visibility of the Table's Header */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -226,14 +226,23 @@ export function ConditionalExpression({
[setExpression]
);

const getRowKey = useCallback((row: ReactTable.Row<ROWTYPE>) => {
return row.original.part["@_id"];
}, []);

const supportsEvaluationHitsCount = useCallback((row: ReactTable.Row<ROWTYPE>) => {
return row.original.label !== "if";
}, []);

return (
<NestedExpressionContainerContext.Provider value={nestedExpressionContainerValue}>
<div data-testid={"kie-tools--boxed-expression-component---conditional"}>
<div className={"conditional-expression"} data-testid={"kie-tools--boxed-expression-component---conditional"}>
<BeeTable<ROWTYPE>
isReadOnly={isReadOnly}
isEditableHeader={!isReadOnly}
resizerStopBehavior={ResizerStopBehavior.SET_WIDTH_WHEN_SMALLER}
tableId={id}
getRowKey={getRowKey}
headerLevelCountForAppendingRowIndexColumn={1}
headerVisibility={headerVisibility}
cellComponentByColumnAccessor={cellComponentByColumnAccessor}
Expand All @@ -247,6 +256,7 @@ export function ConditionalExpression({
shouldRenderRowIndexColumn={false}
shouldShowRowsInlineControls={false}
shouldShowColumnsInlineControls={false}
supportsEvaluationHitsCount={supportsEvaluationHitsCount}
/>
</div>
</NestedExpressionContainerContext.Provider>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1045,6 +1045,10 @@ export function DecisionTableExpression({
[beeTableRows.length]
);

const supportsEvaluationHitsCount = useCallback((row: ReactTable.Row<ROWTYPE>) => {
return true;
}, []);

return (
<div className={`decision-table-expression ${decisionTableExpression["@_id"]}`}>
<BeeTable<ROWTYPE>
Expand Down Expand Up @@ -1073,6 +1077,7 @@ export function DecisionTableExpression({
shouldRenderRowIndexColumn={true}
shouldShowRowsInlineControls={true}
shouldShowColumnsInlineControls={true}
supportsEvaluationHitsCount={supportsEvaluationHitsCount}
// lastColumnMinWidth={lastColumnMinWidth} // FIXME: Check if this is a good strategy or not when doing https://github.com/apache/incubator-kie-issues/issues/181
/>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,82 @@
border: 0;
}

.expression-container-box
.conditional-expression
.table-component
tr.evaluation-hits-count-row-overlay
> td:first-child::before {
content: "";
position: absolute;
background-color: rgb(215, 201, 255, 0.5);
left: 0;
top: 0;
width: 100%;
height: 100%;
}

.expression-container-box
.conditional-expression
.table-component
tr.evaluation-hits-count-row-overlay
> td
> div
> div
> div
> .logic-type-selected-header::before {
content: "";
position: absolute;
background-color: rgb(215, 201, 255, 0.5);
left: 0;
top: 0;
width: 100%;
height: 100%;
}

.expression-container-box
.decision-table-expression
.table-component
tr.evaluation-hits-count-row-overlay
> td::before {
content: "";
position: absolute;
background-color: rgb(215, 201, 255, 0.5);
left: 0;
top: 0;
width: 100%;
height: 100%;
}

.evaluation-hits-count-badge-non-colored::before {
content: attr(data-evaluation-hits-count);
font-size: 0.8em;
text-align: left;
color: white;
background-color: var(--pf-global--palette--black-600);
position: absolute;
top: 0px;
left: 0px;
height: 40px;
width: 40px;
clip-path: polygon(0% 100%, 100% 0%, 0% 0%);
padding-left: 0.2em;
}

.evaluation-hits-count-badge-colored::before {
content: attr(data-evaluation-hits-count);
font-size: 0.8em;
text-align: left;
color: white;
background-color: rgb(134, 106, 212);
position: absolute;
top: 0px;
left: 0px;
height: 40px;
width: 40px;
clip-path: polygon(0% 100%, 100% 0%, 0% 0%);
padding-left: 0.2em;
}

.expression-container .table-component table tbody tr td.row-index-cell-column {
padding: 1.1em 0;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ export function BeeTableInternal<R extends object>({
resizerStopBehavior,
lastColumnMinWidth,
rowWrapper,
supportsEvaluationHitsCount,
}: BeeTableProps<R> & {
selectionRef?: React.RefObject<BeeTableSelectionRef>;
}) {
Expand Down Expand Up @@ -657,6 +658,7 @@ export function BeeTableInternal<R extends object>({
onDataCellKeyUp={onDataCellKeyUp}
lastColumnMinWidth={lastColumnMinWidth}
isReadOnly={isReadOnly}
supportsEvaluationHitsCount={supportsEvaluationHitsCount}
/>
</table>
<BeeTableContextMenuHandler
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import { BeeTableTdForAdditionalRow } from "./BeeTableTdForAdditionalRow";
import { BeeTableTd } from "./BeeTableTd";
import { BeeTableCoordinatesContextProvider } from "../../selection/BeeTableSelectionContext";
import { ResizerStopBehavior } from "../../resizing/ResizingWidthsContext";
import { useBoxedExpressionEditor } from "../../BoxedExpressionEditorContext";

export interface BeeTableBodyProps<R extends object> {
/** Table instance */
Expand Down Expand Up @@ -55,6 +56,8 @@ export interface BeeTableBodyProps<R extends object> {
rowWrapper?: React.FunctionComponent<React.PropsWithChildren<{ row: R; rowIndex: number }>>;

isReadOnly: boolean;
/** See BeeTable.ts */
supportsEvaluationHitsCount?: (row: ReactTable.Row<R>) => boolean;
}

export function BeeTableBody<R extends object>({
Expand All @@ -72,18 +75,37 @@ export function BeeTableBody<R extends object>({
lastColumnMinWidth,
rowWrapper,
isReadOnly,
supportsEvaluationHitsCount,
}: BeeTableBodyProps<R>) {
const { evaluationHitsCountById } = useBoxedExpressionEditor();

const renderRow = useCallback(
(row: ReactTable.Row<R>, rowIndex: number) => {
reactTableInstance.prepareRow(row);

const rowKey = getRowKey(row);
const rowEvaluationHitsCount = evaluationHitsCountById ? evaluationHitsCountById?.get(rowKey) ?? 0 : undefined;
const canDisplayEvaluationHitsCountRowOverlay =
rowEvaluationHitsCount !== undefined && (supportsEvaluationHitsCount?.(row) ?? false);
const rowClassName = `${rowKey}${canDisplayEvaluationHitsCountRowOverlay && rowEvaluationHitsCount > 0 ? " evaluation-hits-count-row-overlay" : ""}`;

let evaluationHitsCountBadgeColumnIndex = -1;
const renderTr = () => (
<tr className={rowKey} key={rowKey} data-testid={`kie-tools--bee--expression-row-${rowIndex}`}>
<tr className={rowClassName} key={rowKey} data-testid={`kie-tools--bee--expression-row-${rowIndex}`}>
{row.cells.map((cell, cellIndex) => {
const columnKey = getColumnKey(reactTableInstance.allColumns[cellIndex]);
const isColumnToRender =
(cell.column.isRowIndexColumn && shouldRenderRowIndexColumn) || !cell.column.isRowIndexColumn;
if (evaluationHitsCountBadgeColumnIndex === -1 && isColumnToRender) {
// We store the index of the first column in the row
// We show evaluation hits count badge in this column
evaluationHitsCountBadgeColumnIndex = cellIndex;
}
const canDisplayEvaluationHitsCountBadge =
canDisplayEvaluationHitsCountRowOverlay && cellIndex === evaluationHitsCountBadgeColumnIndex;
return (
<React.Fragment key={columnKey}>
{((cell.column.isRowIndexColumn && shouldRenderRowIndexColumn) || !cell.column.isRowIndexColumn) && (
{isColumnToRender && (
<BeeTableTd<R>
resizerStopBehavior={resizerStopBehavior}
shouldShowRowsInlineControls={shouldShowRowsInlineControls}
Expand All @@ -104,6 +126,8 @@ export function BeeTableBody<R extends object>({
cellIndex === reactTableInstance.allColumns.length - 1 ? lastColumnMinWidth : undefined
}
isReadOnly={isReadOnly}
canDisplayEvaluationHitsCountBadge={canDisplayEvaluationHitsCountBadge}
evaluationHitsCount={rowEvaluationHitsCount}
/>
)}
</React.Fragment>
Expand All @@ -114,8 +138,6 @@ export function BeeTableBody<R extends object>({

const RowWrapper = rowWrapper;

const rowKey = getRowKey(row);

return (
<React.Fragment key={rowKey}>
{RowWrapper ? (
Expand All @@ -129,6 +151,8 @@ export function BeeTableBody<R extends object>({
);
},
[
evaluationHitsCountById,
supportsEvaluationHitsCount,
reactTableInstance,
rowWrapper,
getRowKey,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@ export interface BeeTableTdProps<R extends object> {
onDataCellClick?: (columnID: string) => void;
onDataCellKeyUp?: (columnID: string) => void;
isReadOnly: boolean;
/** True means the table cell can display evaluation hits count. False means evaluation hits count is not displayed in the table cell. */
canDisplayEvaluationHitsCountBadge?: boolean;
/** Actuall evaluation hits count number that will be displayed in the table cell if 'canDisplayEvaluationHitsCountBadge' is set to true. */
evaluationHitsCount?: number;
}

export type HoverInfo =
Expand All @@ -73,6 +77,8 @@ export function BeeTableTd<R extends object>({
onDataCellClick,
onDataCellKeyUp,
isReadOnly,
canDisplayEvaluationHitsCountBadge,
evaluationHitsCount,
}: BeeTableTdProps<R>) {
const [isResizing, setResizing] = useState(false);
const [hoverInfo, setHoverInfo] = useState<HoverInfo>({ isHovered: false });
Expand Down Expand Up @@ -225,6 +231,14 @@ export function BeeTableTd<R extends object>({
return onDataCellKeyUp?.(column.id);
}, [column.id, onDataCellKeyUp]);

const evaluationHitsCountBadgeClassName = useMemo(() => {
return canDisplayEvaluationHitsCountBadge
? (evaluationHitsCount ?? 0) > 0
? "evaluation-hits-count-badge-colored"
: "evaluation-hits-count-badge-non-colored"
: "";
}, [canDisplayEvaluationHitsCountBadge, evaluationHitsCount]);

return (
<BeeTableCoordinatesContextProvider coordinates={coordinates}>
<td
Expand All @@ -246,9 +260,11 @@ export function BeeTableTd<R extends object>({
}}
>
{column.isRowIndexColumn ? (
<>{rowIndexLabel}</>
<div className={evaluationHitsCountBadgeClassName} data-evaluation-hits-count={evaluationHitsCount}>
{rowIndexLabel}
</div>
) : (
<>
<div className={evaluationHitsCountBadgeClassName} data-evaluation-hits-count={evaluationHitsCount}>
{tdContent}

{!isReadOnly && shouldRenderResizer && (
Expand All @@ -262,7 +278,7 @@ export function BeeTableTd<R extends object>({
setResizing={setResizing}
/>
)}
</>
</div>
)}

{!isReadOnly &&
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@ export function BoxedExpressionEditorStory(props?: Partial<BoxedExpressionEditor
}
expressionHolderTypeRef={props?.expressionHolderTypeRef ?? args?.expressionHolderTypeRef}
expression={expressionState}
evaluationHitsCountById={props?.evaluationHitsCountById ?? args?.evaluationHitsCountById}
onExpressionChange={setExpressionState}
onWidthsChange={onWidthsChange}
dataTypes={props?.dataTypes ?? args?.dataTypes ?? dataTypes}
Expand Down
Loading

0 comments on commit 74659fd

Please sign in to comment.