Skip to content

Commit

Permalink
Fix fragment nodes errors in scenario's tips (#7446)
Browse files Browse the repository at this point in the history
  • Loading branch information
Elmacioro authored and lciolecki committed Jan 20, 2025
1 parent b91d69c commit 0a7ae6d
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 3 deletions.
19 changes: 16 additions & 3 deletions designer/client/src/components/graph/Graph.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -741,16 +741,18 @@ export class Graph extends React.Component<Props> {
};
};

#highlightNodes = (selectedNodeIds: string[] = [], process = this.props.scenario): void => {
#highlightNodes = (selectedNodeIds: string[] = [], scenario = this.props.scenario): void => {
this.processGraphPaper.freeze();
const elements = this.graph.getElements();
elements.forEach((cell) => {
this.#unhighlightCell(cell, nodeValidationError);
this.#unhighlightCell(cell, nodeFocused);
});

const validationErrors = ProcessUtils.getValidationErrors(process);
const invalidNodeIds = [...keys(validationErrors?.invalidNodes), ...validationErrors.globalErrors.flatMap((e) => e.nodeIds)];
const validationErrors = ProcessUtils.getValidationErrors(scenario);
const invalidNodeKeys = [...keys(validationErrors?.invalidNodes)];
const invalidFragmentNodes = this.#getInvalidFragmentNodes(invalidNodeKeys, scenario.scenarioGraph);
const invalidNodeIds = [...invalidNodeKeys, ...validationErrors.globalErrors.flatMap((e) => e.nodeIds), ...invalidFragmentNodes];

// fast indicator for loose nodes, faster than async validation
elements.forEach((el) => {
Expand All @@ -766,6 +768,17 @@ export class Graph extends React.Component<Props> {
this.processGraphPaper.unfreeze();
};

#getInvalidFragmentNodes = (invalidNodeIds: string[], scenarioGraph: ScenarioGraph): string[] => {
const invalidFragmentNodeIds: Set<string> = new Set();
invalidNodeIds.forEach((invalidNodeId) => {
if (NodeUtils.isFragmentNodeReference(invalidNodeId, scenarioGraph)) {
const fragmentId = scenarioGraph.nodes.find((n) => invalidNodeId.startsWith(n.id))?.id;
invalidFragmentNodeIds.add(fragmentId);
}
});
return [...invalidFragmentNodeIds];
};

#highlightCell(cell: dia.Cell, className: string): void {
this.processGraphPaper.findViewByModel(cell)?.highlight(null, {
highlighter: {
Expand Down
19 changes: 19 additions & 0 deletions designer/client/src/components/graph/NodeUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,25 @@ class NodeUtils {
}
}
};

// We can recognize that a node is part of a referenced fragment by making sure that:
// 1. The nodeId is not present in the scenarioGraph
// 2. There is a fragment node in the scenarioGraph whose name is part of the nodeId
isFragmentNodeReference = (nodeId: NodeId, scenarioGraph: ScenarioGraph): boolean => {
const isNodePresentInScenarioGraph = !!this.getNodeById(nodeId, scenarioGraph);
return !isNodePresentInScenarioGraph && scenarioGraph.nodes.some((n) => nodeId.startsWith(n.id));
};

getDetailsFromFragmentNode = (nodeId: NodeId, scenarioGraph: ScenarioGraph): { fragmentId: string; fragmentNodeId: string } | null => {
if (this.isFragmentNodeReference(nodeId, scenarioGraph)) {
const fragment = scenarioGraph.nodes.find((n) => nodeId.startsWith(n.id));
return {
fragmentId: fragment.ref.id,
fragmentNodeId: nodeId.replace(`${fragment.id}-`, ""),
};
}
return null;
};
}

//TODO this pattern is not necessary, just export every public function as in actions.js
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ import { NodeId, NodeType } from "../../../types";
import { ErrorHeader } from "./ErrorHeader";
import { NodeErrorLink } from "./NodeErrorLink";
import { Scenario } from "../../Process/types";
import { NavLink } from "react-router-dom";
import { ErrorLinkStyle } from "./styled";
import { visualizationUrl } from "../../../common/VisualizationUrl";

interface NodeErrorsLinkSectionProps {
nodeIds: NodeId[];
Expand All @@ -25,6 +28,23 @@ export default function NodeErrorsLinkSection(props: NodeErrorsLinkSectionProps)
<div>
<ErrorHeader message={message} />
{nodeIds.map((nodeId, index) => {
const isFragmentNodeReference = NodeUtils.isFragmentNodeReference(nodeId, scenario.scenarioGraph);
if (isFragmentNodeReference) {
const { fragmentId, fragmentNodeId } = NodeUtils.getDetailsFromFragmentNode(nodeId, scenario.scenarioGraph);
return (
<React.Fragment key={nodeId}>
<ErrorLinkStyle
variant={"body2"}
component={NavLink}
target={"_blank"}
to={visualizationUrl(fragmentId, fragmentNodeId)}
>
{nodeId}
</ErrorLinkStyle>
{index < nodeIds.length - 1 ? separator : null}
</React.Fragment>
);
}
const details =
nodeId === "properties"
? NodeUtils.getProcessPropertiesNode(scenario, unsavedName)
Expand Down
3 changes: 3 additions & 0 deletions docs/Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@
* [#7404](https://github.com/TouK/nussknacker/pull/7404) Fix spel evaluation error when using conversion extensions methods or array.get extension method
* [#7420](https://github.com/TouK/nussknacker/pull/7420) Add toInteger and toIntegerOrNull conversions. Also add canBeInteger extension
* [#7438](https://github.com/TouK/nussknacker/pull/7438) Map int32 integer format in OpenAPI schema to the `Integer` type
* [#7446](https://github.com/TouK/nussknacker/pull/7446) Small changes regarding node errors in fragments used in scenarios:
* Fragment error node tips in scenarios are now clickable and open problematic node edit window in a new tab.
* Fragment nodes are now highlighted when they contain nodes with errors.

## 1.18

Expand Down

0 comments on commit 0a7ae6d

Please sign in to comment.