Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

kie-issues#451: Implement autolayout on the new React-based DMN Editor for DMN files without Diagram information (part 1) #2130

Merged
merged 27 commits into from
Feb 2, 2024
Merged
Show file tree
Hide file tree
Changes from 26 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
b451b39
Autolayout
tiagobento Jan 17, 2024
e204d47
Renaming
tiagobento Jan 24, 2024
4e29330
External data types not being rendered
tiagobento Jan 24, 2024
f2b0a77
Removing unnecessary code
tiagobento Jan 24, 2024
eefdb6a
Comment re-render label
tiagobento Jan 24, 2024
d68e4e5
Preparing for automatic DRG view and fix ongoingConnection bug
tiagobento Jan 26, 2024
bc8aed2
Allow formatting DRDs that don't include all nodes
tiagobento Jan 26, 2024
086f319
Add ordinal numbers to DRD lis
tiagobento Jan 26, 2024
c7e88d6
Remove text annotation extra border
tiagobento Jan 26, 2024
fa62ba9
Auto-focus DRD name when creating a new one
tiagobento Jan 26, 2024
8082017
Oops
tiagobento Jan 26, 2024
75c8a86
Alignment improvements
tiagobento Jan 26, 2024
8b5bea5
Allow external edges to be present when their nodes are
tiagobento Jan 26, 2024
c885149
Add missing comment
tiagobento Jan 26, 2024
ee38686
Allow hiding nodes from DRD withoout deleting them from DRG. Enable d…
tiagobento Jan 26, 2024
865d1f2
Only use edges that have both ends on the diagram
tiagobento Jan 26, 2024
fa59666
Improve hiding nodes from DRD
tiagobento Jan 26, 2024
8b3b635
Don't allow expanding typerefSelector for external nods
tiagobento Jan 26, 2024
d2e6ee3
Add contained decisions togheter with DS when adding it to a DRD
tiagobento Jan 27, 2024
91ac38a
Improve node deletion when doing it from any DRD
tiagobento Jan 29, 2024
c6fe383
Revert experiment
tiagobento Jan 29, 2024
8f32308
Removing 'view drg' button
tiagobento Jan 30, 2024
30d77bc
Self review
tiagobento Jan 30, 2024
1df21d8
Merge remote-tracking branch 'origin/main' into autolayout-dmn-pr
tiagobento Jan 30, 2024
7fc6592
Comment unfinished code
tiagobento Jan 30, 2024
3f5a98b
Remove ordering by nodes order
tiagobento Jan 31, 2024
9f96555
PR review
tiagobento Feb 2, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions packages/dmn-editor/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@
"@visx/text": "^3.3.0",
"d3-drag": "^3.0.0",
"d3-selection": "^3.0.0",
"elkjs": "^0.9.1",
"fast-deep-equal": "^3.1.3",
"immer": "^10.0.3",
"moment": "^2.29.4",
"react": "^17.0.2",
Expand Down
52 changes: 44 additions & 8 deletions packages/dmn-editor/src/DmnEditor.css
Original file line number Diff line number Diff line change
Expand Up @@ -318,17 +318,51 @@
}
/* (end) version popover */

/* (begin) overlays panel toggle */
.kie-dmn-editor--overlay-panel-popover .pf-c-popover__body {
/* (begin) autolayout panel button */
.kie-dmn-editor--autolayout-panel-toggle {
width: 42px;
background: #fff;
border-radius: 40px;
border: 1px solid black;
}
.kie-dmn-editor--autolayout-panel-toggle:not(:last-child) {
margin-right: 16px;
}

.kie-dmn-editor--autolayout-panel-toggle:hover {
box-shadow: -4px 4px 2px 0px rgb(127 127 127);
}
.kie-dmn-editor--autolayout-panel-toggle-button {
margin: 0;
width: 40px;
height: 40px;
max-width: 40px;
border-radius: 40px;
border: 0;
background: white;
}
.kie-dmn-editor--autolayout-panel-toggle-button:hover {
filter: brightness(95%);
}
.kie-dmn-editor--autolayout-panel-toggle-button:active {
filter: brightness(90%);
}
/* (end) autolayout panel toggle *
/
/* (begin) autolayout panel toggle */
tiagobento marked this conversation as resolved.
Show resolved Hide resolved
.kie-dmn-editor--autolayout-panel-popover .pf-c-popover__body {
padding: 0;
}
.kie-dmn-editor--overlays-panel-toggle {
margin-right: 16px;
width: 42px;
background: #fff;
border-radius: 40px;
border: 1px solid black;
}
.kie-dmn-editor--overlays-panel-toggle:not(:last-child) {
margin-right: 16px;
}

.kie-dmn-editor--overlays-panel-toggle:hover {
box-shadow: -4px 4px 2px 0px rgb(127 127 127);
}
Expand Down Expand Up @@ -395,7 +429,8 @@
left: 58px;
overflow: auto;
box-shadow: 0px 5px 10px 0px lightgray;
background: white;
background: rgb(255, 255, 255, 90%);
backdrop-filter: blur(4px);
width: 400px;
}
.kie-dmn-editor--external-nodes-panel-toggle {
Expand Down Expand Up @@ -700,14 +735,13 @@ circle.kie-dmn-editor--diagram-edge-waypoint:hover {
}
.kie-dmn-editor--external-nodes-list-item {
border-radius: 999px;
background: white;
}
.kie-dmn-editor--external-nodes-list-item:hover {
filter: brightness(95%);
background-color: rgba(0, 0, 0, 0.1);
cursor: grab;
}
.kie-dmn-editor--external-nodes-list-item:active {
filter: brightness(90%);
background-color: rgba(0, 0, 0, 0.15);
cursor: grabbing;
}
Comment on lines 736 to 743
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cosmetic changes...

/* (end) external nodes */
Expand Down Expand Up @@ -903,7 +937,9 @@ th {
fill: rgba(0, 107, 164, 0.1) !important;
}

.react-flow__node.selected:not(.react-flow__node-node_unknown) > .kie-dmn-editor--node-shape > * {
.react-flow__node.selected:not(.react-flow__node-node_unknown):not(.react-flow__node-node_textAnnotation)
> .kie-dmn-editor--node-shape
> * {
stroke: #006ba4 !important;
}
Comment on lines +937 to 941
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Text annotation nodes have a special "selected" style.


Expand Down
99 changes: 53 additions & 46 deletions packages/dmn-editor/src/DmnEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,47 +20,40 @@
import "@patternfly/react-core/dist/styles/base.css";
import "reactflow/dist/style.css";

import * as React from "react";
import * as ReactDOM from "react-dom";
import * as RF from "reactflow";
import { useCallback, useEffect, useImperativeHandle, useRef, useState, useMemo } from "react";
import { AllDmnMarshallers, DmnLatestModel } from "@kie-tools/dmn-marshaller";
import { PMML } from "@kie-tools/pmml-editor-marshaller";
import { Drawer, DrawerContent, DrawerContentBody } from "@patternfly/react-core/dist/js/components/Drawer";
import { Label } from "@patternfly/react-core/dist/js/components/Label";
import { Tab, TabTitleIcon, TabTitleText, Tabs } from "@patternfly/react-core/dist/js/components/Tabs";
import { FileIcon } from "@patternfly/react-icons/dist/js/icons/file-icon";
import { InfrastructureIcon } from "@patternfly/react-icons/dist/js/icons/infrastructure-icon";
import { PficonTemplateIcon } from "@patternfly/react-icons/dist/js/icons/pficon-template-icon";
import { original } from "immer";
import * as React from "react";
import { useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState } from "react";
import * as ReactDOM from "react-dom";
import { ErrorBoundary, ErrorBoundaryPropsWithFallback } from "react-error-boundary";
import * as RF from "reactflow";
import { DmnEditorContextProvider, useDmnEditor } from "./DmnEditorContext";
import { DmnEditorErrorFallback } from "./DmnEditorErrorFallback";
import { BoxedExpression } from "./boxedExpressions/BoxedExpression";
import { DataTypes } from "./dataTypes/DataTypes";
import { Diagram, DiagramRef } from "./diagram/Diagram";
import { DmnVersionLabel } from "./diagram/DmnVersionLabel";
import { DmnEditorExternalModelsContextProvider } from "./includedModels/DmnEditorDependenciesContext";
import { IncludedModels } from "./includedModels/IncludedModels";
import { BeePropertiesPanel } from "./propertiesPanel/BeePropertiesPanel";
import { DiagramPropertiesPanel } from "./propertiesPanel/DiagramPropertiesPanel";
import {
DmnEditorStoreApiContext,
DmnEditorTab,
StoreApiType,
createDmnEditorStore,
defaultStaticState,
useDmnEditorStore,
useDmnEditorStoreApi,
} from "./store/Store";
import { ComputedStateCache } from "./store/ComputedStateCache";
import { Computed, DmnEditorTab, createDmnEditorStore, defaultStaticState } from "./store/Store";
import { DmnEditorStoreApiContext, StoreApiType, useDmnEditorStore, useDmnEditorStoreApi } from "./store/StoreContext";
import { DmnDiagramSvg } from "./svg/DmnDiagramSvg";
import { useEffectAfterFirstRender } from "./useEffectAfterFirstRender";
import { Label } from "@patternfly/react-core/dist/js/components/Label";
import { BeePropertiesPanel } from "./propertiesPanel/BeePropertiesPanel";
import { DmnEditorDerivedStoreContextProvider, useDmnEditorDerivedStore } from "./store/DerivedStore";
import { DmnEditorContextProvider, useDmnEditor } from "./DmnEditorContext";
import { DmnEditorExternalModelsContextProvider } from "./includedModels/DmnEditorDependenciesContext";
import { ErrorBoundary, ErrorBoundaryPropsWithFallback } from "react-error-boundary";
import { DmnEditorErrorFallback } from "./DmnEditorErrorFallback";
import { DmnLatestModel, AllDmnMarshallers } from "@kie-tools/dmn-marshaller";
import { PMML } from "@kie-tools/pmml-editor-marshaller";
import { original } from "immer";
import { INITIAL_COMPUTED_CACHE } from "./store/computed/initial";

import "@kie-tools/dmn-marshaller/dist/kie-extensions"; // This is here because of the KIE Extension for DMN.
import "./DmnEditor.css"; // Leave it for last, as this overrides some of the PF and RF styles.

import { DmnDiagramSvg } from "./svg/DmnDiagramSvg";

const ON_MODEL_CHANGE_DEBOUNCE_TIME_IN_MS = 500;

const SVG_PADDING = 20;
Expand Down Expand Up @@ -163,10 +156,15 @@ export const DmnEditorInternal = ({
onModelChange,
forwardRef,
}: DmnEditorProps & { forwardRef?: React.Ref<DmnEditorRef> }) => {
const { boxedExpressionEditor, dmn, navigation, dispatch, diagram } = useDmnEditorStore((s) => s);
const boxedExpressionEditorActiveDrgElementId = useDmnEditorStore((s) => s.boxedExpressionEditor.activeDrgElementId);
const isBeePropertiesPanelOpen = useDmnEditorStore((s) => s.boxedExpressionEditor.propertiesPanel.isOpen);
const isDiagramPropertiesPanelOpen = useDmnEditorStore((s) => s.diagram.propertiesPanel.isOpen);
const navigationTab = useDmnEditorStore((s) => s.navigation.tab);
const dmn = useDmnEditorStore((s) => s.dmn);
const isDiagramEditingInProgress = useDmnEditorStore((s) => s.computed(s).isDiagramEditingInProgress());

const dmnEditorStoreApi = useDmnEditorStoreApi();
const { isDiagramEditingInProgress, importsByNamespace } = useDmnEditorDerivedStore();

const { dmnModelBeforeEditingRef, dmnEditorRootElementRef } = useDmnEditor();

// Refs
Expand All @@ -179,20 +177,25 @@ export const DmnEditorInternal = ({
useImperativeHandle(
forwardRef,
() => ({
reset: (model) => dispatch.dmn.reset(model),
reset: (model) => {
const state = dmnEditorStoreApi.getState();
return state.dispatch(state).dmn.reset(model);
},
getDiagramSvg: async () => {
const nodes = diagramRef.current?.getReactFlowInstance()?.getNodes();
const edges = diagramRef.current?.getReactFlowInstance()?.getEdges();
if (!nodes || !edges) {
return undefined;
}

const bounds = RF.getRectOfNodes(nodes);
const bounds = RF.getNodesBounds(nodes);

const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
svg.setAttribute("width", bounds.width + SVG_PADDING * 2 + "");
svg.setAttribute("height", bounds.height + SVG_PADDING * 2 + "");

const state = dmnEditorStoreApi.getState();

// We're still on React 17.
// eslint-disable-next-line react/no-deprecated
ReactDOM.render(
Expand All @@ -201,9 +204,9 @@ export const DmnEditorInternal = ({
<DmnDiagramSvg
nodes={nodes}
edges={edges}
snapGrid={diagram.snapGrid}
importsByNamespace={importsByNamespace}
thisDmn={dmnEditorStoreApi.getState().dmn}
snapGrid={state.diagram.snapGrid}
importsByNamespace={state.computed(state).importsByNamespace()}
thisDmn={state.dmn}
/>
</g>,
svg
Expand All @@ -212,7 +215,7 @@ export const DmnEditorInternal = ({
return new XMLSerializer().serializeToString(svg);
},
}),
[diagram.snapGrid, dispatch.dmn, dmnEditorStoreApi, importsByNamespace]
[dmnEditorStoreApi]
);

// Make sure the DMN Editor reacts to props changing.
Expand All @@ -225,7 +228,7 @@ export const DmnEditorInternal = ({
state.dmn.model = model;
dmnModelBeforeEditingRef.current = model;
});
}, [dmnEditorStoreApi, dispatch.dmn, model]);
}, [dmnEditorStoreApi, model]);

useStateAsItWasBeforeConditionBecameTrue(
dmn.model,
Expand Down Expand Up @@ -311,16 +314,16 @@ export const DmnEditorInternal = ({
<div ref={dmnEditorRootElementRef} className={"kie-dmn-editor--root"}>
<Tabs
isFilled={true}
activeKey={navigation.tab}
activeKey={navigationTab}
onSelect={onTabChanged}
role={"region"}
className={"kie-dmn-editor--tabs"}
>
<Tab eventKey={DmnEditorTab.EDITOR} title={tabTitle.editor}>
{navigation.tab === DmnEditorTab.EDITOR && (
{navigationTab === DmnEditorTab.EDITOR && (
<>
{!boxedExpressionEditor.activeDrgElementId && (
<Drawer isExpanded={diagram.propertiesPanel.isOpen} isInline={true} position={"right"}>
{!boxedExpressionEditorActiveDrgElementId && (
<Drawer isExpanded={isDiagramPropertiesPanelOpen} isInline={true} position={"right"}>
<DrawerContent panelContent={diagramPropertiesPanel}>
<DrawerContentBody>
<div className={"kie-dmn-editor--diagram-container"} ref={diagramContainerRef}>
Expand All @@ -331,8 +334,8 @@ export const DmnEditorInternal = ({
</DrawerContent>
</Drawer>
)}
{boxedExpressionEditor.activeDrgElementId && (
<Drawer isExpanded={boxedExpressionEditor.propertiesPanel.isOpen} isInline={true} position={"right"}>
{boxedExpressionEditorActiveDrgElementId && (
<Drawer isExpanded={isBeePropertiesPanelOpen} isInline={true} position={"right"}>
<DrawerContent panelContent={beePropertiesPanel}>
<DrawerContentBody>
<div className={"kie-dmn-editor--bee-container"} ref={beeContainerRef}>
Expand All @@ -347,19 +350,25 @@ export const DmnEditorInternal = ({
</Tab>

<Tab eventKey={DmnEditorTab.DATA_TYPES} title={tabTitle.dataTypes}>
{navigation.tab === DmnEditorTab.DATA_TYPES && <DataTypes />}
{navigationTab === DmnEditorTab.DATA_TYPES && <DataTypes />}
</Tab>

<Tab eventKey={DmnEditorTab.INCLUDED_MODELS} title={tabTitle.includedModels}>
{navigation.tab === DmnEditorTab.INCLUDED_MODELS && <IncludedModels />}
{navigationTab === DmnEditorTab.INCLUDED_MODELS && <IncludedModels />}
</Tab>
</Tabs>
</div>
);
};

export const DmnEditor = React.forwardRef((props: DmnEditorProps, ref: React.Ref<DmnEditorRef>) => {
const storeRef = React.useRef<StoreApiType>(createDmnEditorStore(props.model));
const store = useMemo(
() => createDmnEditorStore(props.model, new ComputedStateCache<Computed>(INITIAL_COMPUTED_CACHE)),
// Purposefully empty. This memoizes the initial value of the store
// eslint-disable-next-line react-hooks/exhaustive-deps
[]
);
const storeRef = React.useRef<StoreApiType>(store);

const resetState: ErrorBoundaryPropsWithFallback["onReset"] = useCallback(({ args }) => {
storeRef.current?.setState((state) => {
Expand All @@ -373,9 +382,7 @@ export const DmnEditor = React.forwardRef((props: DmnEditorProps, ref: React.Ref
<ErrorBoundary FallbackComponent={DmnEditorErrorFallback} onReset={resetState}>
<DmnEditorExternalModelsContextProvider {...props}>
<DmnEditorStoreApiContext.Provider value={storeRef.current}>
<DmnEditorDerivedStoreContextProvider>
<DmnEditorInternal forwardRef={ref} {...props} />
</DmnEditorDerivedStoreContextProvider>
<DmnEditorInternal forwardRef={ref} {...props} />
</DmnEditorStoreApiContext.Provider>
</DmnEditorExternalModelsContextProvider>
</ErrorBoundary>
Expand Down
Loading
Loading