@flowgram.ai/free-history-plugin 0.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/dist/esm/index.js +761 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/index.d.mts +158 -0
- package/dist/index.d.ts +158 -0
- package/dist/index.js +787 -0
- package/dist/index.js.map +1 -0
- package/package.json +52 -0
|
@@ -0,0 +1,761 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
|
+
var __decorateClass = (decorators, target, key, kind) => {
|
|
4
|
+
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
|
|
5
|
+
for (var i = decorators.length - 1, decorator; i >= 0; i--)
|
|
6
|
+
if (decorator = decorators[i])
|
|
7
|
+
result = (kind ? decorator(target, key, result) : decorator(result)) || result;
|
|
8
|
+
if (kind && result) __defProp(target, key, result);
|
|
9
|
+
return result;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
// src/create-free-history-plugin.ts
|
|
13
|
+
import { bindContributions, definePluginCreator } from "@flowgram.ai/core";
|
|
14
|
+
import { HistoryContainerModule, OperationContribution } from "@flowgram.ai/history";
|
|
15
|
+
|
|
16
|
+
// src/history-entity-manager.ts
|
|
17
|
+
import { cloneDeep, isEqual } from "lodash";
|
|
18
|
+
import { injectable } from "inversify";
|
|
19
|
+
import { DisposableCollection } from "@flowgram.ai/utils";
|
|
20
|
+
var HistoryEntityManager = class {
|
|
21
|
+
constructor() {
|
|
22
|
+
this._entityDataValues = /* @__PURE__ */ new Map();
|
|
23
|
+
this._toDispose = new DisposableCollection();
|
|
24
|
+
}
|
|
25
|
+
addEntityData(entityData) {
|
|
26
|
+
this._entityDataValues.set(entityData, cloneDeep(entityData.toJSON()));
|
|
27
|
+
this._toDispose.push(
|
|
28
|
+
entityData.onWillChange((event) => {
|
|
29
|
+
const value = event.toJSON();
|
|
30
|
+
const oldValue = this._entityDataValues.get(entityData);
|
|
31
|
+
if (isEqual(value, oldValue)) {
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
this._entityDataValues.set(entityData, cloneDeep(value));
|
|
35
|
+
})
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
getValue(entityData) {
|
|
39
|
+
return this._entityDataValues.get(entityData);
|
|
40
|
+
}
|
|
41
|
+
setValue(entityData, value) {
|
|
42
|
+
return this._entityDataValues.set(entityData, value);
|
|
43
|
+
}
|
|
44
|
+
dispose() {
|
|
45
|
+
this._entityDataValues.clear();
|
|
46
|
+
this._toDispose.dispose();
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
HistoryEntityManager = __decorateClass([
|
|
50
|
+
injectable()
|
|
51
|
+
], HistoryEntityManager);
|
|
52
|
+
|
|
53
|
+
// src/handlers/drag-nodes-handler.ts
|
|
54
|
+
import { injectable as injectable2, inject } from "inversify";
|
|
55
|
+
import { TransformData } from "@flowgram.ai/core";
|
|
56
|
+
import { HistoryService } from "@flowgram.ai/history";
|
|
57
|
+
|
|
58
|
+
// src/types.ts
|
|
59
|
+
var FreeOperationType = /* @__PURE__ */ ((FreeOperationType2) => {
|
|
60
|
+
FreeOperationType2["addLine"] = "addLine";
|
|
61
|
+
FreeOperationType2["deleteLine"] = "deleteLine";
|
|
62
|
+
FreeOperationType2["moveNode"] = "moveNode";
|
|
63
|
+
FreeOperationType2["addNode"] = "addNode";
|
|
64
|
+
FreeOperationType2["deleteNode"] = "deleteNode";
|
|
65
|
+
FreeOperationType2["changeNodeData"] = "changeNodeData";
|
|
66
|
+
FreeOperationType2["resetLayout"] = "resetLayout";
|
|
67
|
+
FreeOperationType2["dragNodes"] = "dragNodes";
|
|
68
|
+
return FreeOperationType2;
|
|
69
|
+
})(FreeOperationType || {});
|
|
70
|
+
|
|
71
|
+
// src/handlers/drag-nodes-handler.ts
|
|
72
|
+
var DragNodesHandler = class {
|
|
73
|
+
handle(event) {
|
|
74
|
+
if (event.type === "onDragEnd" && !event.altKey) {
|
|
75
|
+
this._dragNode(event);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
_dragNode(event) {
|
|
79
|
+
this._historyService.pushOperation(
|
|
80
|
+
{
|
|
81
|
+
type: "dragNodes" /* dragNodes */,
|
|
82
|
+
value: {
|
|
83
|
+
ids: event.nodes.map((node) => node.id),
|
|
84
|
+
value: event.nodes.map((node) => {
|
|
85
|
+
const { x, y } = node.getData(TransformData).position;
|
|
86
|
+
return {
|
|
87
|
+
x,
|
|
88
|
+
y
|
|
89
|
+
};
|
|
90
|
+
}),
|
|
91
|
+
oldValue: event.startPositions
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
{ noApply: true }
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
__decorateClass([
|
|
99
|
+
inject(HistoryService)
|
|
100
|
+
], DragNodesHandler.prototype, "_historyService", 2);
|
|
101
|
+
DragNodesHandler = __decorateClass([
|
|
102
|
+
injectable2()
|
|
103
|
+
], DragNodesHandler);
|
|
104
|
+
|
|
105
|
+
// src/handlers/change-node-data-handler.ts
|
|
106
|
+
import { cloneDeep as cloneDeep2, get, isEqual as isEqual2, set } from "lodash";
|
|
107
|
+
import { injectable as injectable4, inject as inject2 } from "inversify";
|
|
108
|
+
import { FlowNodeFormData } from "@flowgram.ai/form-core";
|
|
109
|
+
import { WorkflowDocument } from "@flowgram.ai/free-layout-core";
|
|
110
|
+
import { HistoryService as HistoryService2 } from "@flowgram.ai/history";
|
|
111
|
+
|
|
112
|
+
// src/free-history-config.ts
|
|
113
|
+
import { injectable as injectable3 } from "inversify";
|
|
114
|
+
var FreeHistoryConfig = class {
|
|
115
|
+
constructor() {
|
|
116
|
+
this.enable = false;
|
|
117
|
+
this.nodeToJSON = (node) => node.toJSON();
|
|
118
|
+
this.getNodeLabelById = (id) => id;
|
|
119
|
+
this.getNodeLabel = (node) => node.id;
|
|
120
|
+
this.getBlockLabel = (node) => node.id;
|
|
121
|
+
this.getNodeURI = (id) => `node:${id}`;
|
|
122
|
+
this.getLineURI = (id) => `line:${id}`;
|
|
123
|
+
}
|
|
124
|
+
init(ctx, options) {
|
|
125
|
+
this.enable = !!options?.enable;
|
|
126
|
+
if (options.nodeToJSON) {
|
|
127
|
+
this.nodeToJSON = options.nodeToJSON(ctx);
|
|
128
|
+
}
|
|
129
|
+
if (options.getNodeLabelById) {
|
|
130
|
+
this.getNodeLabelById = options.getNodeLabelById(ctx);
|
|
131
|
+
}
|
|
132
|
+
if (options.getNodeLabel) {
|
|
133
|
+
this.getNodeLabel = options.getNodeLabel(ctx);
|
|
134
|
+
}
|
|
135
|
+
if (options.getBlockLabel) {
|
|
136
|
+
this.getBlockLabel = options.getBlockLabel(ctx);
|
|
137
|
+
}
|
|
138
|
+
if (options.getNodeURI) {
|
|
139
|
+
this.getNodeURI = options.getNodeURI(ctx);
|
|
140
|
+
}
|
|
141
|
+
if (options.getLineURI) {
|
|
142
|
+
this.getLineURI = options.getLineURI(ctx);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
FreeHistoryConfig = __decorateClass([
|
|
147
|
+
injectable3()
|
|
148
|
+
], FreeHistoryConfig);
|
|
149
|
+
|
|
150
|
+
// src/handlers/change-node-data-handler.ts
|
|
151
|
+
var ChangeNodeDataHandler = class {
|
|
152
|
+
handle(event) {
|
|
153
|
+
const { path, value, initialized, node } = event;
|
|
154
|
+
const formData = node.getData(FlowNodeFormData);
|
|
155
|
+
const oldValue = this._entityManager.getValue(formData);
|
|
156
|
+
const propPath = path.split("/").filter(Boolean).join(".");
|
|
157
|
+
const propOldValue = propPath ? get(oldValue, propPath) : oldValue;
|
|
158
|
+
if (isEqual2(value, propOldValue)) {
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
if (initialized) {
|
|
162
|
+
let operationPath = path;
|
|
163
|
+
let operationValue = cloneDeep2(value);
|
|
164
|
+
let operationOldValue = propOldValue;
|
|
165
|
+
if (path !== "/") {
|
|
166
|
+
const clonedOldValue = cloneDeep2(oldValue);
|
|
167
|
+
set(clonedOldValue, propPath, value);
|
|
168
|
+
operationPath = path.split("/").filter(Boolean)[0];
|
|
169
|
+
operationValue = get(clonedOldValue, operationPath);
|
|
170
|
+
operationOldValue = get(oldValue, operationPath);
|
|
171
|
+
}
|
|
172
|
+
this._historyService.pushOperation(
|
|
173
|
+
{
|
|
174
|
+
type: "changeNodeData" /* changeNodeData */,
|
|
175
|
+
value: {
|
|
176
|
+
id: node.id,
|
|
177
|
+
path: operationPath,
|
|
178
|
+
value: operationValue,
|
|
179
|
+
oldValue: operationOldValue
|
|
180
|
+
},
|
|
181
|
+
uri: this._config.getNodeURI(node.id)
|
|
182
|
+
},
|
|
183
|
+
{ noApply: true }
|
|
184
|
+
);
|
|
185
|
+
}
|
|
186
|
+
if (propPath) {
|
|
187
|
+
set(oldValue, propPath, cloneDeep2(value));
|
|
188
|
+
} else {
|
|
189
|
+
this._entityManager.setValue(formData, cloneDeep2(value));
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
};
|
|
193
|
+
__decorateClass([
|
|
194
|
+
inject2(HistoryService2)
|
|
195
|
+
], ChangeNodeDataHandler.prototype, "_historyService", 2);
|
|
196
|
+
__decorateClass([
|
|
197
|
+
inject2(WorkflowDocument)
|
|
198
|
+
], ChangeNodeDataHandler.prototype, "document", 2);
|
|
199
|
+
__decorateClass([
|
|
200
|
+
inject2(HistoryEntityManager)
|
|
201
|
+
], ChangeNodeDataHandler.prototype, "_entityManager", 2);
|
|
202
|
+
__decorateClass([
|
|
203
|
+
inject2(FreeHistoryConfig)
|
|
204
|
+
], ChangeNodeDataHandler.prototype, "_config", 2);
|
|
205
|
+
ChangeNodeDataHandler = __decorateClass([
|
|
206
|
+
injectable4()
|
|
207
|
+
], ChangeNodeDataHandler);
|
|
208
|
+
|
|
209
|
+
// src/handlers/change-content-handler.ts
|
|
210
|
+
import { injectable as injectable5, inject as inject3 } from "inversify";
|
|
211
|
+
import { HistoryService as HistoryService3 } from "@flowgram.ai/history";
|
|
212
|
+
|
|
213
|
+
// src/changes/delete-node-change.ts
|
|
214
|
+
import { WorkflowDocument as WorkflowDocument2, WorkflowContentChangeType, delay } from "@flowgram.ai/free-layout-core";
|
|
215
|
+
var deleteNodeChange = {
|
|
216
|
+
type: WorkflowContentChangeType.DELETE_NODE,
|
|
217
|
+
toOperation: async (event, ctx) => {
|
|
218
|
+
const config = ctx.get(FreeHistoryConfig);
|
|
219
|
+
const document = ctx.get(WorkflowDocument2);
|
|
220
|
+
const node = event.entity;
|
|
221
|
+
const json = await document.toNodeJSON(node);
|
|
222
|
+
const parentID = node.parent?.id;
|
|
223
|
+
await delay(0);
|
|
224
|
+
return {
|
|
225
|
+
type: "deleteNode" /* deleteNode */,
|
|
226
|
+
value: {
|
|
227
|
+
node: json,
|
|
228
|
+
parentID
|
|
229
|
+
},
|
|
230
|
+
uri: config.getNodeURI(node.id)
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
};
|
|
234
|
+
|
|
235
|
+
// src/changes/delete-line-change.ts
|
|
236
|
+
import { WorkflowContentChangeType as WorkflowContentChangeType2 } from "@flowgram.ai/free-layout-core";
|
|
237
|
+
var deleteLineChange = {
|
|
238
|
+
type: WorkflowContentChangeType2.DELETE_LINE,
|
|
239
|
+
toOperation: (event, ctx) => {
|
|
240
|
+
const config = ctx.get(FreeHistoryConfig);
|
|
241
|
+
const line = event.entity;
|
|
242
|
+
const value = {
|
|
243
|
+
from: line.info.from,
|
|
244
|
+
to: line.info.to || "",
|
|
245
|
+
fromPort: line.info.fromPort || "",
|
|
246
|
+
toPort: line.info.toPort || "",
|
|
247
|
+
id: line.id
|
|
248
|
+
};
|
|
249
|
+
return {
|
|
250
|
+
type: "deleteLine" /* deleteLine */,
|
|
251
|
+
value,
|
|
252
|
+
uri: config.getNodeURI(line.id)
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
};
|
|
256
|
+
|
|
257
|
+
// src/changes/add-node-change.ts
|
|
258
|
+
import { WorkflowDocument as WorkflowDocument3, delay as delay2 } from "@flowgram.ai/free-layout-core";
|
|
259
|
+
import { WorkflowContentChangeType as WorkflowContentChangeType3 } from "@flowgram.ai/free-layout-core";
|
|
260
|
+
var addNodeChange = {
|
|
261
|
+
type: WorkflowContentChangeType3.ADD_NODE,
|
|
262
|
+
toOperation: async (event, ctx) => {
|
|
263
|
+
const config = ctx.get(FreeHistoryConfig);
|
|
264
|
+
const document = ctx.get(WorkflowDocument3);
|
|
265
|
+
const node = event.entity;
|
|
266
|
+
const parentID = node.parent?.id;
|
|
267
|
+
await delay2(10);
|
|
268
|
+
const json = await document.toNodeJSON(node);
|
|
269
|
+
return {
|
|
270
|
+
type: "addNode" /* addNode */,
|
|
271
|
+
value: {
|
|
272
|
+
node: json,
|
|
273
|
+
parentID
|
|
274
|
+
},
|
|
275
|
+
uri: config.getNodeURI(node.id)
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
};
|
|
279
|
+
|
|
280
|
+
// src/changes/add-line-change.ts
|
|
281
|
+
import { WorkflowContentChangeType as WorkflowContentChangeType4 } from "@flowgram.ai/free-layout-core";
|
|
282
|
+
var addLineChange = {
|
|
283
|
+
type: WorkflowContentChangeType4.ADD_LINE,
|
|
284
|
+
toOperation: (event, ctx) => {
|
|
285
|
+
const config = ctx.get(FreeHistoryConfig);
|
|
286
|
+
const line = event.entity;
|
|
287
|
+
const value = {
|
|
288
|
+
from: line.info.from,
|
|
289
|
+
to: line.info.to || "",
|
|
290
|
+
fromPort: line.info.fromPort || "",
|
|
291
|
+
toPort: line.info.toPort || "",
|
|
292
|
+
id: line.id
|
|
293
|
+
};
|
|
294
|
+
return {
|
|
295
|
+
type: "addLine" /* addLine */,
|
|
296
|
+
value,
|
|
297
|
+
uri: config.getLineURI(line.id)
|
|
298
|
+
};
|
|
299
|
+
}
|
|
300
|
+
};
|
|
301
|
+
|
|
302
|
+
// src/changes/index.ts
|
|
303
|
+
var changes_default = [addLineChange, deleteLineChange, addNodeChange, deleteNodeChange];
|
|
304
|
+
|
|
305
|
+
// src/handlers/change-content-handler.ts
|
|
306
|
+
var ChangeContentHandler = class {
|
|
307
|
+
async handle(event, ctx) {
|
|
308
|
+
if (!this._historyService.undoRedoService.canPush()) {
|
|
309
|
+
return;
|
|
310
|
+
}
|
|
311
|
+
const change = changes_default.find((c) => c.type === event.type);
|
|
312
|
+
if (!change) {
|
|
313
|
+
return;
|
|
314
|
+
}
|
|
315
|
+
const operation = await change.toOperation(event, ctx);
|
|
316
|
+
if (!operation) {
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
319
|
+
this._historyService.pushOperation(operation, { noApply: true });
|
|
320
|
+
}
|
|
321
|
+
};
|
|
322
|
+
__decorateClass([
|
|
323
|
+
inject3(HistoryService3)
|
|
324
|
+
], ChangeContentHandler.prototype, "_historyService", 2);
|
|
325
|
+
ChangeContentHandler = __decorateClass([
|
|
326
|
+
injectable5()
|
|
327
|
+
], ChangeContentHandler);
|
|
328
|
+
|
|
329
|
+
// src/free-history-registers.ts
|
|
330
|
+
import { injectable as injectable6 } from "inversify";
|
|
331
|
+
|
|
332
|
+
// src/operation-metas/reset-layout.ts
|
|
333
|
+
import { WorkflowResetLayoutService } from "@flowgram.ai/free-layout-core";
|
|
334
|
+
|
|
335
|
+
// src/operation-metas/base.ts
|
|
336
|
+
var baseOperationMeta = {
|
|
337
|
+
shouldMerge: (_op, prev, element) => {
|
|
338
|
+
if (!prev) {
|
|
339
|
+
return false;
|
|
340
|
+
}
|
|
341
|
+
if (
|
|
342
|
+
// 合并500ms内的操作, 如删除节点会联动删除线条
|
|
343
|
+
Date.now() - element.getTimestamp() < 500
|
|
344
|
+
) {
|
|
345
|
+
return true;
|
|
346
|
+
}
|
|
347
|
+
return false;
|
|
348
|
+
}
|
|
349
|
+
};
|
|
350
|
+
|
|
351
|
+
// src/operation-metas/reset-layout.ts
|
|
352
|
+
var resetLayoutOperationMeta = {
|
|
353
|
+
...baseOperationMeta,
|
|
354
|
+
type: "resetLayout" /* resetLayout */,
|
|
355
|
+
inverse: (op) => ({
|
|
356
|
+
...op,
|
|
357
|
+
value: {
|
|
358
|
+
...op.value,
|
|
359
|
+
value: op.value.oldValue,
|
|
360
|
+
oldValue: op.value.value
|
|
361
|
+
}
|
|
362
|
+
}),
|
|
363
|
+
apply: async (operation, ctx) => {
|
|
364
|
+
const reset = ctx.get(WorkflowResetLayoutService);
|
|
365
|
+
await reset.layoutToPositions(operation.value.ids, operation.value.value);
|
|
366
|
+
},
|
|
367
|
+
shouldMerge: () => false
|
|
368
|
+
};
|
|
369
|
+
|
|
370
|
+
// src/operation-metas/drag-nodes.ts
|
|
371
|
+
import { FlowNodeTransformData } from "@flowgram.ai/document";
|
|
372
|
+
import { TransformData as TransformData2 } from "@flowgram.ai/core";
|
|
373
|
+
import { WorkflowDocument as WorkflowDocument4 } from "@flowgram.ai/free-layout-core";
|
|
374
|
+
var dragNodesOperationMeta = {
|
|
375
|
+
...baseOperationMeta,
|
|
376
|
+
type: "dragNodes" /* dragNodes */,
|
|
377
|
+
inverse: (op) => ({
|
|
378
|
+
...op,
|
|
379
|
+
value: {
|
|
380
|
+
...op.value,
|
|
381
|
+
value: op.value.oldValue,
|
|
382
|
+
oldValue: op.value.value
|
|
383
|
+
}
|
|
384
|
+
}),
|
|
385
|
+
apply: (operation, ctx) => {
|
|
386
|
+
operation.value.ids.forEach((id, index) => {
|
|
387
|
+
const document = ctx.get(WorkflowDocument4);
|
|
388
|
+
const node = document.getNode(id);
|
|
389
|
+
if (!node) {
|
|
390
|
+
return;
|
|
391
|
+
}
|
|
392
|
+
const transform = node.getData(TransformData2);
|
|
393
|
+
const point = operation.value.value[index];
|
|
394
|
+
transform.update({
|
|
395
|
+
position: {
|
|
396
|
+
x: point.x,
|
|
397
|
+
y: point.y
|
|
398
|
+
}
|
|
399
|
+
});
|
|
400
|
+
if (node.collapsedChildren?.length > 0) {
|
|
401
|
+
node.collapsedChildren.forEach((childNode) => {
|
|
402
|
+
const childNodeTransformData = childNode.getData(FlowNodeTransformData);
|
|
403
|
+
childNodeTransformData.fireChange();
|
|
404
|
+
});
|
|
405
|
+
}
|
|
406
|
+
});
|
|
407
|
+
},
|
|
408
|
+
shouldMerge: () => false
|
|
409
|
+
};
|
|
410
|
+
|
|
411
|
+
// src/operation-metas/delete-node.ts
|
|
412
|
+
import { WorkflowDocument as WorkflowDocument5 } from "@flowgram.ai/free-layout-core";
|
|
413
|
+
var deleteNodeOperationMeta = {
|
|
414
|
+
...baseOperationMeta,
|
|
415
|
+
type: "deleteNode" /* deleteNode */,
|
|
416
|
+
inverse: (op) => ({
|
|
417
|
+
...op,
|
|
418
|
+
type: "addNode" /* addNode */
|
|
419
|
+
}),
|
|
420
|
+
apply: (operation, ctx) => {
|
|
421
|
+
const document = ctx.get(WorkflowDocument5);
|
|
422
|
+
const node = document.getNode(operation.value.node.id);
|
|
423
|
+
if (node) {
|
|
424
|
+
node.dispose();
|
|
425
|
+
}
|
|
426
|
+
},
|
|
427
|
+
getLabel: (op, ctx) => {
|
|
428
|
+
const config = ctx.get(FreeHistoryConfig);
|
|
429
|
+
return `Delete Node ${config.getNodeLabel(op.value.node)}`;
|
|
430
|
+
},
|
|
431
|
+
getDescription: (op, ctx) => {
|
|
432
|
+
const config = ctx.get(FreeHistoryConfig);
|
|
433
|
+
let desc = `Delete Node ${config.getNodeLabel(op.value.node)}`;
|
|
434
|
+
if (op.value.node.meta?.position) {
|
|
435
|
+
desc += ` at ${op.value.node.meta.position.x},${op.value.node.meta.position.y}`;
|
|
436
|
+
}
|
|
437
|
+
return desc;
|
|
438
|
+
}
|
|
439
|
+
};
|
|
440
|
+
|
|
441
|
+
// src/operation-metas/delete-line.ts
|
|
442
|
+
import { WorkflowDocument as WorkflowDocument6 } from "@flowgram.ai/free-layout-core";
|
|
443
|
+
var deleteLineOperationMeta = {
|
|
444
|
+
...baseOperationMeta,
|
|
445
|
+
type: "deleteLine" /* deleteLine */,
|
|
446
|
+
inverse: (op) => ({
|
|
447
|
+
...op,
|
|
448
|
+
type: "addLine" /* addLine */
|
|
449
|
+
}),
|
|
450
|
+
apply: (operation, ctx) => {
|
|
451
|
+
const document = ctx.get(WorkflowDocument6);
|
|
452
|
+
document.removeNode(operation.value.id);
|
|
453
|
+
},
|
|
454
|
+
getLabel: (op, ctx) => "Delete Line",
|
|
455
|
+
getDescription: (op, ctx) => {
|
|
456
|
+
const config = ctx.get(FreeHistoryConfig);
|
|
457
|
+
const { value } = op;
|
|
458
|
+
if (!value.from || !value.to) {
|
|
459
|
+
return "Delete Line";
|
|
460
|
+
}
|
|
461
|
+
const fromName = config.getNodeLabelById(value.from);
|
|
462
|
+
const toName = config.getNodeLabelById(value.to);
|
|
463
|
+
return `Delete Line from ${fromName} to ${toName}`;
|
|
464
|
+
}
|
|
465
|
+
};
|
|
466
|
+
|
|
467
|
+
// src/operation-metas/change-node-data.ts
|
|
468
|
+
import { FlowNodeFormData as FlowNodeFormData2 } from "@flowgram.ai/form-core";
|
|
469
|
+
import { WorkflowDocument as WorkflowDocument7 } from "@flowgram.ai/free-layout-core";
|
|
470
|
+
var changeNodeDataOperationMeta = {
|
|
471
|
+
...baseOperationMeta,
|
|
472
|
+
type: "changeNodeData" /* changeNodeData */,
|
|
473
|
+
inverse: (op) => ({
|
|
474
|
+
...op,
|
|
475
|
+
value: {
|
|
476
|
+
...op.value,
|
|
477
|
+
value: op.value.oldValue,
|
|
478
|
+
oldValue: op.value.value
|
|
479
|
+
}
|
|
480
|
+
}),
|
|
481
|
+
apply: (operation, ctx) => {
|
|
482
|
+
const document = ctx.get(WorkflowDocument7);
|
|
483
|
+
const node = document.getNode(operation.value.id);
|
|
484
|
+
if (!node) {
|
|
485
|
+
return;
|
|
486
|
+
}
|
|
487
|
+
const formData = node.getData(FlowNodeFormData2);
|
|
488
|
+
if (!formData) {
|
|
489
|
+
return;
|
|
490
|
+
}
|
|
491
|
+
let { path } = operation.value;
|
|
492
|
+
if (path.endsWith("/") && path !== "/") {
|
|
493
|
+
path = path.slice(0, -1);
|
|
494
|
+
}
|
|
495
|
+
if (!path.startsWith("/")) {
|
|
496
|
+
path = `/${path}`;
|
|
497
|
+
}
|
|
498
|
+
const formItem = formData.formModel.getFormItemByPath(path);
|
|
499
|
+
if (!formItem) {
|
|
500
|
+
return;
|
|
501
|
+
}
|
|
502
|
+
formItem.value = operation.value.value;
|
|
503
|
+
},
|
|
504
|
+
shouldMerge: (op, prev, element) => {
|
|
505
|
+
if (!prev) {
|
|
506
|
+
return false;
|
|
507
|
+
}
|
|
508
|
+
if (Date.now() - element.getTimestamp() < 500) {
|
|
509
|
+
if (op.type === prev.type && // 相同类型
|
|
510
|
+
op.value.id === prev.value.id && // 相同节点
|
|
511
|
+
op.value?.path === prev.value?.path) {
|
|
512
|
+
return {
|
|
513
|
+
type: op.type,
|
|
514
|
+
value: {
|
|
515
|
+
...op.value,
|
|
516
|
+
value: op.value.value,
|
|
517
|
+
oldValue: prev.value.oldValue
|
|
518
|
+
}
|
|
519
|
+
};
|
|
520
|
+
}
|
|
521
|
+
return true;
|
|
522
|
+
}
|
|
523
|
+
return false;
|
|
524
|
+
}
|
|
525
|
+
};
|
|
526
|
+
|
|
527
|
+
// src/operation-metas/add-node.ts
|
|
528
|
+
import { cloneDeep as cloneDeep3 } from "lodash";
|
|
529
|
+
import { WorkflowDocument as WorkflowDocument8 } from "@flowgram.ai/free-layout-core";
|
|
530
|
+
var addNodeOperationMeta = {
|
|
531
|
+
...baseOperationMeta,
|
|
532
|
+
type: "addNode" /* addNode */,
|
|
533
|
+
inverse: (op) => ({
|
|
534
|
+
...op,
|
|
535
|
+
type: "deleteNode" /* deleteNode */
|
|
536
|
+
}),
|
|
537
|
+
apply: async (operation, ctx) => {
|
|
538
|
+
const document = ctx.get(WorkflowDocument8);
|
|
539
|
+
await document.createWorkflowNode(
|
|
540
|
+
cloneDeep3(operation.value.node),
|
|
541
|
+
false,
|
|
542
|
+
operation.value.parentID
|
|
543
|
+
);
|
|
544
|
+
},
|
|
545
|
+
getLabel: (op, ctx) => {
|
|
546
|
+
const config = ctx.get(FreeHistoryConfig);
|
|
547
|
+
return `Create Node ${config.getNodeLabel(op.value.node)}`;
|
|
548
|
+
},
|
|
549
|
+
getDescription: (op, ctx) => {
|
|
550
|
+
const config = ctx.get(FreeHistoryConfig);
|
|
551
|
+
let desc = `Create Node ${config.getNodeLabel(op.value.node)}`;
|
|
552
|
+
if (op.value.node.meta?.position) {
|
|
553
|
+
desc += ` at ${op.value.node.meta.position.x},${op.value.node.meta.position.y}`;
|
|
554
|
+
}
|
|
555
|
+
return desc;
|
|
556
|
+
}
|
|
557
|
+
};
|
|
558
|
+
|
|
559
|
+
// src/operation-metas/add-line.ts
|
|
560
|
+
import { WorkflowLinesManager } from "@flowgram.ai/free-layout-core";
|
|
561
|
+
var addLineOperationMeta = {
|
|
562
|
+
...baseOperationMeta,
|
|
563
|
+
type: "addLine" /* addLine */,
|
|
564
|
+
inverse: (op) => ({
|
|
565
|
+
...op,
|
|
566
|
+
type: "deleteLine" /* deleteLine */
|
|
567
|
+
}),
|
|
568
|
+
apply: (operation, ctx) => {
|
|
569
|
+
const linesManager = ctx.get(WorkflowLinesManager);
|
|
570
|
+
linesManager.createLine({
|
|
571
|
+
...operation.value,
|
|
572
|
+
key: operation.value.id
|
|
573
|
+
});
|
|
574
|
+
},
|
|
575
|
+
getLabel: (op, ctx) => "Create Line",
|
|
576
|
+
getDescription: (op, ctx) => {
|
|
577
|
+
const config = ctx.get(FreeHistoryConfig);
|
|
578
|
+
const { value } = op;
|
|
579
|
+
if (!value.from || !value.to) {
|
|
580
|
+
return "Create Line";
|
|
581
|
+
}
|
|
582
|
+
const fromName = config.getNodeLabelById(value.from);
|
|
583
|
+
const toName = config.getNodeLabelById(value.to);
|
|
584
|
+
return `Create Line from ${fromName} to ${toName}`;
|
|
585
|
+
}
|
|
586
|
+
};
|
|
587
|
+
|
|
588
|
+
// src/operation-metas/index.ts
|
|
589
|
+
var operationMetas = [
|
|
590
|
+
addLineOperationMeta,
|
|
591
|
+
deleteLineOperationMeta,
|
|
592
|
+
addNodeOperationMeta,
|
|
593
|
+
deleteNodeOperationMeta,
|
|
594
|
+
changeNodeDataOperationMeta,
|
|
595
|
+
resetLayoutOperationMeta,
|
|
596
|
+
dragNodesOperationMeta
|
|
597
|
+
];
|
|
598
|
+
|
|
599
|
+
// src/free-history-registers.ts
|
|
600
|
+
var FreeHistoryRegisters = class {
|
|
601
|
+
registerOperationMeta(operationRegistry) {
|
|
602
|
+
operationMetas.forEach((operationMeta) => {
|
|
603
|
+
operationRegistry.registerOperationMeta(operationMeta);
|
|
604
|
+
});
|
|
605
|
+
}
|
|
606
|
+
};
|
|
607
|
+
FreeHistoryRegisters = __decorateClass([
|
|
608
|
+
injectable6()
|
|
609
|
+
], FreeHistoryRegisters);
|
|
610
|
+
|
|
611
|
+
// src/free-history-manager.ts
|
|
612
|
+
import { cloneDeep as cloneDeep4 } from "lodash";
|
|
613
|
+
import { injectable as injectable7, inject as inject4 } from "inversify";
|
|
614
|
+
import { FlowNodeFormData as FlowNodeFormData3 } from "@flowgram.ai/form-core";
|
|
615
|
+
import { PositionData } from "@flowgram.ai/core";
|
|
616
|
+
import {
|
|
617
|
+
WorkflowDocument as WorkflowDocument9,
|
|
618
|
+
WorkflowResetLayoutService as WorkflowResetLayoutService2,
|
|
619
|
+
WorkflowDragService
|
|
620
|
+
} from "@flowgram.ai/free-layout-core";
|
|
621
|
+
import { DisposableCollection as DisposableCollection2 } from "@flowgram.ai/utils";
|
|
622
|
+
import { HistoryService as HistoryService4 } from "@flowgram.ai/history";
|
|
623
|
+
var FreeHistoryManager = class {
|
|
624
|
+
constructor() {
|
|
625
|
+
this._toDispose = new DisposableCollection2();
|
|
626
|
+
}
|
|
627
|
+
onInit(ctx, opts) {
|
|
628
|
+
const document = ctx.get(WorkflowDocument9);
|
|
629
|
+
const historyService = ctx.get(HistoryService4);
|
|
630
|
+
const dragService = ctx.get(WorkflowDragService);
|
|
631
|
+
const resetLayoutService = ctx.get(WorkflowResetLayoutService2);
|
|
632
|
+
if (opts?.limit) {
|
|
633
|
+
historyService.limit(opts.limit);
|
|
634
|
+
}
|
|
635
|
+
historyService.context.source = ctx;
|
|
636
|
+
this._toDispose.pushAll([
|
|
637
|
+
dragService.onNodesDrag(async (event) => {
|
|
638
|
+
if (event.type !== "onDragEnd") {
|
|
639
|
+
return;
|
|
640
|
+
}
|
|
641
|
+
this._dragNodesHandler.handle(event);
|
|
642
|
+
}),
|
|
643
|
+
document.onNodeCreate(({ node, data }) => {
|
|
644
|
+
const positionData = node.getData(PositionData);
|
|
645
|
+
if (positionData) {
|
|
646
|
+
this._entityManager.addEntityData(positionData);
|
|
647
|
+
}
|
|
648
|
+
const formData = node.getData(FlowNodeFormData3);
|
|
649
|
+
if (formData) {
|
|
650
|
+
this._entityManager.setValue(formData, cloneDeep4(data.data));
|
|
651
|
+
this._toDispose.push(
|
|
652
|
+
formData.onDetailChange((event) => {
|
|
653
|
+
this._changeNodeDataHandler.handle({
|
|
654
|
+
...event,
|
|
655
|
+
node
|
|
656
|
+
});
|
|
657
|
+
})
|
|
658
|
+
);
|
|
659
|
+
}
|
|
660
|
+
}),
|
|
661
|
+
document.onContentChange(async (event) => {
|
|
662
|
+
await this._changeContentHandler.handle(event, ctx);
|
|
663
|
+
}),
|
|
664
|
+
document.onReload((_event) => {
|
|
665
|
+
historyService.clear();
|
|
666
|
+
}),
|
|
667
|
+
resetLayoutService.onResetLayout((event) => {
|
|
668
|
+
historyService.pushOperation(
|
|
669
|
+
{
|
|
670
|
+
type: "resetLayout" /* resetLayout */,
|
|
671
|
+
value: {
|
|
672
|
+
ids: event.nodeIds,
|
|
673
|
+
value: event.positionMap,
|
|
674
|
+
oldValue: event.oldPositionMap
|
|
675
|
+
}
|
|
676
|
+
},
|
|
677
|
+
{ noApply: true }
|
|
678
|
+
);
|
|
679
|
+
})
|
|
680
|
+
]);
|
|
681
|
+
}
|
|
682
|
+
dispose() {
|
|
683
|
+
this._entityManager.dispose();
|
|
684
|
+
this._toDispose.dispose();
|
|
685
|
+
}
|
|
686
|
+
};
|
|
687
|
+
__decorateClass([
|
|
688
|
+
inject4(DragNodesHandler)
|
|
689
|
+
], FreeHistoryManager.prototype, "_dragNodesHandler", 2);
|
|
690
|
+
__decorateClass([
|
|
691
|
+
inject4(ChangeNodeDataHandler)
|
|
692
|
+
], FreeHistoryManager.prototype, "_changeNodeDataHandler", 2);
|
|
693
|
+
__decorateClass([
|
|
694
|
+
inject4(ChangeContentHandler)
|
|
695
|
+
], FreeHistoryManager.prototype, "_changeContentHandler", 2);
|
|
696
|
+
__decorateClass([
|
|
697
|
+
inject4(HistoryEntityManager)
|
|
698
|
+
], FreeHistoryManager.prototype, "_entityManager", 2);
|
|
699
|
+
FreeHistoryManager = __decorateClass([
|
|
700
|
+
injectable7()
|
|
701
|
+
], FreeHistoryManager);
|
|
702
|
+
|
|
703
|
+
// src/create-free-history-plugin.ts
|
|
704
|
+
var createFreeHistoryPlugin = definePluginCreator({
|
|
705
|
+
onBind: ({ bind }) => {
|
|
706
|
+
bindContributions(bind, FreeHistoryRegisters, [OperationContribution]);
|
|
707
|
+
bind(FreeHistoryConfig).toSelf().inSingletonScope();
|
|
708
|
+
bind(FreeHistoryManager).toSelf().inSingletonScope();
|
|
709
|
+
bind(HistoryEntityManager).toSelf().inSingletonScope();
|
|
710
|
+
bind(DragNodesHandler).toSelf().inSingletonScope();
|
|
711
|
+
bind(ChangeNodeDataHandler).toSelf().inSingletonScope();
|
|
712
|
+
bind(ChangeContentHandler).toSelf().inSingletonScope();
|
|
713
|
+
},
|
|
714
|
+
onInit(ctx, opts) {
|
|
715
|
+
ctx.get(FreeHistoryConfig).init(ctx, opts);
|
|
716
|
+
if (!opts.enable) {
|
|
717
|
+
return;
|
|
718
|
+
}
|
|
719
|
+
ctx.get(FreeHistoryManager).onInit(ctx, opts);
|
|
720
|
+
},
|
|
721
|
+
onDispose(ctx) {
|
|
722
|
+
ctx.get(HistoryEntityManager).dispose();
|
|
723
|
+
},
|
|
724
|
+
containerModules: [HistoryContainerModule]
|
|
725
|
+
});
|
|
726
|
+
|
|
727
|
+
// src/index.ts
|
|
728
|
+
export * from "@flowgram.ai/history";
|
|
729
|
+
|
|
730
|
+
// src/hooks/use-undo-redo.tsx
|
|
731
|
+
import { useEffect, useState } from "react";
|
|
732
|
+
import { useService } from "@flowgram.ai/core";
|
|
733
|
+
import { HistoryService as HistoryService5 } from "@flowgram.ai/history";
|
|
734
|
+
function useUndoRedo() {
|
|
735
|
+
const historyService = useService(HistoryService5);
|
|
736
|
+
const [canUndo, setCanUndo] = useState(false);
|
|
737
|
+
const [canRedo, setCanRedo] = useState(false);
|
|
738
|
+
useEffect(() => {
|
|
739
|
+
const toDispose = historyService.undoRedoService.onChange(() => {
|
|
740
|
+
setCanUndo(historyService.canUndo());
|
|
741
|
+
setCanRedo(historyService.canRedo());
|
|
742
|
+
});
|
|
743
|
+
return () => {
|
|
744
|
+
toDispose.dispose();
|
|
745
|
+
};
|
|
746
|
+
}, []);
|
|
747
|
+
return {
|
|
748
|
+
canUndo,
|
|
749
|
+
canRedo,
|
|
750
|
+
undo: () => historyService.undo(),
|
|
751
|
+
redo: () => historyService.redo()
|
|
752
|
+
};
|
|
753
|
+
}
|
|
754
|
+
export {
|
|
755
|
+
FreeHistoryConfig,
|
|
756
|
+
FreeHistoryRegisters,
|
|
757
|
+
FreeOperationType,
|
|
758
|
+
createFreeHistoryPlugin,
|
|
759
|
+
useUndoRedo
|
|
760
|
+
};
|
|
761
|
+
//# sourceMappingURL=index.js.map
|