process-graph 1.0.5 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +85 -17
- package/dist/bin.d.ts +1 -0
- package/dist/bin.js +92 -0
- package/dist/cli.d.ts +512 -0
- package/dist/cli.js +3 -0
- package/dist/control-aDk9560d.js +294 -0
- package/dist/detail-panel-B1ZmMuJT.js +341 -0
- package/dist/dist-BpCBmnMl.js +582 -0
- package/dist/dist-HLlW8vgT.js +1388 -0
- package/dist/dist-IjrgWhHQ.js +3 -0
- package/dist/errors-BZe5WzCn.js +19 -0
- package/dist/exit-codes-0ultCqdS.js +23 -0
- package/dist/graphql-C1j5wQFz.d.ts +631 -0
- package/dist/index-CCfe0csl.d.ts +353 -0
- package/dist/index-CmZOswkx.d.ts +512 -0
- package/dist/index-CoA6vXqe.d.ts +404 -0
- package/dist/index-CptUHq6F.d.ts +58 -0
- package/dist/index-CrM5qWUA.d.ts +110 -0
- package/dist/index-DhbvDgK4.d.ts +1582 -0
- package/dist/index-DricKcyl.d.ts +421 -0
- package/dist/index.d.ts +111 -4
- package/dist/index.js +929 -5
- package/dist/layout-CCM-KBdp.js +307 -0
- package/dist/layout.d.ts +8 -0
- package/dist/layout.js +2 -0
- package/dist/node-AchI1T-K.js +40 -0
- package/dist/open-CyRXJ4bt.js +29 -0
- package/dist/parse-CuipC_2K.js +41 -0
- package/dist/queries-CCexJAE2.js +2202 -0
- package/dist/react-flow/style.css +658 -0
- package/dist/react-flow.d.ts +173 -0
- package/dist/react-flow.js +450 -0
- package/dist/react.d.ts +2 -0
- package/dist/react.js +107 -0
- package/dist/rolldown-runtime-D7D4PA-g.js +13 -0
- package/dist/router-D4gtTlXm.js +188 -0
- package/dist/schema-CVnS6HiX.js +234 -0
- package/dist/selection-BW_xXWOy.js +314 -0
- package/dist/source/github/node.d.ts +16 -0
- package/dist/source/github/node.js +2 -0
- package/dist/source/github.d.ts +49 -0
- package/dist/source/github.js +201 -0
- package/dist/source-DRDpEA8Q.js +1316 -0
- package/dist/status-Bm1CGu9C.js +11 -0
- package/dist/store/node.d.ts +24 -0
- package/dist/store/node.js +2 -0
- package/dist/store/wasm/worker.d.ts +16 -0
- package/dist/store/wasm/worker.js +98 -0
- package/dist/store/wasm.d.ts +9 -0
- package/dist/store/wasm.js +11 -0
- package/dist/store-BcR70CaO.js +1287 -0
- package/dist/store.d.ts +1328 -0
- package/dist/store.js +238 -0
- package/dist/ui/style.css +351 -0
- package/dist/ui.d.ts +235 -0
- package/dist/ui.js +2 -0
- package/dist/validate-DF3mQZww.js +125 -0
- package/package.json +148 -13
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import { F as Status } from "./index-CCfe0csl.js";
|
|
2
|
+
import { G as IdSpace, O as Projection, g as Model, x as Element } from "./index-CmZOswkx.js";
|
|
3
|
+
import { A as Flowchart, E as Swimlane, x as StateMachine } from "./index-CoA6vXqe.js";
|
|
4
|
+
import { i as LayoutView, n as LayoutOptions, r as LayoutResult, s as Direction } from "./index-CrM5qWUA.js";
|
|
5
|
+
import { A as ElementFilter, rt as Run, y as NamedElement } from "./index-DricKcyl.js";
|
|
6
|
+
import { ReactElement } from "react";
|
|
7
|
+
import { ColorMode, Edge, EdgeProps, Node, NodeProps } from "@xyflow/react";
|
|
8
|
+
//#region ../../ui/graph/react-flow/dist/use-layout.d.ts
|
|
9
|
+
/** Where laying out a view stands. */
|
|
10
|
+
type LayoutState<I extends IdSpace> = {
|
|
11
|
+
readonly status: "pending";
|
|
12
|
+
} | {
|
|
13
|
+
readonly status: "placed";
|
|
14
|
+
readonly result: LayoutResult<I>;
|
|
15
|
+
} | {
|
|
16
|
+
readonly status: "failed";
|
|
17
|
+
readonly error: unknown;
|
|
18
|
+
};
|
|
19
|
+
/** The layout options a view is laid out with: everything `layout` takes but the signal, which the hook owns. */
|
|
20
|
+
type FlowLayoutOptions = Omit<LayoutOptions, "signal">;
|
|
21
|
+
/**
|
|
22
|
+
* Lays out a view with `graph-layout`'s `layout`, again whenever the view or the options change, aborting a layout that is no longer wanted.
|
|
23
|
+
* @param view - The flowchart, swimlane or state machine to place. Keep it stable between renders.
|
|
24
|
+
* @param options - Direction, spacing and the engine. Keep it stable between renders.
|
|
25
|
+
* @returns `pending` until the layout resolves, then `placed` with the positions, sizes and lanes, or `failed` with what the engine threw.
|
|
26
|
+
*/
|
|
27
|
+
export declare const useLayout: <I extends IdSpace>(view: LayoutView<I>, options: FlowLayoutOptions) => LayoutState<I>;
|
|
28
|
+
//#endregion
|
|
29
|
+
//#region ../../ui/graph/react-flow/dist/process-flow.d.ts
|
|
30
|
+
/** A projection React Flow can draw: anything but a sequence diagram, which `SequenceDiagram` draws. */
|
|
31
|
+
type FlowProjection<I extends IdSpace> = Exclude<Projection<I>, {
|
|
32
|
+
readonly notation: "sequence";
|
|
33
|
+
}>;
|
|
34
|
+
interface ProcessFlowProps<I extends IdSpace> {
|
|
35
|
+
/** The model, its overlay and facts. Keep each part stable between renders. */
|
|
36
|
+
readonly run: Run<I>;
|
|
37
|
+
/** The view to draw: a flowchart, a swimlane or a state machine. Keep it stable between renders. */
|
|
38
|
+
readonly projection: FlowProjection<I>;
|
|
39
|
+
/** The canvas's accessible name. */
|
|
40
|
+
readonly label: string;
|
|
41
|
+
/** Direction, spacing and the layout engine, passed to `graph-layout`. The engine defaults to elkjs; a test injects a stub. Keep it stable between renders. */
|
|
42
|
+
readonly layout?: FlowLayoutOptions | undefined;
|
|
43
|
+
/** Which elements to show. Defaults to all of them. */
|
|
44
|
+
readonly filter?: ElementFilter | undefined;
|
|
45
|
+
/** React Flow's own colour mode, for its controls and background. Pair it with the graph-ui theme around the view. */
|
|
46
|
+
readonly colorMode?: ColorMode | undefined;
|
|
47
|
+
/** Called with each element a click or key selects, and with `undefined` when the selection is cleared. */
|
|
48
|
+
readonly onSelect?: ((id: I["element"] | undefined) => void) | undefined;
|
|
49
|
+
/**
|
|
50
|
+
* The selected element, when the owner keeps the selection, as `useGraphSelection`'s option of the same name: give the key, even as `undefined`, and the canvas shows this selection and reports through `onSelect` what a click or key asks for, so the canvas and other views of the model share one selection. Leave it out for the canvas to keep its own.
|
|
51
|
+
*/
|
|
52
|
+
readonly selected?: I["element"] | undefined;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* A process view on a React Flow canvas: the projection laid out by `graph-layout`, each element as a styled card with its status and what blocks it, lanes as group nodes in a swimlane, and the critical path's elements and steps highlighted. Elements are selected by a click, or with the arrow, Home, End and Escape keys once the canvas has focus; the filter hides elements and the edges that touch them. Nothing is drawn until the layout resolves, and a layout that fails throws to the nearest error boundary.
|
|
56
|
+
* @param props - The run, the projection, a label, and optionally the layout, a filter, the colour mode and a selection listener.
|
|
57
|
+
* @returns The canvas, which fills its container.
|
|
58
|
+
*/
|
|
59
|
+
export declare const ProcessFlow: <I extends IdSpace>(props: ProcessFlowProps<I>) => ReactElement;
|
|
60
|
+
//#endregion
|
|
61
|
+
//#region ../../ui/graph/react-flow/dist/process-view.d.ts
|
|
62
|
+
interface ProcessViewProps<I extends IdSpace> extends Omit<ProcessFlowProps<I>, "projection"> {
|
|
63
|
+
/** Any of the model's projections. */
|
|
64
|
+
readonly projection: Projection<I>;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Any projection of a model: a sequence projection as graph-ui's SVG sequence diagram, since React Flow has no lifeline layout, and every other as a `ProcessFlow` canvas.
|
|
68
|
+
* @param props - As for `ProcessFlow`, with any projection. A sequence diagram uses only the run's model and the label, as its caption.
|
|
69
|
+
* @returns The view.
|
|
70
|
+
*/
|
|
71
|
+
export declare const ProcessView: <I extends IdSpace>(props: ProcessViewProps<I>) => ReactElement;
|
|
72
|
+
//#endregion
|
|
73
|
+
//#region ../../ui/graph/react-flow/dist/flow.d.ts
|
|
74
|
+
/** A view React Flow draws: a flowchart, a swimlane or a state machine, with its notation. */
|
|
75
|
+
type FlowView<I extends IdSpace> = {
|
|
76
|
+
readonly notation: "flowchart";
|
|
77
|
+
readonly view: Flowchart<I>;
|
|
78
|
+
} | {
|
|
79
|
+
readonly notation: "swimlane";
|
|
80
|
+
readonly view: Swimlane<I>;
|
|
81
|
+
} | {
|
|
82
|
+
readonly notation: "stateMachine";
|
|
83
|
+
readonly view: StateMachine<I>;
|
|
84
|
+
};
|
|
85
|
+
/** What an element node shows. Node and edge data are `Readonly` mapped types rather than interfaces, because React Flow requires data assignable to `Record<string, unknown>`, which an interface is not. */
|
|
86
|
+
type ElementNodeData<I extends IdSpace> = Readonly<{
|
|
87
|
+
element: Element<I["element"], I>;
|
|
88
|
+
status: Status;
|
|
89
|
+
critical: boolean;
|
|
90
|
+
/** The open work it waits on; absent when it is not blocked. */
|
|
91
|
+
blockedBy?: readonly NamedElement[];
|
|
92
|
+
}>;
|
|
93
|
+
/** An element of the view, drawn as a styled element card. */
|
|
94
|
+
type ElementNode<I extends IdSpace> = Node<ElementNodeData<I>, "element">;
|
|
95
|
+
/** What a lane node shows. */
|
|
96
|
+
type LaneNodeData = Readonly<{
|
|
97
|
+
participant: string;
|
|
98
|
+
label: string;
|
|
99
|
+
}>;
|
|
100
|
+
/** A swimlane, drawn as a group node that holds the nodes of its participant's elements. */
|
|
101
|
+
type LaneNode = Node<LaneNodeData, "lane">;
|
|
102
|
+
/** A node of a process view. */
|
|
103
|
+
type ProcessNode<I extends IdSpace> = ElementNode<I> | LaneNode;
|
|
104
|
+
/** What a transition edge shows. */
|
|
105
|
+
type TransitionEdgeData = Readonly<{
|
|
106
|
+
/** The model transitions the edge stands for. */
|
|
107
|
+
transitions: readonly string[];
|
|
108
|
+
label?: string;
|
|
109
|
+
/** Whether it passes work between actors; only a swimlane marks hand-offs. */
|
|
110
|
+
handoff: boolean;
|
|
111
|
+
/** Whether it joins two consecutive elements of the critical path. */
|
|
112
|
+
critical: boolean;
|
|
113
|
+
}>;
|
|
114
|
+
/** A transition of the view, drawn as a labelled edge. */
|
|
115
|
+
type TransitionEdge = Edge<TransitionEdgeData, "transition">;
|
|
116
|
+
/** What a view is drawn from besides its projection and its layout: the run's state. */
|
|
117
|
+
interface FlowRun<I extends IdSpace> {
|
|
118
|
+
readonly model: Model<I>;
|
|
119
|
+
readonly statuses: ReadonlyMap<I["element"], Status>;
|
|
120
|
+
/** The critical path, in dependency order. */
|
|
121
|
+
readonly criticalPath: readonly I["element"][];
|
|
122
|
+
/** Each blocked element's blockers, from `useBlockers`. */
|
|
123
|
+
readonly blockers: ReadonlyMap<I["element"], readonly I["element"][]>;
|
|
124
|
+
/** The elements to show; the others are hidden, and so is every edge with a hidden end. */
|
|
125
|
+
readonly shown: ReadonlySet<I["element"]>;
|
|
126
|
+
/** The direction the view was laid out in, which decides the side each edge leaves and enters a node. */
|
|
127
|
+
readonly direction: Direction;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* The React Flow nodes and edges of a laid-out view: a node per element at its laid-out position and size, a group node per swimlane lane holding its participant's elements, and an edge per drawn edge or transition. Each element node carries its status, whether it is on the critical path and what it is blocked by; each edge whether it is a hand-off and whether it is on the critical path. Group nodes come before the nodes they hold, as React Flow requires.
|
|
131
|
+
* @param flow - The projected view.
|
|
132
|
+
* @param placement - The view's layout.
|
|
133
|
+
* @param run - The run's state and the elements to show.
|
|
134
|
+
* @returns The nodes and edges.
|
|
135
|
+
* @throws Error when the layout lacks a position, size or lane the view needs.
|
|
136
|
+
*/
|
|
137
|
+
export declare const toFlow: <I extends IdSpace>(flow: FlowView<I>, placement: LayoutResult<I>, run: FlowRun<I>) => {
|
|
138
|
+
readonly nodes: ProcessNode<I>[];
|
|
139
|
+
readonly edges: TransitionEdge[];
|
|
140
|
+
};
|
|
141
|
+
//#endregion
|
|
142
|
+
//#region ../../ui/graph/react-flow/dist/nodes.d.ts
|
|
143
|
+
/**
|
|
144
|
+
* An element of a process view: graph-ui's element card, with the handles React Flow routes edges to.
|
|
145
|
+
* @param props - The node React Flow renders, with the element's data.
|
|
146
|
+
* @returns The node's content.
|
|
147
|
+
*/
|
|
148
|
+
export declare const ElementNodeView: (props: NodeProps<ElementNode<IdSpace>>) => ReactElement;
|
|
149
|
+
/**
|
|
150
|
+
* A swimlane: graph-ui's lane, filling the group node that holds its participant's elements.
|
|
151
|
+
* @param props - The node React Flow renders, with the lane's data.
|
|
152
|
+
* @returns The node's content.
|
|
153
|
+
*/
|
|
154
|
+
export declare const LaneNodeView: (props: NodeProps<LaneNode>) => ReactElement;
|
|
155
|
+
/** The node components, by node type. Defined once, outside any component, as React Flow requires. */
|
|
156
|
+
export declare const nodeTypes: {
|
|
157
|
+
element: (props: NodeProps<ElementNode<IdSpace>>) => ReactElement;
|
|
158
|
+
lane: (props: NodeProps<LaneNode>) => ReactElement;
|
|
159
|
+
};
|
|
160
|
+
//#endregion
|
|
161
|
+
//#region ../../ui/graph/react-flow/dist/edges.d.ts
|
|
162
|
+
/**
|
|
163
|
+
* A transition: a stepped line with an arrowhead and its label, coloured as a hand-off or a step of the critical path. Its group carries `data-transitions` with the model transitions it stands for, and `data-handoff` and `data-critical` as they apply.
|
|
164
|
+
* @param props - The edge React Flow renders, with the transition's data.
|
|
165
|
+
* @returns The edge's SVG.
|
|
166
|
+
*/
|
|
167
|
+
export declare const TransitionEdgeView: (props: EdgeProps<TransitionEdge>) => ReactElement;
|
|
168
|
+
/** The edge components, by edge type. Defined once, outside any component, as React Flow requires. */
|
|
169
|
+
export declare const edgeTypes: {
|
|
170
|
+
transition: (props: EdgeProps<TransitionEdge>) => ReactElement;
|
|
171
|
+
};
|
|
172
|
+
//#endregion
|
|
173
|
+
export type { ElementNode, ElementNodeData, FlowLayoutOptions, FlowProjection, FlowRun, FlowView, LaneNode, LaneNodeData, LayoutState, ProcessFlowProps, ProcessNode, ProcessViewProps, TransitionEdge, TransitionEdgeData };
|
|
@@ -0,0 +1,450 @@
|
|
|
1
|
+
import { _ as toSwimlane, g as toStateMachine, m as toSequence, y as toFlowchart } from "./queries-CCexJAE2.js";
|
|
2
|
+
import { t as layout } from "./layout-CCM-KBdp.js";
|
|
3
|
+
import { d as useBlockers, f as useCriticalPath, h as useStatuses, i as filterElements, r as emptyFilter, t as useGraphSelection } from "./selection-BW_xXWOy.js";
|
|
4
|
+
import { c as elementLabel } from "./detail-panel-B1ZmMuJT.js";
|
|
5
|
+
import { a as Lane, n as ElementCard, s as SequenceDiagram } from "./dist-BpCBmnMl.js";
|
|
6
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
7
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
8
|
+
import { BaseEdge, Handle, MarkerType, Position, ReactFlow, getSmoothStepPath } from "@xyflow/react";
|
|
9
|
+
//#region ../../ui/graph/react-flow/dist/index.js
|
|
10
|
+
var elementNode = "_15mv3qb0";
|
|
11
|
+
var laneNode = "_15mv3qb1";
|
|
12
|
+
var handle = "_15mv3qb2";
|
|
13
|
+
var transitionEdge = "_15mv3qb3";
|
|
14
|
+
var handoffEdge = "_15mv3qb4";
|
|
15
|
+
var criticalEdge = "_15mv3qb5";
|
|
16
|
+
/**
|
|
17
|
+
* A transition: a stepped line with an arrowhead and its label, coloured as a hand-off or a step of the critical path. Its group carries `data-transitions` with the model transitions it stands for, and `data-handoff` and `data-critical` as they apply.
|
|
18
|
+
* @param props - The edge React Flow renders, with the transition's data.
|
|
19
|
+
* @returns The edge's SVG.
|
|
20
|
+
*/
|
|
21
|
+
var TransitionEdgeView = (props) => {
|
|
22
|
+
const { id, data, sourceX, sourceY, targetX, targetY, sourcePosition, targetPosition, markerEnd } = props;
|
|
23
|
+
const [path, labelX, labelY] = getSmoothStepPath({
|
|
24
|
+
sourceX,
|
|
25
|
+
sourceY,
|
|
26
|
+
targetX,
|
|
27
|
+
targetY,
|
|
28
|
+
sourcePosition,
|
|
29
|
+
targetPosition
|
|
30
|
+
});
|
|
31
|
+
const classes = [
|
|
32
|
+
transitionEdge,
|
|
33
|
+
data?.handoff === true ? handoffEdge : void 0,
|
|
34
|
+
data?.critical === true ? criticalEdge : void 0
|
|
35
|
+
].filter((name) => name !== void 0);
|
|
36
|
+
return /* @__PURE__ */ jsx("g", {
|
|
37
|
+
className: classes.join(" "),
|
|
38
|
+
"data-transitions": data?.transitions.join(" "),
|
|
39
|
+
"data-handoff": data?.handoff === true ? "" : void 0,
|
|
40
|
+
"data-critical": data?.critical === true ? "" : void 0,
|
|
41
|
+
children: /* @__PURE__ */ jsx(BaseEdge, {
|
|
42
|
+
id,
|
|
43
|
+
path,
|
|
44
|
+
...markerEnd === void 0 ? {} : { markerEnd },
|
|
45
|
+
label: data?.label,
|
|
46
|
+
labelX,
|
|
47
|
+
labelY
|
|
48
|
+
})
|
|
49
|
+
});
|
|
50
|
+
};
|
|
51
|
+
/** The edge components, by edge type. Defined once, outside any component, as React Flow requires. */
|
|
52
|
+
var edgeTypes = { transition: TransitionEdgeView };
|
|
53
|
+
/** The side an edge enters a node, and the side it leaves, for each layout direction. */
|
|
54
|
+
var sides = {
|
|
55
|
+
right: {
|
|
56
|
+
target: Position.Left,
|
|
57
|
+
source: Position.Right
|
|
58
|
+
},
|
|
59
|
+
down: {
|
|
60
|
+
target: Position.Top,
|
|
61
|
+
source: Position.Bottom
|
|
62
|
+
},
|
|
63
|
+
left: {
|
|
64
|
+
target: Position.Right,
|
|
65
|
+
source: Position.Left
|
|
66
|
+
},
|
|
67
|
+
up: {
|
|
68
|
+
target: Position.Bottom,
|
|
69
|
+
source: Position.Top
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
/** The middle of each side of a box, relative to the box. */
|
|
73
|
+
var anchors = {
|
|
74
|
+
[Position.Left]: (size) => ({
|
|
75
|
+
x: 0,
|
|
76
|
+
y: size.height / 2
|
|
77
|
+
}),
|
|
78
|
+
[Position.Right]: (size) => ({
|
|
79
|
+
x: size.width,
|
|
80
|
+
y: size.height / 2
|
|
81
|
+
}),
|
|
82
|
+
[Position.Top]: (size) => ({
|
|
83
|
+
x: size.width / 2,
|
|
84
|
+
y: 0
|
|
85
|
+
}),
|
|
86
|
+
[Position.Bottom]: (size) => ({
|
|
87
|
+
x: size.width / 2,
|
|
88
|
+
y: size.height
|
|
89
|
+
})
|
|
90
|
+
};
|
|
91
|
+
/** A node's handles, given up front so React Flow can route edges without measuring the node first. */
|
|
92
|
+
var handlesOf = (direction, size) => {
|
|
93
|
+
const { target, source } = sides[direction];
|
|
94
|
+
return [{
|
|
95
|
+
type: "target",
|
|
96
|
+
position: target,
|
|
97
|
+
...anchors[target](size)
|
|
98
|
+
}, {
|
|
99
|
+
type: "source",
|
|
100
|
+
position: source,
|
|
101
|
+
...anchors[source](size)
|
|
102
|
+
}];
|
|
103
|
+
};
|
|
104
|
+
var laneId = (participant) => `lane:${participant}`;
|
|
105
|
+
var required = (value, what) => {
|
|
106
|
+
if (value === void 0) throw new Error(`The layout has no ${what}`);
|
|
107
|
+
return value;
|
|
108
|
+
};
|
|
109
|
+
/** The label of a state machine transition in the notation's form: `event [guard] / effect`. */
|
|
110
|
+
var transitionLabel = (model, transition) => {
|
|
111
|
+
const event = model.events.find((candidate) => candidate.id === transition.event);
|
|
112
|
+
const effect = model.actions.find((candidate) => candidate.id === transition.effect);
|
|
113
|
+
const label = [
|
|
114
|
+
event?.name,
|
|
115
|
+
transition.guard === void 0 ? void 0 : `[${transition.guard}]`,
|
|
116
|
+
effect === void 0 ? void 0 : `/ ${effect.name}`
|
|
117
|
+
].filter((part) => part !== void 0).join(" ");
|
|
118
|
+
return label === "" ? void 0 : label;
|
|
119
|
+
};
|
|
120
|
+
/**
|
|
121
|
+
* The React Flow nodes and edges of a laid-out view: a node per element at its laid-out position and size, a group node per swimlane lane holding its participant's elements, and an edge per drawn edge or transition. Each element node carries its status, whether it is on the critical path and what it is blocked by; each edge whether it is a hand-off and whether it is on the critical path. Group nodes come before the nodes they hold, as React Flow requires.
|
|
122
|
+
* @param flow - The projected view.
|
|
123
|
+
* @param placement - The view's layout.
|
|
124
|
+
* @param run - The run's state and the elements to show.
|
|
125
|
+
* @returns The nodes and edges.
|
|
126
|
+
* @throws Error when the layout lacks a position, size or lane the view needs.
|
|
127
|
+
*/
|
|
128
|
+
var toFlow = (flow, placement, run) => {
|
|
129
|
+
const { model, statuses, criticalPath, blockers, shown, direction } = run;
|
|
130
|
+
const positions = required(placement.views[flow.notation], "positions");
|
|
131
|
+
const elements = new Map(model.elements.map((element) => [element.id, element]));
|
|
132
|
+
const step = new Map(criticalPath.map((id, index) => [id, index]));
|
|
133
|
+
const sideOf = sides[direction];
|
|
134
|
+
const laneOf = /* @__PURE__ */ new Map();
|
|
135
|
+
const lanes = [];
|
|
136
|
+
if (flow.notation === "swimlane") flow.view.lanes.forEach((lane, index) => {
|
|
137
|
+
const bounds = required(placement.lanes[index], `lane for ${lane.participant}`);
|
|
138
|
+
for (const node of lane.nodes) laneOf.set(node, bounds);
|
|
139
|
+
lanes.push({
|
|
140
|
+
id: laneId(lane.participant),
|
|
141
|
+
type: "lane",
|
|
142
|
+
position: {
|
|
143
|
+
x: bounds.x,
|
|
144
|
+
y: bounds.y
|
|
145
|
+
},
|
|
146
|
+
width: bounds.width,
|
|
147
|
+
height: bounds.height,
|
|
148
|
+
selectable: false,
|
|
149
|
+
focusable: false,
|
|
150
|
+
draggable: false,
|
|
151
|
+
data: {
|
|
152
|
+
participant: lane.participant,
|
|
153
|
+
label: lane.label
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
});
|
|
157
|
+
const ids = flow.notation === "stateMachine" ? flow.view.states.map((state) => state.id) : flow.view.nodes.map((node) => node.id);
|
|
158
|
+
const labelOf = (id) => elementLabel(required(elements.get(id), `element ${id} in the model`));
|
|
159
|
+
const elementNodes = ids.map((id) => {
|
|
160
|
+
const element = required(elements.get(id), `element ${id} in the model`);
|
|
161
|
+
const status = required(statuses.get(id), `status for ${id}`);
|
|
162
|
+
const size = required(placement.sizes[id], `size for ${id}`);
|
|
163
|
+
const at = required(positions[id], `position for ${id}`);
|
|
164
|
+
const lane = laneOf.get(id);
|
|
165
|
+
const blockedBy = blockers.get(id);
|
|
166
|
+
return {
|
|
167
|
+
id,
|
|
168
|
+
type: "element",
|
|
169
|
+
position: lane === void 0 ? at : {
|
|
170
|
+
x: at.x - lane.x,
|
|
171
|
+
y: at.y - lane.y
|
|
172
|
+
},
|
|
173
|
+
...lane === void 0 ? {} : {
|
|
174
|
+
parentId: laneId(lane.participant),
|
|
175
|
+
extent: "parent"
|
|
176
|
+
},
|
|
177
|
+
width: size.width,
|
|
178
|
+
height: size.height,
|
|
179
|
+
handles: handlesOf(direction, size),
|
|
180
|
+
sourcePosition: sideOf.source,
|
|
181
|
+
targetPosition: sideOf.target,
|
|
182
|
+
hidden: !shown.has(id),
|
|
183
|
+
draggable: false,
|
|
184
|
+
ariaLabel: `${elementLabel(element)}, ${status}`,
|
|
185
|
+
data: {
|
|
186
|
+
element,
|
|
187
|
+
status,
|
|
188
|
+
critical: step.has(id),
|
|
189
|
+
...blockedBy === void 0 ? {} : { blockedBy: blockedBy.map((blocker) => ({
|
|
190
|
+
id: blocker,
|
|
191
|
+
label: labelOf(blocker)
|
|
192
|
+
})) }
|
|
193
|
+
}
|
|
194
|
+
};
|
|
195
|
+
});
|
|
196
|
+
const handoffs = new Set(flow.notation === "swimlane" ? flow.view.handoffs.map((handoff) => handoff.transition) : []);
|
|
197
|
+
const onCriticalPath = (from, to) => {
|
|
198
|
+
const at = step.get(from);
|
|
199
|
+
return at !== void 0 && step.get(to) === at + 1;
|
|
200
|
+
};
|
|
201
|
+
const edges = (flow.notation === "stateMachine" ? flow.view.transitions.map((transition) => ({
|
|
202
|
+
from: transition.source,
|
|
203
|
+
to: transition.target,
|
|
204
|
+
transitions: transition.transitions,
|
|
205
|
+
label: transitionLabel(model, transition)
|
|
206
|
+
})) : flow.view.edges.map((edge) => ({
|
|
207
|
+
from: edge.from,
|
|
208
|
+
to: edge.to,
|
|
209
|
+
transitions: edge.transitions,
|
|
210
|
+
label: edge.label
|
|
211
|
+
}))).map((edge) => {
|
|
212
|
+
const critical = onCriticalPath(edge.from, edge.to);
|
|
213
|
+
const handoff = edge.transitions.some((id) => handoffs.has(id));
|
|
214
|
+
return {
|
|
215
|
+
id: `transition:${edge.transitions.join(",")}`,
|
|
216
|
+
type: "transition",
|
|
217
|
+
source: edge.from,
|
|
218
|
+
target: edge.to,
|
|
219
|
+
hidden: !shown.has(edge.from) || !shown.has(edge.to),
|
|
220
|
+
markerEnd: { type: MarkerType.ArrowClosed },
|
|
221
|
+
data: {
|
|
222
|
+
transitions: edge.transitions,
|
|
223
|
+
...edge.label === void 0 ? {} : { label: edge.label },
|
|
224
|
+
handoff,
|
|
225
|
+
critical
|
|
226
|
+
}
|
|
227
|
+
};
|
|
228
|
+
});
|
|
229
|
+
return {
|
|
230
|
+
nodes: [...lanes, ...elementNodes],
|
|
231
|
+
edges
|
|
232
|
+
};
|
|
233
|
+
};
|
|
234
|
+
/**
|
|
235
|
+
* An element of a process view: graph-ui's element card, with the handles React Flow routes edges to.
|
|
236
|
+
* @param props - The node React Flow renders, with the element's data.
|
|
237
|
+
* @returns The node's content.
|
|
238
|
+
*/
|
|
239
|
+
var ElementNodeView = (props) => {
|
|
240
|
+
const { data, sourcePosition, targetPosition, selected } = props;
|
|
241
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
242
|
+
className: elementNode,
|
|
243
|
+
"data-selected": selected ? "" : void 0,
|
|
244
|
+
children: [
|
|
245
|
+
targetPosition === void 0 ? null : /* @__PURE__ */ jsx(Handle, {
|
|
246
|
+
type: "target",
|
|
247
|
+
position: targetPosition,
|
|
248
|
+
isConnectable: false,
|
|
249
|
+
className: handle
|
|
250
|
+
}),
|
|
251
|
+
/* @__PURE__ */ jsx(ElementCard, {
|
|
252
|
+
element: data.element,
|
|
253
|
+
status: data.status,
|
|
254
|
+
critical: data.critical,
|
|
255
|
+
blockedBy: data.blockedBy
|
|
256
|
+
}),
|
|
257
|
+
sourcePosition === void 0 ? null : /* @__PURE__ */ jsx(Handle, {
|
|
258
|
+
type: "source",
|
|
259
|
+
position: sourcePosition,
|
|
260
|
+
isConnectable: false,
|
|
261
|
+
className: handle
|
|
262
|
+
})
|
|
263
|
+
]
|
|
264
|
+
});
|
|
265
|
+
};
|
|
266
|
+
/**
|
|
267
|
+
* A swimlane: graph-ui's lane, filling the group node that holds its participant's elements.
|
|
268
|
+
* @param props - The node React Flow renders, with the lane's data.
|
|
269
|
+
* @returns The node's content.
|
|
270
|
+
*/
|
|
271
|
+
var LaneNodeView = (props) => {
|
|
272
|
+
const { data } = props;
|
|
273
|
+
return /* @__PURE__ */ jsx("div", {
|
|
274
|
+
className: laneNode,
|
|
275
|
+
children: /* @__PURE__ */ jsx(Lane, {
|
|
276
|
+
participant: data.participant,
|
|
277
|
+
label: data.label
|
|
278
|
+
})
|
|
279
|
+
});
|
|
280
|
+
};
|
|
281
|
+
/** The node components, by node type. Defined once, outside any component, as React Flow requires. */
|
|
282
|
+
var nodeTypes = {
|
|
283
|
+
element: ElementNodeView,
|
|
284
|
+
lane: LaneNodeView
|
|
285
|
+
};
|
|
286
|
+
var pending = { status: "pending" };
|
|
287
|
+
/**
|
|
288
|
+
* Lays out a view with `graph-layout`'s `layout`, again whenever the view or the options change, aborting a layout that is no longer wanted.
|
|
289
|
+
* @param view - The flowchart, swimlane or state machine to place. Keep it stable between renders.
|
|
290
|
+
* @param options - Direction, spacing and the engine. Keep it stable between renders.
|
|
291
|
+
* @returns `pending` until the layout resolves, then `placed` with the positions, sizes and lanes, or `failed` with what the engine threw.
|
|
292
|
+
*/
|
|
293
|
+
var useLayout = (view, options) => {
|
|
294
|
+
const [state, setState] = useState({
|
|
295
|
+
view,
|
|
296
|
+
options,
|
|
297
|
+
value: pending
|
|
298
|
+
});
|
|
299
|
+
useEffect(() => {
|
|
300
|
+
const controller = new AbortController();
|
|
301
|
+
const settle = (value) => {
|
|
302
|
+
setState({
|
|
303
|
+
view,
|
|
304
|
+
options,
|
|
305
|
+
value
|
|
306
|
+
});
|
|
307
|
+
};
|
|
308
|
+
layout(view, {
|
|
309
|
+
...options,
|
|
310
|
+
signal: controller.signal
|
|
311
|
+
}).then((result) => {
|
|
312
|
+
settle({
|
|
313
|
+
status: "placed",
|
|
314
|
+
result
|
|
315
|
+
});
|
|
316
|
+
}, (error) => {
|
|
317
|
+
if (!controller.signal.aborted) settle({
|
|
318
|
+
status: "failed",
|
|
319
|
+
error
|
|
320
|
+
});
|
|
321
|
+
});
|
|
322
|
+
return () => {
|
|
323
|
+
controller.abort();
|
|
324
|
+
};
|
|
325
|
+
}, [view, options]);
|
|
326
|
+
return state.view === view && state.options === options ? state.value : pending;
|
|
327
|
+
};
|
|
328
|
+
/** The direction a view is laid out in when its options name none: edges point right, as `graph-layout`'s own default. */
|
|
329
|
+
var defaultDirection = "right";
|
|
330
|
+
var projectFlow = (run, projection) => {
|
|
331
|
+
if (projection.notation === "stateMachine") return {
|
|
332
|
+
notation: "stateMachine",
|
|
333
|
+
view: toStateMachine(run.model, projection.subject)
|
|
334
|
+
};
|
|
335
|
+
return projection.notation === "swimlane" ? {
|
|
336
|
+
notation: "swimlane",
|
|
337
|
+
view: toSwimlane(run.model)
|
|
338
|
+
} : {
|
|
339
|
+
notation: "flowchart",
|
|
340
|
+
view: toFlowchart(run.model)
|
|
341
|
+
};
|
|
342
|
+
};
|
|
343
|
+
/**
|
|
344
|
+
* A process view on a React Flow canvas: the projection laid out by `graph-layout`, each element as a styled card with its status and what blocks it, lanes as group nodes in a swimlane, and the critical path's elements and steps highlighted. Elements are selected by a click, or with the arrow, Home, End and Escape keys once the canvas has focus; the filter hides elements and the edges that touch them. Nothing is drawn until the layout resolves, and a layout that fails throws to the nearest error boundary.
|
|
345
|
+
* @param props - The run, the projection, a label, and optionally the layout, a filter, the colour mode and a selection listener.
|
|
346
|
+
* @returns The canvas, which fills its container.
|
|
347
|
+
*/
|
|
348
|
+
var ProcessFlow = (props) => {
|
|
349
|
+
const { run, projection, label, layout, filter = emptyFilter, colorMode, onSelect } = props;
|
|
350
|
+
const direction = layout?.direction ?? defaultDirection;
|
|
351
|
+
const options = useMemo(() => ({
|
|
352
|
+
...layout,
|
|
353
|
+
direction
|
|
354
|
+
}), [layout, direction]);
|
|
355
|
+
const flow = useMemo(() => projectFlow(run, projection), [run, projection]);
|
|
356
|
+
const placement = useLayout(flow.view, options);
|
|
357
|
+
const statuses = useStatuses(run);
|
|
358
|
+
const blockers = useBlockers(run);
|
|
359
|
+
const { path } = useCriticalPath(run);
|
|
360
|
+
const shown = useMemo(() => filterElements(run.model, statuses, filter), [
|
|
361
|
+
run.model,
|
|
362
|
+
statuses,
|
|
363
|
+
filter
|
|
364
|
+
]);
|
|
365
|
+
const canvas = useRef(null);
|
|
366
|
+
const focus = useCallback((id) => {
|
|
367
|
+
const node = canvas.current?.querySelector(`.react-flow__node[data-id="${CSS.escape(id)}"]`);
|
|
368
|
+
if (node instanceof HTMLElement) node.focus();
|
|
369
|
+
}, []);
|
|
370
|
+
const { selected, select, containerProps } = useGraphSelection(shown, {
|
|
371
|
+
onChange: onSelect,
|
|
372
|
+
focus,
|
|
373
|
+
..."selected" in props ? { selected: props.selected } : {}
|
|
374
|
+
});
|
|
375
|
+
const drawn = useMemo(() => {
|
|
376
|
+
if (placement.status !== "placed") return;
|
|
377
|
+
return toFlow(flow, placement.result, {
|
|
378
|
+
model: run.model,
|
|
379
|
+
statuses,
|
|
380
|
+
criticalPath: path,
|
|
381
|
+
blockers,
|
|
382
|
+
shown: new Set(shown),
|
|
383
|
+
direction
|
|
384
|
+
});
|
|
385
|
+
}, [
|
|
386
|
+
flow,
|
|
387
|
+
placement,
|
|
388
|
+
run.model,
|
|
389
|
+
statuses,
|
|
390
|
+
path,
|
|
391
|
+
blockers,
|
|
392
|
+
shown,
|
|
393
|
+
direction
|
|
394
|
+
]);
|
|
395
|
+
if (placement.status === "failed") throw new Error(`${label} could not be laid out`, { cause: placement.error });
|
|
396
|
+
if (drawn === void 0) return /* @__PURE__ */ jsxs("p", {
|
|
397
|
+
role: "status",
|
|
398
|
+
children: ["Laying out ", label]
|
|
399
|
+
});
|
|
400
|
+
return /* @__PURE__ */ jsx(ReactFlow, {
|
|
401
|
+
ref: canvas,
|
|
402
|
+
"aria-label": label,
|
|
403
|
+
nodes: drawn.nodes.map((node) => node.id === selected ? {
|
|
404
|
+
...node,
|
|
405
|
+
selected: true
|
|
406
|
+
} : node),
|
|
407
|
+
edges: drawn.edges,
|
|
408
|
+
nodeTypes,
|
|
409
|
+
edgeTypes,
|
|
410
|
+
...colorMode === void 0 ? {} : { colorMode },
|
|
411
|
+
nodesDraggable: false,
|
|
412
|
+
nodesConnectable: false,
|
|
413
|
+
fitView: true,
|
|
414
|
+
onKeyDown: containerProps.onKeyDown,
|
|
415
|
+
onNodeClick: (_event, node) => {
|
|
416
|
+
if (node.type === "element") select(node.id);
|
|
417
|
+
},
|
|
418
|
+
onPaneClick: () => {
|
|
419
|
+
select(void 0);
|
|
420
|
+
}
|
|
421
|
+
});
|
|
422
|
+
};
|
|
423
|
+
var SequenceView = (props) => {
|
|
424
|
+
const { run, projection, label } = props;
|
|
425
|
+
const diagram = useMemo(() => toSequence(run.model, projection.scenario), [run.model, projection]);
|
|
426
|
+
const participants = useMemo(() => new Map(run.model.participants.map((participant) => [participant.id, participant.label])), [run.model]);
|
|
427
|
+
return /* @__PURE__ */ jsx(SequenceDiagram, {
|
|
428
|
+
diagram,
|
|
429
|
+
title: label,
|
|
430
|
+
labelOf: (actor) => participants.get(actor) ?? actor
|
|
431
|
+
});
|
|
432
|
+
};
|
|
433
|
+
/**
|
|
434
|
+
* Any projection of a model: a sequence projection as graph-ui's SVG sequence diagram, since React Flow has no lifeline layout, and every other as a `ProcessFlow` canvas.
|
|
435
|
+
* @param props - As for `ProcessFlow`, with any projection. A sequence diagram uses only the run's model and the label, as its caption.
|
|
436
|
+
* @returns The view.
|
|
437
|
+
*/
|
|
438
|
+
var ProcessView = (props) => {
|
|
439
|
+
const { projection, run, label } = props;
|
|
440
|
+
return projection.notation === "sequence" ? /* @__PURE__ */ jsx(SequenceView, {
|
|
441
|
+
run,
|
|
442
|
+
projection,
|
|
443
|
+
label
|
|
444
|
+
}) : /* @__PURE__ */ jsx(ProcessFlow, {
|
|
445
|
+
...props,
|
|
446
|
+
projection
|
|
447
|
+
});
|
|
448
|
+
};
|
|
449
|
+
//#endregion
|
|
450
|
+
export { ElementNodeView, LaneNodeView, ProcessFlow, ProcessView, TransitionEdgeView, edgeTypes, nodeTypes, toFlow, useLayout };
|
package/dist/react.d.ts
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { $ as useWhyStatus, A as ElementFilter, B as useElementFilter, C as ruleDescriptions, D as SelectionContainerProps, E as GraphSelectionOptions, F as emptyFilter, G as BlockedChain, H as ViewsByNotation, I as filterElements, J as useBlockers, K as stepWeight, L as filterOptions, M as FilterOption, N as FilterOptions, O as SelectionItemProps, P as actorsOf, Q as useStatuses, R as matchesFilter, S as elementLabel, T as GraphSelection, U as project, V as ProjectedView, W as useProjection, X as useImpact, Y as useCriticalPath, Z as useReadySet, _ as ElementCardPart, a as FilterPanelPart, b as StatusBadge, c as LegendPart, d as LanePart, et as ModelClient, f as LaneProps, g as ElementCard, h as TransitionItemProps, i as FilterPanel, it as noFacts, j as ElementFilterState, k as useGraphSelection, l as LegendProps, m as TransitionItemPart, n as DetailPanelPart, nt as useModel, o as FilterPanelProps, p as TransitionItem, q as useBlockedChain, r as DetailPanelProps, rt as Run, s as Legend, t as DetailPanel, tt as ModelState, u as Lane, v as ElementCardProps, w as statusLabels, x as StatusBadgeProps, y as NamedElement, z as sourceScope } from "./index-DricKcyl.js";
|
|
2
|
+
export { type BlockedChain, DetailPanel, type DetailPanelPart, type DetailPanelProps, ElementCard, type ElementCardPart, type ElementCardProps, type ElementFilter, type ElementFilterState, type FilterOption, type FilterOptions, FilterPanel, type FilterPanelPart, type FilterPanelProps, type GraphSelection, type GraphSelectionOptions, Lane, type LanePart, type LaneProps, Legend, type LegendPart, type LegendProps, type ModelClient, type ModelState, type NamedElement, type ProjectedView, type Run, type SelectionContainerProps, type SelectionItemProps, StatusBadge, type StatusBadgeProps, TransitionItem, type TransitionItemPart, type TransitionItemProps, type ViewsByNotation, actorsOf, elementLabel, emptyFilter, filterElements, filterOptions, matchesFilter, noFacts, project, ruleDescriptions, sourceScope, statusLabels, stepWeight, useBlockedChain, useBlockers, useCriticalPath, useElementFilter, useGraphSelection, useImpact, useModel, useProjection, useReadySet, useStatuses, useWhyStatus };
|