@vyr/service-graph 0.0.1
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/package.json +23 -0
- package/src/GraphDrawer.ts +309 -0
- package/src/GraphService.ts +181 -0
- package/src/asset/font/demo.css +539 -0
- package/src/asset/font/demo_index.html +326 -0
- package/src/asset/font/iconfont.css +39 -0
- package/src/asset/font/iconfont.js +1 -0
- package/src/asset/font/iconfont.json +51 -0
- package/src/asset/font/iconfont.ttf +0 -0
- package/src/asset/font/iconfont.woff +0 -0
- package/src/asset/font/iconfont.woff2 +0 -0
- package/src/asset/less/index.less +108 -0
- package/src/common/RoutineUnit.ts +65 -0
- package/src/common/Unit.ts +172 -0
- package/src/index.ts +7 -0
- package/src/locale/Language.ts +10 -0
- package/src/locale/LanguageProvider.ts +16 -0
- package/src/locale/index.ts +2 -0
package/package.json
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@vyr/service-graph",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "",
|
|
5
|
+
"main": "./src/index.ts",
|
|
6
|
+
"author": "",
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"dependencies": {
|
|
9
|
+
"vue": "3.5.22",
|
|
10
|
+
"@vyr/locale": "0.0.1",
|
|
11
|
+
"@vyr/engine": "0.0.1",
|
|
12
|
+
"@vyr/service": "0.0.1",
|
|
13
|
+
"jsondiffpatch": "^0.6.0",
|
|
14
|
+
"@antv/x6": "^2.18.1",
|
|
15
|
+
"@antv/x6-plugin-selection": "^2.2.2",
|
|
16
|
+
"@antv/x6-plugin-stencil": "^2.1.5",
|
|
17
|
+
"@antv/x6-plugin-history": "2.2.4"
|
|
18
|
+
},
|
|
19
|
+
"files": [
|
|
20
|
+
"package.json",
|
|
21
|
+
"src/"
|
|
22
|
+
]
|
|
23
|
+
}
|
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
import { Generate, Listener } from '@vyr/engine'
|
|
2
|
+
import { Cell, CellView, Edge, Graph, Shape } from '@antv/x6'
|
|
3
|
+
import { Selection } from '@antv/x6-plugin-selection'
|
|
4
|
+
import { Stencil } from '@antv/x6-plugin-stencil'
|
|
5
|
+
import { History } from '@antv/x6-plugin-history'
|
|
6
|
+
import { Options } from '@antv/x6/lib/graph/options'
|
|
7
|
+
import { Unit } from './common/Unit'
|
|
8
|
+
import { language } from './locale'
|
|
9
|
+
|
|
10
|
+
interface GraphObserver {
|
|
11
|
+
resize: (e: any) => void
|
|
12
|
+
select: (cell: Cell[]) => void
|
|
13
|
+
change: (e: {}) => void
|
|
14
|
+
remove: (cell: Cell) => void
|
|
15
|
+
link: (e: { source: string, target: string }) => void
|
|
16
|
+
unlink: (e: { source: string, target: string }) => void
|
|
17
|
+
dispose: (e: any) => void
|
|
18
|
+
}
|
|
19
|
+
type Connecting = Options.Connecting
|
|
20
|
+
|
|
21
|
+
class GraphDrawer extends Listener<GraphObserver> {
|
|
22
|
+
private isReadonly = false
|
|
23
|
+
readonly connecting
|
|
24
|
+
readonly dom = document.createElement('div')
|
|
25
|
+
readonly selection: Selection
|
|
26
|
+
readonly stencil: Stencil
|
|
27
|
+
readonly graph: Graph
|
|
28
|
+
readonly history: History
|
|
29
|
+
readonly tool
|
|
30
|
+
selectEdge = ''
|
|
31
|
+
container: Element | null = null
|
|
32
|
+
needTriggerChange = false
|
|
33
|
+
|
|
34
|
+
constructor() {
|
|
35
|
+
super()
|
|
36
|
+
this.dom = document.createElement('div')
|
|
37
|
+
this.connecting = {
|
|
38
|
+
snap: true,
|
|
39
|
+
allowMulti: false,
|
|
40
|
+
allowBlank: false,
|
|
41
|
+
allowLoop: false,
|
|
42
|
+
allowNode: false,
|
|
43
|
+
highlight: true,
|
|
44
|
+
connector: 'rounded',
|
|
45
|
+
connectionPoint: 'boundary',
|
|
46
|
+
router: 'manhattan',
|
|
47
|
+
validateMagnet: this._validateMagnet,
|
|
48
|
+
validateConnection: this._validateConnection,
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
this.graph = new Graph({
|
|
52
|
+
container: this.dom,
|
|
53
|
+
autoResize: true,
|
|
54
|
+
mousewheel: true,
|
|
55
|
+
panning: { enabled: true },
|
|
56
|
+
interacting: this._interacting,
|
|
57
|
+
connecting: {
|
|
58
|
+
...this.connecting,
|
|
59
|
+
createEdge: this._createEdge,
|
|
60
|
+
},
|
|
61
|
+
})
|
|
62
|
+
this.selection = new Selection({
|
|
63
|
+
enabled: true,
|
|
64
|
+
multiple: true,
|
|
65
|
+
rubberband: true,
|
|
66
|
+
movable: true,
|
|
67
|
+
modifiers: 'ctrl',
|
|
68
|
+
showNodeSelectionBox: true,
|
|
69
|
+
filter(cell) {
|
|
70
|
+
return cell instanceof Unit ? true : false
|
|
71
|
+
}
|
|
72
|
+
})
|
|
73
|
+
this.stencil = new Stencil({
|
|
74
|
+
target: this.graph,
|
|
75
|
+
title: language.get('graphDrawer.stencil.title'),
|
|
76
|
+
layoutOptions: { columns: 1, columnWidth: 200, dx: 20, },
|
|
77
|
+
stencilGraphHeight: 0,
|
|
78
|
+
stencilGraphPadding: 0,
|
|
79
|
+
groups: [{ name: 'inspector' }],
|
|
80
|
+
})
|
|
81
|
+
this.history = new History({ enabled: false, })
|
|
82
|
+
this.graph.use(this.selection)
|
|
83
|
+
this.graph.use(this.history)
|
|
84
|
+
|
|
85
|
+
this.tool = document.createElement('div')
|
|
86
|
+
this.tool.style.width = '240px';
|
|
87
|
+
this.tool.style.height = '100%';
|
|
88
|
+
this.tool.style.position = 'absolute';
|
|
89
|
+
this.tool.style.top = '0px'
|
|
90
|
+
this.tool.style.left = '0px'
|
|
91
|
+
this.tool.style.zIndex = '999'
|
|
92
|
+
this.tool.appendChild(this.stencil.container)
|
|
93
|
+
this.stencil.dnd.options.dndContainer = this.tool
|
|
94
|
+
|
|
95
|
+
this.graph.on('node:added', this._changeListener)
|
|
96
|
+
this.graph.on('node:removed', this._changeListener)
|
|
97
|
+
this.graph.on('edge:removed', this._changeListener)
|
|
98
|
+
this.graph.on('node:moved', this._changeListener)
|
|
99
|
+
|
|
100
|
+
this.graph.on('node:selected', this._delaySelect)
|
|
101
|
+
this.graph.on('node:unselected', this._delaySelect)
|
|
102
|
+
|
|
103
|
+
this.graph.on('edge:connected', (e) => {
|
|
104
|
+
//@ts-ignore
|
|
105
|
+
const source = e.edge.source.cell
|
|
106
|
+
//@ts-ignore
|
|
107
|
+
const target = e.edge.target.cell
|
|
108
|
+
|
|
109
|
+
const sourceCell = this.graph.getCellById(source)
|
|
110
|
+
const targetCell = this.graph.getCellById(target)
|
|
111
|
+
if (sourceCell instanceof Unit && targetCell instanceof Unit) {
|
|
112
|
+
this.trigger('link', { source, target })
|
|
113
|
+
this._changeListener()
|
|
114
|
+
}
|
|
115
|
+
})
|
|
116
|
+
|
|
117
|
+
//边
|
|
118
|
+
this.graph.on('edge:mouseenter', ({ edge }) => {
|
|
119
|
+
})
|
|
120
|
+
this.graph.on('edge:mouseleave', ({ edge }) => {
|
|
121
|
+
})
|
|
122
|
+
this.graph.on('edge:click', ({ edge }) => {
|
|
123
|
+
this._unselectEdge()
|
|
124
|
+
edge.setAttrs({ line: Unit.edge.highlight })
|
|
125
|
+
this.selectEdge = edge.id
|
|
126
|
+
})
|
|
127
|
+
this.graph.on('edge:removed', ({ edge }: any) => {
|
|
128
|
+
if (edge.id === this.selectEdge) this.selectEdge = ''
|
|
129
|
+
const source = this.graph.getCellById(edge.source.cell)
|
|
130
|
+
const target = this.graph.getCellById(edge.target.cell)
|
|
131
|
+
if (source instanceof Unit && target instanceof Unit) {
|
|
132
|
+
this.trigger('unlink', { source: edge.source.cell, target: edge.target.cell })
|
|
133
|
+
}
|
|
134
|
+
})
|
|
135
|
+
|
|
136
|
+
this.graph.on('blank:mouseup', () => {
|
|
137
|
+
this._unselectEdge()
|
|
138
|
+
})
|
|
139
|
+
this.graph.on('blank:contextmenu', (e) => {
|
|
140
|
+
})
|
|
141
|
+
this.graph.on('cell:contextmenu', ({ cell, x, y }) => {
|
|
142
|
+
if (cell instanceof Unit) cell.rightClick({ cell, x, y })
|
|
143
|
+
})
|
|
144
|
+
//点击节点
|
|
145
|
+
this.graph.on('cell:click', ({ cell, x, y }) => {
|
|
146
|
+
this._unselectEdge()
|
|
147
|
+
if (cell instanceof Unit) cell.click({ cell, x, y })
|
|
148
|
+
})
|
|
149
|
+
|
|
150
|
+
window.addEventListener('resize', this._resize)
|
|
151
|
+
window.addEventListener('keydown', this._delete)
|
|
152
|
+
|
|
153
|
+
this.listen('dispose', () => {
|
|
154
|
+
window.removeEventListener('resize', this._resize)
|
|
155
|
+
window.removeEventListener('keydown', this._delete)
|
|
156
|
+
})
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
private _interacting: CellView.Interacting = ({ cell }) => {
|
|
160
|
+
const result = {
|
|
161
|
+
nodeMovable: true
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
if (cell instanceof Unit) result.nodeMovable = cell.isMove()
|
|
165
|
+
|
|
166
|
+
return result
|
|
167
|
+
}
|
|
168
|
+
private _validateMagnet: Connecting['validateMagnet'] = ({ cell, magnet }) => {
|
|
169
|
+
return cell instanceof Unit ? cell.isCreateEdge(magnet) : false
|
|
170
|
+
}
|
|
171
|
+
private _createEdge: Connecting['createEdge'] = () => {
|
|
172
|
+
return new Shape.Edge({ attrs: Unit.edge })
|
|
173
|
+
}
|
|
174
|
+
private _validateConnection: Connecting['validateConnection'] = ({ sourceCell, targetCell, targetMagnet }) => {
|
|
175
|
+
if (!targetMagnet || !sourceCell) return false
|
|
176
|
+
return targetCell instanceof Unit ? targetCell.isConnection(targetMagnet, sourceCell) : false
|
|
177
|
+
}
|
|
178
|
+
private _undo = (e: KeyboardEvent) => {
|
|
179
|
+
if (e.ctrlKey === false || ['KeyZ'].includes(e.code) === false) return
|
|
180
|
+
if (this.history.canUndo()) this.history.undo()
|
|
181
|
+
}
|
|
182
|
+
private _redo = (e: KeyboardEvent) => {
|
|
183
|
+
if (e.ctrlKey === false || ['KeyY'].includes(e.code) === false) return
|
|
184
|
+
if (this.history.canRedo()) this.history.redo()
|
|
185
|
+
}
|
|
186
|
+
private _unselectEdge = () => {
|
|
187
|
+
if (this.selectEdge) {
|
|
188
|
+
const oldEdge = this.graph.getCellById(this.selectEdge)
|
|
189
|
+
oldEdge.setAttrs({ line: Unit.edge.line })
|
|
190
|
+
}
|
|
191
|
+
this.selectEdge = ''
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
private _delaySelect = Generate.delayExecute(() => {
|
|
195
|
+
const cells = this.selection.getSelectedCells()
|
|
196
|
+
this.trigger('select', cells)
|
|
197
|
+
})
|
|
198
|
+
private _changeListener = () => {
|
|
199
|
+
if (this.needTriggerChange === false) return
|
|
200
|
+
this._delayChange()
|
|
201
|
+
}
|
|
202
|
+
private _delayChange = Generate.delayExecute(() => {
|
|
203
|
+
this.trigger('change', {})
|
|
204
|
+
})
|
|
205
|
+
private _resize = Generate.delayExecute(() => {
|
|
206
|
+
if (!this.container) return
|
|
207
|
+
const rect = this.container.getBoundingClientRect()
|
|
208
|
+
this.graph.resize(rect.width, rect.height)
|
|
209
|
+
this.trigger('resize', {})
|
|
210
|
+
})
|
|
211
|
+
|
|
212
|
+
private _delete = (e: KeyboardEvent) => {
|
|
213
|
+
if (this.isReadonly === true) return
|
|
214
|
+
if (['Delete'].includes(e.code) === false) return
|
|
215
|
+
const cells = this.selection.getSelectedCells()
|
|
216
|
+
for (const cell of cells) this.remove(cell)
|
|
217
|
+
if (this.selectEdge) this.remove(this.graph.getCellById(this.selectEdge))
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
private _isEdgePort(data: { [k: string]: any }): data is { cell: string } {
|
|
221
|
+
return data?.cell ? true : false
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
getMapper(edge: Edge) {
|
|
225
|
+
if (this._isEdgePort(edge.source) === false) return null
|
|
226
|
+
if (this._isEdgePort(edge.target) === false) return null
|
|
227
|
+
return { source: edge.source.cell, target: edge.target.cell }
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
getEdgeOfMapper(source: string, target: string) {
|
|
231
|
+
const edge = {
|
|
232
|
+
shape: 'edge',
|
|
233
|
+
source: { cell: source, port: 'out' },
|
|
234
|
+
target: { cell: target, port: 'in' },
|
|
235
|
+
attrs: Unit.edge,
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
return edge
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
setReadonly(readonly: boolean) {
|
|
242
|
+
this.isReadonly = readonly
|
|
243
|
+
let display = 'none'
|
|
244
|
+
if (readonly) {
|
|
245
|
+
this.graph.options.interacting = false
|
|
246
|
+
} else {
|
|
247
|
+
this.graph.options.interacting = this._interacting
|
|
248
|
+
display = 'block'
|
|
249
|
+
}
|
|
250
|
+
this.tool.style.display = display
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
mount(container: Element | string) {
|
|
254
|
+
this.container = container instanceof Element ? container : document.getElementById(container) ?? null
|
|
255
|
+
if (this.container === null) return
|
|
256
|
+
this.container.appendChild(this.dom)
|
|
257
|
+
this.container.appendChild(this.tool)
|
|
258
|
+
this._resize()
|
|
259
|
+
window.addEventListener('keydown', this._redo)
|
|
260
|
+
window.addEventListener('keydown', this._undo)
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
unmount() {
|
|
264
|
+
if (!this.container) return
|
|
265
|
+
window.removeEventListener('keydown', this._redo)
|
|
266
|
+
window.removeEventListener('keydown', this._undo)
|
|
267
|
+
this.container.removeChild(this.dom)
|
|
268
|
+
this.container = null
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
find(id: string) {
|
|
272
|
+
const cells = this.graph.getCells()
|
|
273
|
+
for (const cell of cells) {
|
|
274
|
+
if (cell.id === id) return cell as Unit
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
return null
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
remove(cell: Cell) {
|
|
281
|
+
const parentCell = cell.parent
|
|
282
|
+
this.graph.removeCell(cell)
|
|
283
|
+
|
|
284
|
+
if (parentCell) {
|
|
285
|
+
const subs = parentCell.getChildren() as Cell[]
|
|
286
|
+
for (let i = 0; i < subs.length; i++) {
|
|
287
|
+
const sub = subs[i]
|
|
288
|
+
sub.setProp('position', { x: 0, y: i * Unit.height })
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
if (cell instanceof Unit) this.trigger('remove', cell)
|
|
293
|
+
cell.dispose()
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
clear() {
|
|
297
|
+
this._unselectEdge()
|
|
298
|
+
this.graph.resetCells([])
|
|
299
|
+
// this.history.clean()
|
|
300
|
+
this.selection.clean()
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
dispose() {
|
|
304
|
+
this.clear()
|
|
305
|
+
this.unmount()
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
export { GraphDrawer }
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import { reactive, AsyncComponentLoader, defineAsyncComponent } from 'vue'
|
|
2
|
+
import { Service } from "@vyr/service"
|
|
3
|
+
import { DeserializationObject, InteractionInputCollection, ObjectUtils, RoutineDescriptor, RoutineMapper, RoutineNode } from '@vyr/engine'
|
|
4
|
+
import { Unit } from './common/Unit'
|
|
5
|
+
import { BranchUnit, ConditionUnit, ExecuteUnit, RoutineUnit as GraphRoutineUnit } from './common/RoutineUnit'
|
|
6
|
+
import { GraphDrawer } from './GraphDrawer'
|
|
7
|
+
|
|
8
|
+
class GraphState {
|
|
9
|
+
width = '60%'
|
|
10
|
+
height = '60%'
|
|
11
|
+
visible = false
|
|
12
|
+
descriptor = ''
|
|
13
|
+
event = ''
|
|
14
|
+
inputs: InteractionInputCollection = {}
|
|
15
|
+
routine: DeserializationObject<RoutineDescriptor> | null = null
|
|
16
|
+
|
|
17
|
+
reset() {
|
|
18
|
+
this.descriptor = ''
|
|
19
|
+
this.event = ''
|
|
20
|
+
this.inputs = {}
|
|
21
|
+
this.routine = null
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
class GraphService extends Service {
|
|
26
|
+
private _map = new Map()
|
|
27
|
+
private _drawer: GraphDrawer | null = null
|
|
28
|
+
get drawer() {
|
|
29
|
+
if (this._drawer === null) {
|
|
30
|
+
this._drawer = new GraphDrawer()
|
|
31
|
+
this._drawer.stencil.load([
|
|
32
|
+
new ExecuteUnit({ drawer: this._drawer, label: 'Execute' },),
|
|
33
|
+
new BranchUnit({ drawer: this._drawer, label: 'Branch' }),
|
|
34
|
+
new ConditionUnit({ drawer: this._drawer, label: 'Condition' }),
|
|
35
|
+
], 'inspector')
|
|
36
|
+
}
|
|
37
|
+
return this._drawer
|
|
38
|
+
}
|
|
39
|
+
readonly state = reactive(new GraphState())
|
|
40
|
+
routine: DeserializationObject<RoutineDescriptor> | null = null
|
|
41
|
+
|
|
42
|
+
private _doNodes(nodes: RoutineNode[]) {
|
|
43
|
+
for (const node of nodes) {
|
|
44
|
+
if (node.routine === 'Execute') {
|
|
45
|
+
const cell = new ExecuteUnit({ ...node, drawer: this.drawer })
|
|
46
|
+
this.drawer.graph.addCell(cell)
|
|
47
|
+
} else if (node.routine === 'Condition') {
|
|
48
|
+
this.drawer.graph.addCell(new ConditionUnit({ ...node, drawer: this.drawer }))
|
|
49
|
+
} else if (node.routine === 'Branch') {
|
|
50
|
+
this.drawer.graph.addCell(new BranchUnit({ ...node, drawer: this.drawer }))
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
}
|
|
55
|
+
private _doMappers(mappers: RoutineMapper[]) {
|
|
56
|
+
for (const mapper of mappers) {
|
|
57
|
+
const edge = this.drawer.getEdgeOfMapper(mapper.source, mapper.target)
|
|
58
|
+
this.drawer.graph.addEdge(edge)
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
private _diff(cur: RoutineNode[], old: RoutineNode[]) {
|
|
63
|
+
const addQueue: RoutineNode[] = []
|
|
64
|
+
const removeQueue: RoutineNode[] = []
|
|
65
|
+
const updateQueue: RoutineNode[] = []
|
|
66
|
+
|
|
67
|
+
const temp = new Map<string, RoutineNode>()
|
|
68
|
+
for (const oldItem of old) {
|
|
69
|
+
temp.set(oldItem.id, oldItem)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
for (const curItem of cur) {
|
|
73
|
+
const oldItem = temp.get(curItem.id)
|
|
74
|
+
if (oldItem === undefined) {
|
|
75
|
+
addQueue.push(curItem)
|
|
76
|
+
} else {
|
|
77
|
+
if (ObjectUtils.equals(curItem, oldItem) === false) updateQueue.push(curItem)
|
|
78
|
+
temp.delete(curItem.id)
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
removeQueue.push(...temp.values())
|
|
83
|
+
|
|
84
|
+
return {
|
|
85
|
+
addQueue,
|
|
86
|
+
removeQueue,
|
|
87
|
+
updateQueue
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
render(routine: DeserializationObject<RoutineDescriptor>) {
|
|
92
|
+
this.routine = routine
|
|
93
|
+
|
|
94
|
+
this.drawer.needTriggerChange = false
|
|
95
|
+
this._doNodes(routine.nodes)
|
|
96
|
+
this._doMappers(routine.mappers)
|
|
97
|
+
this.drawer.needTriggerChange = true
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
update(curRoutine: DeserializationObject<RoutineDescriptor>) {
|
|
101
|
+
if (this.routine === null) return
|
|
102
|
+
|
|
103
|
+
this.drawer.needTriggerChange = false
|
|
104
|
+
this.drawer.selectEdge = ''
|
|
105
|
+
this.drawer.history.clean()
|
|
106
|
+
const selects = this.drawer.selection.getSelectedCells()
|
|
107
|
+
|
|
108
|
+
const edges = this.drawer.graph.getEdges()
|
|
109
|
+
for (const edge of edges) this.drawer.remove(edge)
|
|
110
|
+
|
|
111
|
+
const patch = this._diff(curRoutine.nodes, this.routine.nodes)
|
|
112
|
+
|
|
113
|
+
let needCleanSelection = false
|
|
114
|
+
for (const remove of patch.removeQueue) {
|
|
115
|
+
const cell = this.drawer.graph.getCellById(remove.id)
|
|
116
|
+
if (!cell) continue
|
|
117
|
+
if (selects.includes(cell)) needCleanSelection = true
|
|
118
|
+
this.drawer.remove(cell)
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (needCleanSelection) this.drawer.selection.clean()
|
|
122
|
+
|
|
123
|
+
this._doNodes(patch.addQueue)
|
|
124
|
+
|
|
125
|
+
for (const update of patch.updateQueue) {
|
|
126
|
+
const cell = this.drawer.graph.getCellById(update.id) as Unit
|
|
127
|
+
if (cell) cell.setVMeta(update)
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
this._doMappers(curRoutine.mappers)
|
|
131
|
+
this.drawer.needTriggerChange = true
|
|
132
|
+
|
|
133
|
+
this.routine = curRoutine
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
build() {
|
|
137
|
+
const routine = new RoutineDescriptor()
|
|
138
|
+
const cells = this.drawer.graph.getCells()
|
|
139
|
+
|
|
140
|
+
for (const cell of cells) {
|
|
141
|
+
if (cell instanceof GraphRoutineUnit) {
|
|
142
|
+
const node = {
|
|
143
|
+
id: cell.id,
|
|
144
|
+
label: cell.vMeta.label ?? '',
|
|
145
|
+
url: cell.vMeta.url,
|
|
146
|
+
routine: cell.vMeta.routine,
|
|
147
|
+
input: cell.vMeta.input,
|
|
148
|
+
position: cell.getPosition(),
|
|
149
|
+
}
|
|
150
|
+
routine.nodes.push(node)
|
|
151
|
+
} else if (cell.isEdge()) {
|
|
152
|
+
const mapper = this.drawer.getMapper(cell)
|
|
153
|
+
if (mapper) routine.mappers.push(mapper)
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const roots = this.drawer.graph.getRootNodes()
|
|
158
|
+
for (const root of roots) routine.roots.push(root.id)
|
|
159
|
+
|
|
160
|
+
return { ...routine, uuid: this.routine?.uuid }
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
get(id: string) {
|
|
164
|
+
return this._map.get(id) ?? null
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
keys() {
|
|
168
|
+
return [...this._map.keys()]
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
set(id: string, executor: AsyncComponentLoader): void {
|
|
172
|
+
const component = defineAsyncComponent({
|
|
173
|
+
loader: executor,
|
|
174
|
+
timeout: 5000
|
|
175
|
+
})
|
|
176
|
+
this._map.set(id, component)
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
export { GraphService }
|