
META-INF.resources.js.components.ModelBuilder.Diagram.Diagram.tsx Maven / Gradle / Ivy
The newest version!
/**
* SPDX-FileCopyrightText: (c) 2023 Liferay, Inc. https://liferay.com
* SPDX-License-Identifier: LGPL-2.1-or-later OR LicenseRef-Liferay-DXP-EULA-2.0.0-2023-06
*/
import {API} from '@liferay/object-js-components-web';
import classNames from 'classnames';
import {
LearnMessage,
LearnResourcesContext,
openToast,
} from 'frontend-js-components-web';
import React, {useCallback, useState} from 'react';
import ReactFlow, {
Background,
Connection,
ConnectionLineType,
ConnectionMode,
Controls,
Edge,
MiniMap,
Node,
isEdge,
isNode,
} from 'react-flow-renderer';
import {ModalAddObjectRelationship} from '../../ObjectRelationship/ModalAddObjectRelationship';
import {getUpdatedModelBuilderStructurePayload} from '../../ViewObjectDefinitions/objectDefinitionUtil';
import DefaultObjectRelationshipEdge from '../Edges/DefaultObjectRelationshipEdge';
import SelfObjectRelationshipEdge from '../Edges/SelfObjectRelationshipEdge';
import {useObjectFolderContext} from '../ModelBuilderContext/objectFolderContext';
import {TYPES} from '../ModelBuilderContext/typesEnum';
import {ObjectDefinitionNode} from '../ObjectDefinitionNode/ObjectDefinitionNode';
import {ObjectRelationshipEdgeData} from '../types';
import {getUnsupportedObjectRelationshipErrorMessage} from '../utils';
import './Diagram.scss';
let ReactFlowDefault = ReactFlow;
// `react-flow-renderer` provides both a commonjs and ESM version.
// We need this logic here so that both work. Unit tests rely on commonjs and
// our DXP runtime uses ESM.
// @ts-ignore
if (ReactFlowDefault.default) {
// @ts-ignore
ReactFlowDefault = ReactFlowDefault.default;
}
const NODE_TYPES = {
objectDefinitionNode: ObjectDefinitionNode,
};
const EDGE_TYPES = {
defaultObjectRelationshipEdge: DefaultObjectRelationshipEdge,
selfObjectRelationshipEdge: SelfObjectRelationshipEdge,
treeStructureObjectRelationshipEdge: DefaultObjectRelationshipEdge,
};
function DiagramBuilder() {
const [
{
baseResourceURL,
elements,
isLoadingObjectFolder,
learnResourceContext,
selectedObjectFolder,
showChangesSaved,
showSidebars,
},
dispatch,
] = useObjectFolderContext();
const [showAddObjectRelationshipModal, setShowAddObjectRelationshipModal] =
useState(false);
const [
newObjectRelationshipSourceNodeProps,
setNewObjectRelationshipSourceNodeProps,
] = useState<{
parameterRequired: boolean;
sourceNode: {
erc: string;
};
targetNode: {
erc: string;
};
}>();
const edges: Edge[] = [];
const nodes: Node[] = [];
elements.forEach((element) => {
if (isEdge(element)) {
edges.push(element as Edge);
}
else {
nodes.push(element as Node);
}
});
const onConnect = useCallback(
(connection: Connection | Edge) => {
if (connection.targetHandle === connection.sourceHandle) {
return;
}
const sourceNode = elements.find(
(node) => isNode(node) && node.id === connection.source
) as Node;
const targetNode = elements.find(
(node) => isNode(node) && node.id === connection.target
) as Node;
const unsupportedObjectRelationship =
getUnsupportedObjectRelationshipErrorMessage(
nodes,
sourceNode,
targetNode
);
if (unsupportedObjectRelationship?.errorMessage) {
openToast({
message: unsupportedObjectRelationship?.errorMessage,
toastProps: unsupportedObjectRelationship.learnMessage
? {
actions: (
),
}
: undefined,
type: 'warning',
});
}
else {
setShowAddObjectRelationshipModal(true);
setNewObjectRelationshipSourceNodeProps({
parameterRequired: sourceNode?.data?.parameterRequired!,
sourceNode: {
erc: sourceNode?.data?.externalReferenceCode!,
},
targetNode: {
erc: targetNode?.data?.externalReferenceCode!,
},
});
}
},
// eslint-disable-next-line react-hooks/exhaustive-deps
[elements]
);
const onNodeDragStop = async (node: Node) => {
const updatedObjectFolderItems =
selectedObjectFolder.objectFolderItems.map((objectFolderItem) => {
if (
objectFolderItem.objectDefinitionExternalReferenceCode ===
node.data?.externalReferenceCode
) {
return {
...objectFolderItem,
positionX: node.position.x,
positionY: node.position.y,
};
}
return objectFolderItem;
});
const updatedObjectFolder = {
...selectedObjectFolder,
objectFolderItems: updatedObjectFolderItems,
};
await API.putObjectFolderByExternalReferenceCode({
externalReferenceCode: updatedObjectFolder.externalReferenceCode,
id: updatedObjectFolder.id,
label: updatedObjectFolder.label,
name: updatedObjectFolder.name,
objectFolderItems: updatedObjectFolder.objectFolderItems,
});
dispatch({
payload: {
newObjectDefinitionNodePosition: {
x: node.position.x,
y: node.position.y,
},
objectDefinitionNodes: nodes,
objectRelationshipEdges: edges,
updatedObjectDefinitionNodeId: node.data?.id as number,
updatedObjectFolder,
},
type: TYPES.SET_SELECTED_OBJECT_DEFINITION_NODE_POSITION,
});
if (!showChangesSaved) {
dispatch({
payload: {updatedShowChangesSaved: true},
type: TYPES.SET_SHOW_CHANGES_SAVED,
});
}
};
const setNodeHandleConnection = (nodeHandleConnectable: boolean) => {
dispatch({
payload: {
nodeHandleConnectable,
},
type: TYPES.SET_NODE_HANDLE_CONNECTION,
});
};
const updateModelBuilderStructure = async (
newObjectRelationshipId: number
) => {
const payload = await getUpdatedModelBuilderStructurePayload(
baseResourceURL,
selectedObjectFolder.name
);
dispatch({
payload: {
...payload,
dispatch,
rightSidebarType: 'objectRelationshipDetails',
selectedObjectRelationshipId: newObjectRelationshipId,
},
type: TYPES.UPDATE_MODEL_BUILDER_STRUCTURE,
});
dispatch({
payload: {
selectedObjectRelationshipId: newObjectRelationshipId,
},
type: TYPES.SET_SELECTED_OBJECT_RELATIONSHIP_EDGE,
});
openToast({
message: Liferay.Language.get(
'relationship-was-created-successfully'
),
});
};
return (
{showAddObjectRelationshipModal && (
setShowAddObjectRelationshipModal(false)
}
hasDefinedObjectDefinitionTarget
learnResources={learnResourceContext}
objectDefinitionExternalReferenceCode1={
newObjectRelationshipSourceNodeProps?.sourceNode.erc!
}
objectDefinitionExternalReferenceCode2={
newObjectRelationshipSourceNodeProps?.targetNode.erc!
}
objectRelationshipParameterRequired={
newObjectRelationshipSourceNodeProps?.parameterRequired!
}
onAfterAddObjectRelationship={(newObjectRelationship) =>
updateModelBuilderStructure(newObjectRelationship.id)
}
reload={false}
/>
)}
setNodeHandleConnection(true)}
onConnectStop={() => setNodeHandleConnection(false)}
onNodeDragStop={(_, node) => onNodeDragStop(node)}
>
{!isLoadingObjectFolder ? (
) : (
)}
);
}
export default DiagramBuilder;
© 2015 - 2025 Weber Informatics LLC | Privacy Policy