JDM Editor
repository·master·Indexed 43 days ago
https://github.com/gorules/jdm-editorAn open-source React component library for creating and managing JSON Decision Model (JDM) files through visual interfaces like Decision Graphs and Decision Tables. Version 1.52.0 includes components such as DecisionGraph and JdmConfigProvider, as well as integration with ZEN Engine WASM for expression validation, linting, and type checking.
What's inside JDM Editor
- ZEN Engine WASM is an experimental version of the ZEN Engine designed specifically for web platforms. At its current stage of development, its functionality is limited to supporting expressions only.
Basic usage of DecisionGraph and JdmConfigProvider
masterTo implement the JDM Editor, you must wrap your components in a
JdmConfigProvider. The primary component for visual modeling isDecisionGraph. You should also import the required CSS styles for the editor to render correctly.import '@gorules/jdm-editor/dist/style.css'; import { DecisionGraph, JdmConfigProvider } from '@gorules/jdm-editor'; // ... inside your component <JdmConfigProvider> <DecisionGraph value={graph} onChange={(val) => setGraph(val as any)} /> </JdmConfigProvider>Install @gorules/jdm-editor via npm
masterTo use the JDM Editor in your project, install the package using npm.
npm i @gorules/jdm-editorSelf-host Monaco Editor in Vite
masterIf you are using Vite and need to self-host the Monaco Editor (used by the JDM Editor), you must configure the
MonacoEnvironmentto handle workers for different languages like JSON, CSS, HTML, and TypeScript. This ensures that language features like syntax highlighting and IntelliSense work correctly in your environment.import type { Monaco } from '@monaco-editor/react'; import { loader } from '@monaco-editor/react'; import * as monaco from 'monaco-editor'; import editorWorker from 'monaco-editor/esm/vs/editor/editor.worker?worker'; import cssWorker from 'monaco-editor/esm/vs/language/css/css.worker?worker'; import htmlWorker from 'monaco-editor/esm/vs/language/html/html.worker?worker'; import jsonWorker from 'monaco-editor/esm/vs/language/json/json.worker?worker'; import tsWorker from 'monaco-editor/esm/vs/language/typescript/ts.worker?worker'; declare global { interface Window { monaco?: Monaco; } } self.monaco = monaco; self.MonacoEnvironment = { getWorker(workerId: string, label: string): Promise<Worker> | Worker { if (label === 'json') { return new jsonWorker(); } if (label === 'css' || label === 'scss' || label === 'less') { return new cssWorker(); } if (label === 'html' || label === 'handlebars' || label === 'razor') { return new htmlWorker(); } if (label === 'typescript' || label === 'javascript') { return new tsWorker(); } return new editorWorker(); }, }; loader.config({ monaco });Structure of a Decision Model
masterA complete decision model is defined by the
decisionModelSchema, which consists of an array ofnodesand an array ofedges.Each node must include common properties:
id,name, andposition(x and y coordinates). Edges connect nodes usingsourceIdandtargetId.const model = { nodes: [ { id: 'node-1', type: 'inputNode', name: 'My Input', position: { x: 100, y: 100 }, content: { schema: '...' } } ], edges: [ { id: 'edge-1', sourceId: 'node-1', targetId: 'node-2', type: 'edge' } ] };Define node inputs using InputSchema
masterWhen using
createJdmNode, you can define a schema for the node's configuration data using theinputsarray. This schema determines the shape of theconfigobject within the node's content and dictates which UI controls are rendered in the node's settings form.Each input in the
inputsarray follows theInputSchematype:Property Type Description namestringThe key in the configuration object. Supports dot notation for nested objects (e.g., user.name).control'text' | 'bool'The UI control to use. 'text'uses aCodeEditor;'bool'uses aCheckbox.labelstring(optional)The label displayed in the form. Nested Objects: If you use dot notation in the
name(e.g.,settings.threshold), thecreateJdmNodeutility will automatically infer a nested object structure for the node's data type.// Example of defining inputs that create a nested config object const inputs = [ { name: 'metadata.title', control: 'text', label: 'Title' }, { name: 'metadata.active', control: 'bool', label: 'Is Active' } ] as const; // The resulting config object will be: // { metadata: { title: string, active: boolean } }Define the structure of a Decision Graph
masterA
DecisionGraphTyperepresents the complete state of a decision graph, consisting of an array ofnodesand an array ofedges. This structure is used to model the logic flow within the JDM Editor.export type DecisionGraphType = { nodes: DecisionNode[]; edges: DecisionEdge[]; };Integrate the DecisionTableProvider into your application
masterTo use the Decision Table editor components and state management, wrap your component tree with the
DecisionTableProvider. This provider initializes the state, listeners, and actions required for managing decision table data, columns, and rules.import { DecisionTableProvider } from '@gorules/jdm-editor/components/decision-table/context/dt-store.context'; function App() { return ( <DecisionTableProvider> <YourDecisionTableEditor /> </DecisionTableProvider> ); }Import JDM Editor styles
masterThe JDM Editor package requires its CSS styles to be imported to ensure components render correctly. This is typically done at the entry point of your application.
import '@gorules/jdm-editor/dist/index.css'; // Or the equivalent path depending on your build setupConfigure the DecisionTable component
masterThe
DecisionTablecomponent allows for tabular decision modeling. Use these props to manage data, schema, and rendering.export type DecisionTableProps = { id?: string; defaultValue?: DecisionTableType; value?: DecisionTableType; onChange?: (decisionTable: DecisionTableType) => void; activeRules?: string[]; permission?: DecisionTablePermission; disabled?: boolean; disableHitPolicy?: boolean; minColWidth?: number; colWidth?: number; inputsSchema?: SchemaSelectProps[]; outputsSchema?: SchemaSelectProps[]; cellRenderer?: (props: CellProps) => JSX.Element | null | undefined; };Configure the DecisionGraph component
masterThe
DecisionGraphcomponent is used to design decision models visually. Use the following props to control its behavior and appearance.export type DecisionGraphProps = { id?: string; forwardedRef?: (instance: DecisionGraphRef) => void; defaultValue?: DecisionGraphType; value?: DecisionGraphType; disabled?: boolean; viewConfig?: ViewConfig; components?: CustomNodeType[]; onChange?: (val: DecisionGraphType) => void; manager?: DragDropManager; reactFlowProOptions?: ProOptions; onReactFlowInit?: () => void; };Validate ZEN expressions with validateZenExpression()
masterUse
validateZenExpressionto perform manual linting and type checking on ZEN expressions. This function returns an array of CodeMirrorDiagnosticobjects. It checks for syntax errors (via the WASM engine) and validates the expression against provided types and expected variable types.Key Behaviors:
- Syntax Errors: Detects
parserError,lexerError,compilerError, andvmError. - Type Checking: Validates the expression against a list of
ZenTypeobjects. If a type error is found, it maps the error message to awarning,info, orhintbased on the error string prefix. - Unary Expressions: If
expressionTypeis set to'unary', it ensures the result evaluates to aBooltype. If not, it reports a mismatch. - Variable Type Matching: If
expectedVariableTypeis provided, it checks if the expression's result satisfies that type. Instrictmode, matching'Any'against specific types is disallowed. - Severity: In
strictmode, type mismatches are reported aserror; otherwise, they are reported aswarning.
Note: This function requires the ZEN Engine WASM to be available to perform syntax validation.
import { validateZenExpression } from '@gorules/jdm-editor'; const diagnostics = validateZenExpression({ source: 'my_expression', expressionType: 'standard', strict: true, types: [...], expectedVariableType: ... });- Syntax Errors: Detects