sample-ui-component-library 0.0.39-dev → 0.0.41-dev
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/dist/cjs/index.js +1 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/esm/index.js +3 -3
- package/dist/esm/index.js.map +1 -1
- package/package.json +4 -2
- package/src/components/BehavioralGraphBuilder/BehavioralGraphBuilder.jsx +90 -142
- package/src/components/BehavioralGraphBuilder/BehavioralGraphBuilder.scss +12 -0
- package/src/components/BehavioralGraphBuilder/helper.js +39 -0
- package/src/index.js +1 -2
- package/src/stories/{BehavioralGraphBuilderStories.scss → BehavioralGraphBuilder.scss} +4 -1
- package/src/stories/BehavioralGraphBuilder.stories.js +91 -18
- package/src/stories/components/ToolBar/ToolBar.js +9 -25
- package/src/stories/data/Designs/simple_designs_temp.json +1 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sample-ui-component-library",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.41-dev",
|
|
4
4
|
"description": "A library which contains sample UI elements that can be used for populating layouts.",
|
|
5
5
|
"main": "dist/cjs/index.js",
|
|
6
6
|
"module": "dist/esm/index.js",
|
|
@@ -68,6 +68,8 @@
|
|
|
68
68
|
"@dagrejs/dagre": "^1.1.4",
|
|
69
69
|
"@monaco-editor/react": "^4.7.0",
|
|
70
70
|
"@xyflow/react": "^12.6.0",
|
|
71
|
-
"
|
|
71
|
+
"dal-engine-core-js-lib-dev": "^0.0.4",
|
|
72
|
+
"react-bootstrap-icons": "^1.11.5",
|
|
73
|
+
"reaflow": "^5.4.1"
|
|
72
74
|
}
|
|
73
75
|
}
|
|
@@ -1,159 +1,107 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
ReactFlowProvider,
|
|
5
|
-
useNodesState,
|
|
6
|
-
useEdgesState,
|
|
7
|
-
Background,
|
|
8
|
-
Controls,
|
|
9
|
-
useReactFlow,
|
|
10
|
-
addEdge,
|
|
11
|
-
applyNodeChanges,
|
|
12
|
-
applyEdgeChanges
|
|
13
|
-
} from "@xyflow/react";
|
|
14
|
-
import "@xyflow/react/dist/style.css";
|
|
1
|
+
import { useEffect, useState, useRef, useImperativeHandle, forwardRef, useMemo, useCallback } from "react";
|
|
2
|
+
import { Canvas, Node, Edge, removeAndUpsertNodes } from 'reaflow';
|
|
3
|
+
import PropTypes from 'prop-types';
|
|
15
4
|
|
|
16
|
-
|
|
17
|
-
{
|
|
18
|
-
id: "1",
|
|
19
|
-
position: { x: 250, y: 150 },
|
|
20
|
-
data: { label: "Behavior 1" },
|
|
21
|
-
draggable: true,
|
|
22
|
-
selectable: true,
|
|
23
|
-
},
|
|
24
|
-
{
|
|
25
|
-
id: "2",
|
|
26
|
-
position: { x: 250, y: 250 },
|
|
27
|
-
data: { label: "Behavior 2" },
|
|
28
|
-
draggable: true,
|
|
29
|
-
selectable: true,
|
|
30
|
-
},
|
|
31
|
-
];
|
|
5
|
+
import { designToNodes } from "./helper";
|
|
32
6
|
|
|
33
|
-
|
|
34
|
-
const NODE_HEIGHT = 40;
|
|
35
|
-
const Flow = ({ activeTool }) => {
|
|
36
|
-
const { screenToFlowPosition } = useReactFlow();
|
|
37
|
-
const [nodes, setNodes] = useState(initialNodes);
|
|
38
|
-
const [edges, setEdges] = useState([]);
|
|
39
|
-
const [ghostNode, setGhostNode] = useState(null);
|
|
7
|
+
import "./BehavioralGraphBuilder.scss";
|
|
40
8
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
9
|
+
/**
|
|
10
|
+
* Renders a behavioral graph editor component using reaflow.
|
|
11
|
+
*
|
|
12
|
+
* @return {JSX}
|
|
13
|
+
*/
|
|
14
|
+
export const BehavioralGraphBuilder = forwardRef(({connectBehaviors, deleteTransition, deleteBehavior}, ref) => {
|
|
15
|
+
const canvasRef = useRef();
|
|
48
16
|
|
|
49
|
-
//
|
|
17
|
+
// Resizer to set canvas size to match container
|
|
18
|
+
// TODO: Issues with zooming and resizing, need to explore.
|
|
19
|
+
const containerRef = useRef();
|
|
20
|
+
const [size, setSize] = useState({ width: 0, height: 0 });
|
|
50
21
|
useEffect(() => {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
// Callback for mouse pane move
|
|
55
|
-
const onPaneMouseMove = useCallback( (event) => {
|
|
56
|
-
const pos = screenToFlowPosition({
|
|
57
|
-
x: event.clientX,
|
|
58
|
-
y: event.clientY,
|
|
22
|
+
const observer = new ResizeObserver(([entry]) => {
|
|
23
|
+
const { width, height } = entry.contentRect;
|
|
24
|
+
setSize({ width, height });
|
|
59
25
|
});
|
|
60
26
|
|
|
61
|
-
if (
|
|
62
|
-
|
|
63
|
-
id: "ghost",
|
|
64
|
-
position: {
|
|
65
|
-
x: pos.x - NODE_WIDTH / 2,
|
|
66
|
-
y: pos.y - NODE_HEIGHT / 2,
|
|
67
|
-
},
|
|
68
|
-
data: { label: "Behavior" },
|
|
69
|
-
draggable: false,
|
|
70
|
-
selectable: false,
|
|
71
|
-
style: {
|
|
72
|
-
opacity: 0.5,
|
|
73
|
-
pointerEvents: "none",
|
|
74
|
-
width: NODE_WIDTH,
|
|
75
|
-
height: NODE_HEIGHT,
|
|
76
|
-
},
|
|
77
|
-
});
|
|
78
|
-
}
|
|
79
|
-
}, [activeTool]);
|
|
80
|
-
|
|
81
|
-
// Callback for when mouse leaves pane
|
|
82
|
-
const onPaneMouseLeave = useCallback(() => {
|
|
83
|
-
setGhostNode(null);
|
|
27
|
+
if (containerRef.current) observer.observe(containerRef.current);
|
|
28
|
+
return () => observer.disconnect();
|
|
84
29
|
}, []);
|
|
85
30
|
|
|
86
|
-
// Callback for pane click
|
|
87
|
-
const onPaneClick = useCallback((event, node) => {
|
|
88
|
-
if (activeTool === "drop") {
|
|
89
|
-
if (!ghostNode) return;
|
|
90
|
-
setNodes((nds) => [
|
|
91
|
-
...nds,
|
|
92
|
-
{
|
|
93
|
-
...ghostNode,
|
|
94
|
-
draggable: true,
|
|
95
|
-
selectable: true,
|
|
96
|
-
id: crypto.randomUUID(),
|
|
97
|
-
style: {},
|
|
98
|
-
},
|
|
99
|
-
]);
|
|
100
|
-
}
|
|
101
|
-
}, [ghostNode, activeTool]);
|
|
102
31
|
|
|
103
|
-
|
|
104
|
-
const
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
}
|
|
111
|
-
}, [activeTool]);
|
|
32
|
+
const [edges, setEdges] = useState([]);
|
|
33
|
+
const [nodes, setNodes] = useState([]);
|
|
34
|
+
const [selections, setSelections] = useState([]);
|
|
35
|
+
'1'
|
|
36
|
+
const onNodeLink =(_event, from, to) => {
|
|
37
|
+
connectBehaviors(from, to);
|
|
38
|
+
}
|
|
112
39
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
40
|
+
const updateEngine = useCallback((engine) => {
|
|
41
|
+
if (engine) {
|
|
42
|
+
const { nodes, edges } = designToNodes(engine);
|
|
43
|
+
setNodes(nodes);
|
|
44
|
+
setEdges(edges);
|
|
117
45
|
}
|
|
118
|
-
}, [
|
|
46
|
+
}, [setNodes, setEdges]);
|
|
119
47
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
const edge = {
|
|
124
|
-
...connection,
|
|
125
|
-
id: crypto.randomUUID(),
|
|
126
|
-
type: "smoothstep",
|
|
127
|
-
animated: true,
|
|
48
|
+
const api = useMemo(() => {
|
|
49
|
+
return {
|
|
50
|
+
updateEngine
|
|
128
51
|
};
|
|
129
|
-
|
|
130
|
-
|
|
52
|
+
}, [updateEngine]);
|
|
53
|
+
|
|
54
|
+
useImperativeHandle(ref, () => api, [api]);
|
|
131
55
|
|
|
132
|
-
|
|
133
|
-
<
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
onConnect={onConnect}
|
|
140
|
-
onNodesChange={onNodesChange}
|
|
141
|
-
onEdgesChange={onEdgesChange}
|
|
142
|
-
onNodeClick={onNodeClick}
|
|
143
|
-
onEdgeClick={onEdgeClick}
|
|
144
|
-
colorMode={"dark"}
|
|
145
|
-
fitView
|
|
146
|
-
>
|
|
147
|
-
<Background />
|
|
148
|
-
<Controls />
|
|
149
|
-
</ReactFlow>
|
|
150
|
-
);
|
|
151
|
-
};
|
|
56
|
+
const handleWheel = useCallback((e) => {
|
|
57
|
+
if (e.deltaY < 0) {
|
|
58
|
+
canvasRef.current.zoomIn()
|
|
59
|
+
} else {
|
|
60
|
+
canvasRef.current.zoomOut();
|
|
61
|
+
}
|
|
62
|
+
}, [canvasRef]);
|
|
152
63
|
|
|
153
|
-
export const BehavioralGraphBuilder = ({ activeTool }) => {
|
|
154
64
|
return (
|
|
155
|
-
<
|
|
156
|
-
<
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
}
|
|
65
|
+
<div onWheel={handleWheel} ref={containerRef} className="canvas-wrapper">
|
|
66
|
+
<Canvas
|
|
67
|
+
ref={canvasRef}
|
|
68
|
+
nodes={nodes}
|
|
69
|
+
edges={edges}
|
|
70
|
+
width={size.width}
|
|
71
|
+
height={size.height}
|
|
72
|
+
onNodeLink={onNodeLink}
|
|
73
|
+
panType="drag"
|
|
74
|
+
selections={selections}node={
|
|
75
|
+
<Node
|
|
76
|
+
onClick={(event, node) => {
|
|
77
|
+
setSelections([node.id]);
|
|
78
|
+
}}
|
|
79
|
+
onRemove={(event, node) => {
|
|
80
|
+
deleteBehavior(node);
|
|
81
|
+
setSelections([]);
|
|
82
|
+
}}
|
|
83
|
+
/>
|
|
84
|
+
}
|
|
85
|
+
edge={
|
|
86
|
+
<Edge
|
|
87
|
+
onClick={(event, edge) => {
|
|
88
|
+
setSelections([edge.id]);
|
|
89
|
+
}}
|
|
90
|
+
onRemove={(event, edge) => {
|
|
91
|
+
deleteTransition(edge);
|
|
92
|
+
setSelections([]);
|
|
93
|
+
}}
|
|
94
|
+
/>
|
|
95
|
+
}
|
|
96
|
+
onCanvasClick={(event) => {setSelections([]);}}
|
|
97
|
+
fit
|
|
98
|
+
center
|
|
99
|
+
/>
|
|
100
|
+
</div>
|
|
101
|
+
)
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
BehavioralGraphBuilder.propTypes = {
|
|
105
|
+
connectBehaviors: PropTypes.func.isRequired,
|
|
106
|
+
deleteBehavior: PropTypes.func.isRequired
|
|
107
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
|
|
2
|
+
/**
|
|
3
|
+
* Converts a DAL design specification object into React Flow elements (nodes and edges).
|
|
4
|
+
* @param {Object} design
|
|
5
|
+
* @returns {Object} An object containing nodes and edges for React Flow
|
|
6
|
+
*/
|
|
7
|
+
export const designToNodes = (engine) => {
|
|
8
|
+
|
|
9
|
+
let edges = [];
|
|
10
|
+
let nodes = [];
|
|
11
|
+
|
|
12
|
+
for (let i = 0; i < engine.graph.nodes.length; i++) {
|
|
13
|
+
const node = engine.graph.nodes[i];
|
|
14
|
+
nodes.push({
|
|
15
|
+
id: node.getBehavior().name,
|
|
16
|
+
text: node.getBehavior().name,
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
for (let i = 0; i < engine.graph.nodes.length; i++) {
|
|
21
|
+
const node = engine.graph.nodes[i];
|
|
22
|
+
if (!node?.getGoToBehaviors()) {
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
node.getGoToBehaviors().forEach((goTo) => {
|
|
27
|
+
edges.push({
|
|
28
|
+
id: `${node.getBehavior().name}->${goTo}`,
|
|
29
|
+
from: node.getBehavior().name,
|
|
30
|
+
to: goTo,
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return {
|
|
36
|
+
nodes: nodes,
|
|
37
|
+
edges: edges
|
|
38
|
+
};
|
|
39
|
+
}
|
package/src/index.js
CHANGED
|
@@ -1,42 +1,115 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { BehavioralGraphBuilder } from "../components/BehavioralGraphBuilder";
|
|
3
|
-
import "./BehavioralGraphBuilderStories.scss"
|
|
4
|
-
import { ToolBar } from "./components/ToolBar/ToolBar";
|
|
1
|
+
import { useEffect, useState, useCallback, useRef } from "react";
|
|
5
2
|
import { useArgs } from "@storybook/preview-api";
|
|
3
|
+
import { action } from "@storybook/addon-actions";
|
|
4
|
+
|
|
5
|
+
import { BehavioralGraphBuilder } from "../components/BehavioralGraphBuilder/BehavioralGraphBuilder";
|
|
6
|
+
import { ToolBar } from "./components/ToolBar/ToolBar";
|
|
7
|
+
|
|
8
|
+
import { DALEngine } from "dal-engine-core-js-lib-dev";
|
|
9
|
+
|
|
10
|
+
import design from "./data/Designs/simple_designs_temp.json";
|
|
11
|
+
|
|
12
|
+
import "./BehavioralGraphBuilder.scss";
|
|
6
13
|
|
|
7
14
|
export default {
|
|
8
|
-
title:
|
|
15
|
+
title: "BehavioralGraphBuilder",
|
|
9
16
|
component: BehavioralGraphBuilder,
|
|
10
|
-
argTypes: {
|
|
11
|
-
}
|
|
17
|
+
argTypes: {},
|
|
12
18
|
};
|
|
13
19
|
|
|
20
|
+
let count = 0;
|
|
21
|
+
|
|
14
22
|
const Template = (args) => {
|
|
15
23
|
const [, updateArgs] = useArgs();
|
|
16
24
|
|
|
25
|
+
const editorRef = useRef();
|
|
26
|
+
|
|
27
|
+
const [engine, setEngine] = useState();
|
|
28
|
+
|
|
17
29
|
const [activeTool, setActiveTool] = useState("select");
|
|
18
30
|
|
|
19
|
-
const selectTool = useCallback(
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
31
|
+
const selectTool = useCallback(
|
|
32
|
+
(tool) => {
|
|
33
|
+
updateArgs({ activeTool: tool });
|
|
34
|
+
setActiveTool(tool);
|
|
35
|
+
|
|
36
|
+
if (tool === "add-node") {
|
|
37
|
+
engine.addNode("node-" + count++, []);
|
|
38
|
+
editorRef.current.updateEngine(engine);
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
[activeTool, setActiveTool, engine],
|
|
42
|
+
);
|
|
43
|
+
|
|
23
44
|
useEffect(() => {
|
|
24
|
-
updateArgs({
|
|
45
|
+
updateArgs({
|
|
46
|
+
activeTool: activeTool,
|
|
47
|
+
design: design,
|
|
48
|
+
});
|
|
25
49
|
}, []);
|
|
26
50
|
|
|
51
|
+
useEffect(() => {
|
|
52
|
+
if (editorRef.current) {
|
|
53
|
+
const engine = new DALEngine({ name: "testEngine" });
|
|
54
|
+
// engine.deserialize(JSON.stringify(design));
|
|
55
|
+
setEngine(engine);
|
|
56
|
+
editorRef.current.updateEngine(engine);
|
|
57
|
+
setTimeout(() => {
|
|
58
|
+
engine.addNode("testBehavior", []);
|
|
59
|
+
engine.addNode("testBehavior2", []);
|
|
60
|
+
editorRef.current.updateEngine(engine);
|
|
61
|
+
}, 4000);
|
|
62
|
+
}
|
|
63
|
+
}, [design, editorRef]);
|
|
64
|
+
|
|
65
|
+
const connectBehaviors = useCallback(
|
|
66
|
+
(from, to) => {
|
|
67
|
+
if (!to) return;
|
|
68
|
+
action("Connect Behaviors")(from, to);
|
|
69
|
+
engine.getNode(from.id).addGoToBehavior(to.id);
|
|
70
|
+
editorRef.current.updateEngine(engine);
|
|
71
|
+
},
|
|
72
|
+
[editorRef, engine],
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
const deleteBehavior = useCallback(
|
|
76
|
+
(node) => {
|
|
77
|
+
action("Delete Behavior")(node);
|
|
78
|
+
engine.removeNode(node.id);
|
|
79
|
+
editorRef.current.updateEngine(engine);
|
|
80
|
+
},
|
|
81
|
+
[engine, editorRef],
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
const deleteTransition = useCallback(
|
|
85
|
+
(edge) => {
|
|
86
|
+
action("Delete Transition")(edge);
|
|
87
|
+
const fromNode = engine.getNode(edge.from);
|
|
88
|
+
fromNode.removeGoToBehavior(edge.to);
|
|
89
|
+
editorRef.current.updateEngine(engine);
|
|
90
|
+
},
|
|
91
|
+
[engine, editorRef],
|
|
92
|
+
);
|
|
27
93
|
return (
|
|
28
94
|
<div className="graphBuilderRootContainer">
|
|
29
95
|
<div className="toolbar">
|
|
30
|
-
<ToolBar onSelectTool={selectTool}/>
|
|
96
|
+
<ToolBar onSelectTool={selectTool} />
|
|
31
97
|
</div>
|
|
32
98
|
<div className="flow">
|
|
33
|
-
<BehavioralGraphBuilder
|
|
99
|
+
<BehavioralGraphBuilder
|
|
100
|
+
ref={editorRef}
|
|
101
|
+
{...args}
|
|
102
|
+
connectBehaviors={connectBehaviors}
|
|
103
|
+
deleteTransition={deleteTransition}
|
|
104
|
+
deleteBehavior={deleteBehavior}
|
|
105
|
+
/>
|
|
34
106
|
</div>
|
|
35
107
|
</div>
|
|
36
|
-
)
|
|
37
|
-
}
|
|
108
|
+
);
|
|
109
|
+
};
|
|
38
110
|
|
|
39
|
-
export const Default = Template.bind({})
|
|
111
|
+
export const Default = Template.bind({});
|
|
40
112
|
|
|
41
113
|
Default.args = {
|
|
42
|
-
|
|
114
|
+
design: design,
|
|
115
|
+
};
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
import React, { useState } from "react";
|
|
2
2
|
|
|
3
3
|
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
NodePlus,
|
|
7
|
-
Trash
|
|
4
|
+
PlusSquare,
|
|
5
|
+
Floppy
|
|
8
6
|
} from "react-bootstrap-icons";
|
|
9
7
|
|
|
10
8
|
import "./ToolBar.scss";
|
|
@@ -26,32 +24,18 @@ export function ToolBar({ onSelectTool }) {
|
|
|
26
24
|
return (
|
|
27
25
|
<div className="toolbarWrapper">
|
|
28
26
|
<div className="toolbarContainer">
|
|
29
|
-
<
|
|
30
|
-
onClick={(e) => selectTool("
|
|
31
|
-
style={{color: selectedTool === "select" ? "white": "grey"}}
|
|
32
|
-
title="Select"
|
|
33
|
-
className="icon"
|
|
34
|
-
/>
|
|
35
|
-
<Square
|
|
36
|
-
onClick={(e) => selectTool("drop")}
|
|
37
|
-
style={{color: selectedTool === "drop" ? "white": "grey"}}
|
|
27
|
+
<PlusSquare
|
|
28
|
+
onClick={(e) => selectTool("add-node")}
|
|
38
29
|
title="Add Node"
|
|
39
30
|
className="icon"
|
|
40
31
|
/>
|
|
41
|
-
<NodePlus
|
|
42
|
-
onClick={(e) => selectTool("connect")}
|
|
43
|
-
style={{color: selectedTool === "connect" ? "white": "grey"}}
|
|
44
|
-
title="Connect Node"
|
|
45
|
-
className="icon"
|
|
46
|
-
/>
|
|
47
|
-
<Trash
|
|
48
|
-
onClick={(e) => selectTool("delete")}
|
|
49
|
-
style={{color: selectedTool === "delete" ? "white": "grey"}}
|
|
50
|
-
title="Delete Node"
|
|
51
|
-
className="icon"
|
|
52
|
-
/>
|
|
53
32
|
</div>
|
|
54
33
|
<div className="toolbarContainer bottom"></div>
|
|
34
|
+
<Floppy
|
|
35
|
+
onClick={(e) => selectTool("save")}
|
|
36
|
+
title="Save Design"
|
|
37
|
+
className="icon"
|
|
38
|
+
/>
|
|
55
39
|
</div>
|
|
56
40
|
);
|
|
57
41
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"uid":"3b9b65ab-5e3e-48a7-871c-c76de3e20187","type":5,"nodes":[{"uid":"2038c653-587d-4c33-9103-43b59d85c5be","type":6,"_behavior":{"uid":"19ffb9d9-772b-4aca-89b5-6278e0cbee89","type":1,"participants":[],"abstractionIds":[],"invalidWorldState":false,"name":"AcceptChoiceToAddBookToBasket"},"_goToBehaviorIds":["AcceptBookFromUser"]},{"uid":"98d6a9b8-3867-49c8-a93a-f0e11f70af3b","type":6,"_behavior":{"uid":"d1157a53-5938-42ca-92ad-d2d34d99c704","type":1,"participants":[],"abstractionIds":[],"invalidWorldState":false,"name":"AcceptBookFromUser"},"_goToBehaviorIds":["AddBookToBasket"]},{"uid":"2aeb336f-37cc-4f28-8301-f3464c387603","type":6,"_behavior":{"uid":"0dc90e9c-6342-4c3d-90f7-5e5e89b48b76","type":1,"participants":[],"abstractionIds":[],"invalidWorldState":false,"name":"AddBookToBasket"},"_goToBehaviorIds":[]},{"uid":"763e440b-8c09-4893-8e21-b7af11722d93","type":6,"_behavior":{"uid":"555f261d-00b8-4f2d-ad1d-7d18fb68a035","type":1,"participants":[],"abstractionIds":[],"invalidWorldState":false,"name":"AcceptChoiceToAuditLibrary"},"_goToBehaviorIds":["GenerateAuditReport"]},{"uid":"92ba2c22-3beb-442c-a198-562779d7936c","type":6,"_behavior":{"uid":"d44d5d9c-f0f5-4542-9b7d-21793ea1995c","type":1,"participants":[],"abstractionIds":[],"invalidWorldState":false,"name":"GenerateAuditReport"},"_goToBehaviorIds":["HandAuditToUser"]},{"uid":"f2e7e018-2596-4aeb-abeb-55948a17157c","type":6,"_behavior":{"uid":"17ac5068-a521-4fbd-9dcb-783d365e01fd","type":1,"participants":[],"abstractionIds":[],"invalidWorldState":false,"name":"HandAuditToUser"},"_goToBehaviorIds":[]},{"uid":"e89cefaa-cdda-450e-808e-ffee9250db01","type":6,"_behavior":{"uid":"4db0dab8-3d4c-4668-88de-e73f38d8c28e","type":1,"participants":[],"abstractionIds":[],"invalidWorldState":false,"name":"AcceptChoiceToPlaceBooksOnShelf"},"_goToBehaviorIds":[]},{"uid":"4d1de6bd-cd98-48de-81ed-9754b40c3a36","type":6,"_behavior":{"uid":"0ddc2e33-2b01-411b-a3ae-9f0198fafaf8","type":1,"participants":[],"abstractionIds":[],"invalidWorldState":false,"name":"GetFirstLetterOfBookName"},"_goToBehaviorIds":["CreateSlotOnBookShelf","AddBookToShelf"]},{"uid":"e8e5ffe7-ba16-4c3e-a87f-2083c2502812","type":6,"_behavior":{"uid":"eefbf993-c76b-4c80-bb8d-e3093aaa17cb","type":1,"participants":[],"abstractionIds":[],"invalidWorldState":false,"name":"CreateSlotOnBookShelf"},"_goToBehaviorIds":["AddBookToShelf"]},{"uid":"2fb19dc7-7647-44c1-afd1-4a157ab3d833","type":6,"_behavior":{"uid":"e4092d6e-49bb-4c54-9573-0379466c4ae6","type":1,"participants":[],"abstractionIds":[],"invalidWorldState":false,"name":"AddBookToShelf"},"_goToBehaviorIds":[]}]}
|