@flowgram-vue/history-node-plugin 0.2.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/LICENSE +22 -0
- package/dist/index.cjs +127 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.js +125 -0
- package/dist/index.js.map +1 -0
- package/package.json +61 -0
- package/src/create-history-node-plugin.ts +35 -0
- package/src/env.d.ts +10 -0
- package/src/history-node-registers.ts +21 -0
- package/src/index.ts +6 -0
- package/src/operation-metas/change-form-values.ts +44 -0
- package/src/operation-metas/index.ts +10 -0
- package/src/types.ts +15 -0
- package/src/utils/index.ts +95 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
|
|
4
|
+
Copyright (c) 2026 Crayon
|
|
5
|
+
|
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
8
|
+
in the Software without restriction, including without limitation the rights
|
|
9
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
11
|
+
furnished to do so, subject to the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be included in all
|
|
14
|
+
copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
22
|
+
SOFTWARE.
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var document = require('@flowgram-vue/document');
|
|
4
|
+
var core = require('@flowgram-vue/core');
|
|
5
|
+
var history = require('@flowgram-vue/history');
|
|
6
|
+
var lodashEs = require('lodash-es');
|
|
7
|
+
var node = require('@flowgram-vue/node');
|
|
8
|
+
var formCore = require('@flowgram-vue/form-core');
|
|
9
|
+
var inversify = require('inversify');
|
|
10
|
+
|
|
11
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
12
|
+
var __decorateClass = (decorators, target, key, kind) => {
|
|
13
|
+
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
|
|
14
|
+
for (var i = decorators.length - 1, decorator; i >= 0; i--)
|
|
15
|
+
if (decorator = decorators[i])
|
|
16
|
+
result = (decorator(result)) || result;
|
|
17
|
+
return result;
|
|
18
|
+
};
|
|
19
|
+
function getFormModelV2(node$1) {
|
|
20
|
+
if (!node$1) {
|
|
21
|
+
return void 0;
|
|
22
|
+
}
|
|
23
|
+
const formModel = node$1?.getData(formCore.FlowNodeFormData)?.getFormModel();
|
|
24
|
+
if (!formModel || !node.isFormModelV2(formModel)) {
|
|
25
|
+
return void 0;
|
|
26
|
+
}
|
|
27
|
+
return formModel;
|
|
28
|
+
}
|
|
29
|
+
function shouldChangeFormValuesMerge(op, prev, element) {
|
|
30
|
+
if (!prev) {
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
if (Date.now() - element.getTimestamp() < 500) {
|
|
34
|
+
if (op.type === prev.type && // 相同类型
|
|
35
|
+
op.value?.id === prev.value?.id && // 相同节点
|
|
36
|
+
op.value?.path === prev.value?.path) {
|
|
37
|
+
return {
|
|
38
|
+
type: op.type,
|
|
39
|
+
value: {
|
|
40
|
+
...op.value,
|
|
41
|
+
value: op.value?.value,
|
|
42
|
+
oldValue: prev.value?.oldValue
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
return true;
|
|
47
|
+
}
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
function attachFormValuesChange(formModel, node, historyService) {
|
|
51
|
+
formModel.onFormValuesChange((event) => {
|
|
52
|
+
historyService.pushOperation(
|
|
53
|
+
{
|
|
54
|
+
type: "changeFormValues" /* changeFormValues */,
|
|
55
|
+
value: {
|
|
56
|
+
id: node.id,
|
|
57
|
+
path: event.name,
|
|
58
|
+
value: event.name ? lodashEs.get(event.values, event.name) : event.values,
|
|
59
|
+
oldValue: event.name ? lodashEs.get(event.prevValues, event.name) : event.prevValues
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
{ noApply: true }
|
|
63
|
+
);
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
var changeFormValueOperationMeta = {
|
|
67
|
+
type: "changeFormValues" /* changeFormValues */,
|
|
68
|
+
inverse: (op) => ({
|
|
69
|
+
...op,
|
|
70
|
+
value: {
|
|
71
|
+
...op.value,
|
|
72
|
+
value: op.value.oldValue,
|
|
73
|
+
oldValue: op.value.value
|
|
74
|
+
}
|
|
75
|
+
}),
|
|
76
|
+
apply: ({ value: { value, path, id } }, ctx) => {
|
|
77
|
+
const document$1 = ctx.get(document.FlowDocument);
|
|
78
|
+
const formModel = getFormModelV2(document$1.getNode(id));
|
|
79
|
+
if (!formModel) {
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
if (!path) {
|
|
83
|
+
formModel.updateFormValues(value);
|
|
84
|
+
} else {
|
|
85
|
+
formModel.setValueIn(path, value);
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
shouldMerge: shouldChangeFormValuesMerge
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
// src/operation-metas/index.ts
|
|
92
|
+
var operationMetas = [changeFormValueOperationMeta];
|
|
93
|
+
|
|
94
|
+
// src/history-node-registers.ts
|
|
95
|
+
var HistoryNodeRegisters = class {
|
|
96
|
+
registerOperationMeta(operationRegistry) {
|
|
97
|
+
operationMetas.forEach((operationMeta) => {
|
|
98
|
+
operationRegistry.registerOperationMeta(operationMeta);
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
HistoryNodeRegisters = __decorateClass([
|
|
103
|
+
inversify.injectable()
|
|
104
|
+
], HistoryNodeRegisters);
|
|
105
|
+
|
|
106
|
+
// src/create-history-node-plugin.ts
|
|
107
|
+
var createHistoryNodePlugin = core.definePluginCreator({
|
|
108
|
+
onBind: ({ bind }) => {
|
|
109
|
+
core.bindContributions(bind, HistoryNodeRegisters, [history.OperationContribution]);
|
|
110
|
+
},
|
|
111
|
+
onInit: (ctx, _opts) => {
|
|
112
|
+
const document$1 = ctx.get(document.FlowDocument);
|
|
113
|
+
const historyService = ctx.get(history.HistoryService);
|
|
114
|
+
document$1.onNodeCreate(({ node }) => {
|
|
115
|
+
const formModel = getFormModelV2(node);
|
|
116
|
+
if (!formModel) {
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
attachFormValuesChange(formModel, node, historyService);
|
|
120
|
+
});
|
|
121
|
+
},
|
|
122
|
+
containerModules: [history.HistoryContainerModule]
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
exports.createHistoryNodePlugin = createHistoryNodePlugin;
|
|
126
|
+
//# sourceMappingURL=index.cjs.map
|
|
127
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/utils/index.ts","../src/operation-metas/change-form-values.ts","../src/operation-metas/index.ts","../src/history-node-registers.ts","../src/create-history-node-plugin.ts"],"names":["node","FlowNodeFormData","isFormModelV2","get","document","FlowDocument","injectable","definePluginCreator","bindContributions","OperationContribution","HistoryService","HistoryContainerModule"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { get } from 'lodash-es';\nimport { FormModelV2, isFormModelV2 } from '@flowgram-vue/node';\nimport { HistoryService, Operation } from '@flowgram-vue/history';\nimport { StackOperation } from '@flowgram-vue/history';\nimport { FlowNodeFormData } from '@flowgram-vue/form-core';\nimport { FlowNodeEntity } from '@flowgram-vue/document';\n\nimport { ChangeFormValuesOperationValue, NodeOperationType } from '../types';\n\n/**\n * 获取v2版本的formModel\n * @param node 节点\n * @returns\n */\nexport function getFormModelV2(node: FlowNodeEntity | undefined): FormModelV2 | undefined {\n if (!node) {\n return undefined;\n }\n\n const formModel = node?.getData(FlowNodeFormData)?.getFormModel<FormModelV2>();\n\n if (!formModel || !isFormModelV2(formModel)) {\n return undefined;\n }\n\n return formModel;\n}\n\n/**\n * 表单合并策略\n * @param op 操作\n * @param prev 上一个操作\n * @param element 操作栈元素\n * @returns\n */\nexport function shouldChangeFormValuesMerge(\n op: Operation<ChangeFormValuesOperationValue | undefined>,\n prev: Operation<ChangeFormValuesOperationValue | undefined>,\n element: StackOperation\n) {\n if (!prev) {\n return false;\n }\n\n if (Date.now() - element.getTimestamp() < 500) {\n if (\n op.type === prev.type && // 相同类型\n op.value?.id === prev.value?.id && // 相同节点\n op.value?.path === prev.value?.path // 相同路径\n ) {\n return {\n type: op.type,\n value: {\n ...op.value,\n value: op.value?.value,\n oldValue: prev.value?.oldValue,\n },\n };\n }\n return true;\n }\n return false;\n}\n\n/**\n * 监听表单值变化\n * @param formModel 表单模型\n * @param node 节点\n * @param historyService 历史服务\n */\nexport function attachFormValuesChange(\n formModel: FormModelV2,\n node: FlowNodeEntity,\n historyService: HistoryService\n) {\n formModel.onFormValuesChange((event) => {\n historyService.pushOperation(\n {\n type: NodeOperationType.changeFormValues,\n value: {\n id: node.id,\n path: event.name,\n value: event.name ? get(event.values, event.name) : event.values,\n oldValue: event.name ? get(event.prevValues, event.name) : event.prevValues,\n },\n },\n { noApply: true }\n );\n });\n}\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { type OperationMeta } from '@flowgram-vue/history';\nimport { FlowDocument } from '@flowgram-vue/document';\nimport { type PluginContext } from '@flowgram-vue/core';\n\nimport { getFormModelV2, shouldChangeFormValuesMerge } from '../utils';\nimport { ChangeFormValuesOperationValue, NodeOperationType } from '../types';\n\n/**\n * 表单修改操作\n */\nexport const changeFormValueOperationMeta: OperationMeta<\n ChangeFormValuesOperationValue,\n PluginContext,\n void\n> = {\n type: NodeOperationType.changeFormValues,\n inverse: (op) => ({\n ...op,\n value: {\n ...op.value,\n value: op.value.oldValue,\n oldValue: op.value.value,\n },\n }),\n apply: ({ value: { value, path, id } }, ctx: PluginContext) => {\n const document = ctx.get<FlowDocument>(FlowDocument);\n const formModel = getFormModelV2(document.getNode(id));\n\n if (!formModel) {\n return;\n }\n if (!path) {\n formModel.updateFormValues(value);\n } else {\n formModel.setValueIn(path, value);\n }\n },\n shouldMerge: shouldChangeFormValuesMerge as OperationMeta['shouldMerge'],\n};\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { OperationMeta } from '@flowgram-vue/history';\n\nimport { changeFormValueOperationMeta } from './change-form-values';\n\nexport const operationMetas: OperationMeta[] = [changeFormValueOperationMeta];\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { injectable } from 'inversify';\nimport { type OperationContribution, type OperationRegistry } from '@flowgram-vue/history';\n\nimport { operationMetas } from './operation-metas';\n\n/**\n * 表单历史操作\n */\n@injectable()\nexport class HistoryNodeRegisters implements OperationContribution {\n registerOperationMeta(operationRegistry: OperationRegistry): void {\n operationMetas.forEach(operationMeta => {\n operationRegistry.registerOperationMeta(operationMeta);\n });\n }\n}\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { FlowDocument } from '@flowgram-vue/document';\nimport { bindContributions, definePluginCreator } from '@flowgram-vue/core';\nimport { HistoryContainerModule, HistoryService, OperationContribution } from '@flowgram-vue/history';\n\nimport { attachFormValuesChange, getFormModelV2 } from './utils';\nimport { HistoryNodeRegisters } from './history-node-registers';\n\n/**\n * 表单历史插件\n */\nexport const createHistoryNodePlugin = definePluginCreator({\n onBind: ({ bind }) => {\n bindContributions(bind, HistoryNodeRegisters, [OperationContribution]);\n },\n onInit: (ctx, _opts) => {\n const document = ctx.get<FlowDocument>(FlowDocument);\n const historyService = ctx.get<HistoryService>(HistoryService);\n\n document.onNodeCreate(({ node }) => {\n const formModel = getFormModelV2(node);\n\n if (!formModel) {\n return;\n }\n\n attachFormValuesChange(formModel, node, historyService);\n });\n },\n containerModules: [HistoryContainerModule],\n});\n"]}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import * as _flowgram_vue_core from '@flowgram-vue/core';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
|
|
5
|
+
* SPDX-License-Identifier: MIT
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* 表单历史插件
|
|
9
|
+
*/
|
|
10
|
+
declare const createHistoryNodePlugin: _flowgram_vue_core.PluginCreator<unknown>;
|
|
11
|
+
|
|
12
|
+
export { createHistoryNodePlugin };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { FlowDocument } from '@flowgram-vue/document';
|
|
2
|
+
import { definePluginCreator, bindContributions } from '@flowgram-vue/core';
|
|
3
|
+
import { HistoryContainerModule, HistoryService, OperationContribution } from '@flowgram-vue/history';
|
|
4
|
+
import { get } from 'lodash-es';
|
|
5
|
+
import { isFormModelV2 } from '@flowgram-vue/node';
|
|
6
|
+
import { FlowNodeFormData } from '@flowgram-vue/form-core';
|
|
7
|
+
import { injectable } from 'inversify';
|
|
8
|
+
|
|
9
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
10
|
+
var __decorateClass = (decorators, target, key, kind) => {
|
|
11
|
+
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
|
|
12
|
+
for (var i = decorators.length - 1, decorator; i >= 0; i--)
|
|
13
|
+
if (decorator = decorators[i])
|
|
14
|
+
result = (decorator(result)) || result;
|
|
15
|
+
return result;
|
|
16
|
+
};
|
|
17
|
+
function getFormModelV2(node) {
|
|
18
|
+
if (!node) {
|
|
19
|
+
return void 0;
|
|
20
|
+
}
|
|
21
|
+
const formModel = node?.getData(FlowNodeFormData)?.getFormModel();
|
|
22
|
+
if (!formModel || !isFormModelV2(formModel)) {
|
|
23
|
+
return void 0;
|
|
24
|
+
}
|
|
25
|
+
return formModel;
|
|
26
|
+
}
|
|
27
|
+
function shouldChangeFormValuesMerge(op, prev, element) {
|
|
28
|
+
if (!prev) {
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
if (Date.now() - element.getTimestamp() < 500) {
|
|
32
|
+
if (op.type === prev.type && // 相同类型
|
|
33
|
+
op.value?.id === prev.value?.id && // 相同节点
|
|
34
|
+
op.value?.path === prev.value?.path) {
|
|
35
|
+
return {
|
|
36
|
+
type: op.type,
|
|
37
|
+
value: {
|
|
38
|
+
...op.value,
|
|
39
|
+
value: op.value?.value,
|
|
40
|
+
oldValue: prev.value?.oldValue
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
return true;
|
|
45
|
+
}
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
function attachFormValuesChange(formModel, node, historyService) {
|
|
49
|
+
formModel.onFormValuesChange((event) => {
|
|
50
|
+
historyService.pushOperation(
|
|
51
|
+
{
|
|
52
|
+
type: "changeFormValues" /* changeFormValues */,
|
|
53
|
+
value: {
|
|
54
|
+
id: node.id,
|
|
55
|
+
path: event.name,
|
|
56
|
+
value: event.name ? get(event.values, event.name) : event.values,
|
|
57
|
+
oldValue: event.name ? get(event.prevValues, event.name) : event.prevValues
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
{ noApply: true }
|
|
61
|
+
);
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
var changeFormValueOperationMeta = {
|
|
65
|
+
type: "changeFormValues" /* changeFormValues */,
|
|
66
|
+
inverse: (op) => ({
|
|
67
|
+
...op,
|
|
68
|
+
value: {
|
|
69
|
+
...op.value,
|
|
70
|
+
value: op.value.oldValue,
|
|
71
|
+
oldValue: op.value.value
|
|
72
|
+
}
|
|
73
|
+
}),
|
|
74
|
+
apply: ({ value: { value, path, id } }, ctx) => {
|
|
75
|
+
const document = ctx.get(FlowDocument);
|
|
76
|
+
const formModel = getFormModelV2(document.getNode(id));
|
|
77
|
+
if (!formModel) {
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
if (!path) {
|
|
81
|
+
formModel.updateFormValues(value);
|
|
82
|
+
} else {
|
|
83
|
+
formModel.setValueIn(path, value);
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
shouldMerge: shouldChangeFormValuesMerge
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
// src/operation-metas/index.ts
|
|
90
|
+
var operationMetas = [changeFormValueOperationMeta];
|
|
91
|
+
|
|
92
|
+
// src/history-node-registers.ts
|
|
93
|
+
var HistoryNodeRegisters = class {
|
|
94
|
+
registerOperationMeta(operationRegistry) {
|
|
95
|
+
operationMetas.forEach((operationMeta) => {
|
|
96
|
+
operationRegistry.registerOperationMeta(operationMeta);
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
HistoryNodeRegisters = __decorateClass([
|
|
101
|
+
injectable()
|
|
102
|
+
], HistoryNodeRegisters);
|
|
103
|
+
|
|
104
|
+
// src/create-history-node-plugin.ts
|
|
105
|
+
var createHistoryNodePlugin = definePluginCreator({
|
|
106
|
+
onBind: ({ bind }) => {
|
|
107
|
+
bindContributions(bind, HistoryNodeRegisters, [OperationContribution]);
|
|
108
|
+
},
|
|
109
|
+
onInit: (ctx, _opts) => {
|
|
110
|
+
const document = ctx.get(FlowDocument);
|
|
111
|
+
const historyService = ctx.get(HistoryService);
|
|
112
|
+
document.onNodeCreate(({ node }) => {
|
|
113
|
+
const formModel = getFormModelV2(node);
|
|
114
|
+
if (!formModel) {
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
attachFormValuesChange(formModel, node, historyService);
|
|
118
|
+
});
|
|
119
|
+
},
|
|
120
|
+
containerModules: [HistoryContainerModule]
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
export { createHistoryNodePlugin };
|
|
124
|
+
//# sourceMappingURL=index.js.map
|
|
125
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/utils/index.ts","../src/operation-metas/change-form-values.ts","../src/operation-metas/index.ts","../src/history-node-registers.ts","../src/create-history-node-plugin.ts"],"names":["FlowDocument"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { get } from 'lodash-es';\nimport { FormModelV2, isFormModelV2 } from '@flowgram-vue/node';\nimport { HistoryService, Operation } from '@flowgram-vue/history';\nimport { StackOperation } from '@flowgram-vue/history';\nimport { FlowNodeFormData } from '@flowgram-vue/form-core';\nimport { FlowNodeEntity } from '@flowgram-vue/document';\n\nimport { ChangeFormValuesOperationValue, NodeOperationType } from '../types';\n\n/**\n * 获取v2版本的formModel\n * @param node 节点\n * @returns\n */\nexport function getFormModelV2(node: FlowNodeEntity | undefined): FormModelV2 | undefined {\n if (!node) {\n return undefined;\n }\n\n const formModel = node?.getData(FlowNodeFormData)?.getFormModel<FormModelV2>();\n\n if (!formModel || !isFormModelV2(formModel)) {\n return undefined;\n }\n\n return formModel;\n}\n\n/**\n * 表单合并策略\n * @param op 操作\n * @param prev 上一个操作\n * @param element 操作栈元素\n * @returns\n */\nexport function shouldChangeFormValuesMerge(\n op: Operation<ChangeFormValuesOperationValue | undefined>,\n prev: Operation<ChangeFormValuesOperationValue | undefined>,\n element: StackOperation\n) {\n if (!prev) {\n return false;\n }\n\n if (Date.now() - element.getTimestamp() < 500) {\n if (\n op.type === prev.type && // 相同类型\n op.value?.id === prev.value?.id && // 相同节点\n op.value?.path === prev.value?.path // 相同路径\n ) {\n return {\n type: op.type,\n value: {\n ...op.value,\n value: op.value?.value,\n oldValue: prev.value?.oldValue,\n },\n };\n }\n return true;\n }\n return false;\n}\n\n/**\n * 监听表单值变化\n * @param formModel 表单模型\n * @param node 节点\n * @param historyService 历史服务\n */\nexport function attachFormValuesChange(\n formModel: FormModelV2,\n node: FlowNodeEntity,\n historyService: HistoryService\n) {\n formModel.onFormValuesChange((event) => {\n historyService.pushOperation(\n {\n type: NodeOperationType.changeFormValues,\n value: {\n id: node.id,\n path: event.name,\n value: event.name ? get(event.values, event.name) : event.values,\n oldValue: event.name ? get(event.prevValues, event.name) : event.prevValues,\n },\n },\n { noApply: true }\n );\n });\n}\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { type OperationMeta } from '@flowgram-vue/history';\nimport { FlowDocument } from '@flowgram-vue/document';\nimport { type PluginContext } from '@flowgram-vue/core';\n\nimport { getFormModelV2, shouldChangeFormValuesMerge } from '../utils';\nimport { ChangeFormValuesOperationValue, NodeOperationType } from '../types';\n\n/**\n * 表单修改操作\n */\nexport const changeFormValueOperationMeta: OperationMeta<\n ChangeFormValuesOperationValue,\n PluginContext,\n void\n> = {\n type: NodeOperationType.changeFormValues,\n inverse: (op) => ({\n ...op,\n value: {\n ...op.value,\n value: op.value.oldValue,\n oldValue: op.value.value,\n },\n }),\n apply: ({ value: { value, path, id } }, ctx: PluginContext) => {\n const document = ctx.get<FlowDocument>(FlowDocument);\n const formModel = getFormModelV2(document.getNode(id));\n\n if (!formModel) {\n return;\n }\n if (!path) {\n formModel.updateFormValues(value);\n } else {\n formModel.setValueIn(path, value);\n }\n },\n shouldMerge: shouldChangeFormValuesMerge as OperationMeta['shouldMerge'],\n};\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { OperationMeta } from '@flowgram-vue/history';\n\nimport { changeFormValueOperationMeta } from './change-form-values';\n\nexport const operationMetas: OperationMeta[] = [changeFormValueOperationMeta];\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { injectable } from 'inversify';\nimport { type OperationContribution, type OperationRegistry } from '@flowgram-vue/history';\n\nimport { operationMetas } from './operation-metas';\n\n/**\n * 表单历史操作\n */\n@injectable()\nexport class HistoryNodeRegisters implements OperationContribution {\n registerOperationMeta(operationRegistry: OperationRegistry): void {\n operationMetas.forEach(operationMeta => {\n operationRegistry.registerOperationMeta(operationMeta);\n });\n }\n}\n","/**\n * Copyright (c) 2025 Bytedance Ltd. and/or its affiliates\n * SPDX-License-Identifier: MIT\n */\n\nimport { FlowDocument } from '@flowgram-vue/document';\nimport { bindContributions, definePluginCreator } from '@flowgram-vue/core';\nimport { HistoryContainerModule, HistoryService, OperationContribution } from '@flowgram-vue/history';\n\nimport { attachFormValuesChange, getFormModelV2 } from './utils';\nimport { HistoryNodeRegisters } from './history-node-registers';\n\n/**\n * 表单历史插件\n */\nexport const createHistoryNodePlugin = definePluginCreator({\n onBind: ({ bind }) => {\n bindContributions(bind, HistoryNodeRegisters, [OperationContribution]);\n },\n onInit: (ctx, _opts) => {\n const document = ctx.get<FlowDocument>(FlowDocument);\n const historyService = ctx.get<HistoryService>(HistoryService);\n\n document.onNodeCreate(({ node }) => {\n const formModel = getFormModelV2(node);\n\n if (!formModel) {\n return;\n }\n\n attachFormValuesChange(formModel, node, historyService);\n });\n },\n containerModules: [HistoryContainerModule],\n});\n"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@flowgram-vue/history-node-plugin",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"homepage": "https://flowgram.ai/",
|
|
6
|
+
"repository": "https://github.com/Crayon-hua/flowgram-vue",
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js",
|
|
12
|
+
"require": "./dist/index.cjs"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"main": "./dist/index.cjs",
|
|
16
|
+
"module": "./dist/index.js",
|
|
17
|
+
"types": "./dist/index.d.ts",
|
|
18
|
+
"files": [
|
|
19
|
+
"src",
|
|
20
|
+
"dist"
|
|
21
|
+
],
|
|
22
|
+
"dependencies": {
|
|
23
|
+
"inversify": "^6.0.1",
|
|
24
|
+
"lodash-es": "^4.17.21",
|
|
25
|
+
"reflect-metadata": "~0.2.2",
|
|
26
|
+
"@flowgram-vue/document": "0.2.0",
|
|
27
|
+
"@flowgram-vue/core": "0.2.0",
|
|
28
|
+
"@flowgram-vue/history": "0.2.0",
|
|
29
|
+
"@flowgram-vue/node": "0.2.0",
|
|
30
|
+
"@flowgram-vue/form": "0.2.0",
|
|
31
|
+
"@flowgram-vue/form-core": "0.2.0"
|
|
32
|
+
},
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"@types/lodash-es": "^4.17.12",
|
|
35
|
+
"@types/node": "^20",
|
|
36
|
+
"@vitejs/plugin-vue": "^6.0.1",
|
|
37
|
+
"@vitest/coverage-v8": "^3.2.4",
|
|
38
|
+
"eslint": "^9.0.0",
|
|
39
|
+
"jsdom": "^26.1.0",
|
|
40
|
+
"typescript": "^5.8.3",
|
|
41
|
+
"vitest": "^3.2.4",
|
|
42
|
+
"vue": "^3.5.18",
|
|
43
|
+
"@flowgram-vue/eslint-config": "0.2.0",
|
|
44
|
+
"@flowgram-vue/ts-config": "0.2.0",
|
|
45
|
+
"@flowgram-vue/build-config": "0.2.0"
|
|
46
|
+
},
|
|
47
|
+
"publishConfig": {
|
|
48
|
+
"access": "public",
|
|
49
|
+
"registry": "https://registry.npmjs.org/"
|
|
50
|
+
},
|
|
51
|
+
"scripts": {
|
|
52
|
+
"build": "flowgram-build",
|
|
53
|
+
"test": "vitest run",
|
|
54
|
+
"test:cov": "vitest run --coverage",
|
|
55
|
+
"lint": "eslint .",
|
|
56
|
+
"ts-check": "tsc --noEmit",
|
|
57
|
+
"type-check": "tsc --noEmit",
|
|
58
|
+
"build:fast": "flowgram-build --fast",
|
|
59
|
+
"build:watch": "flowgram-build --watch"
|
|
60
|
+
}
|
|
61
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
|
|
3
|
+
* SPDX-License-Identifier: MIT
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { FlowDocument } from '@flowgram-vue/document';
|
|
7
|
+
import { bindContributions, definePluginCreator } from '@flowgram-vue/core';
|
|
8
|
+
import { HistoryContainerModule, HistoryService, OperationContribution } from '@flowgram-vue/history';
|
|
9
|
+
|
|
10
|
+
import { attachFormValuesChange, getFormModelV2 } from './utils';
|
|
11
|
+
import { HistoryNodeRegisters } from './history-node-registers';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* 表单历史插件
|
|
15
|
+
*/
|
|
16
|
+
export const createHistoryNodePlugin = definePluginCreator({
|
|
17
|
+
onBind: ({ bind }) => {
|
|
18
|
+
bindContributions(bind, HistoryNodeRegisters, [OperationContribution]);
|
|
19
|
+
},
|
|
20
|
+
onInit: (ctx, _opts) => {
|
|
21
|
+
const document = ctx.get<FlowDocument>(FlowDocument);
|
|
22
|
+
const historyService = ctx.get<HistoryService>(HistoryService);
|
|
23
|
+
|
|
24
|
+
document.onNodeCreate(({ node }) => {
|
|
25
|
+
const formModel = getFormModelV2(node);
|
|
26
|
+
|
|
27
|
+
if (!formModel) {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
attachFormValuesChange(formModel, node, historyService);
|
|
32
|
+
});
|
|
33
|
+
},
|
|
34
|
+
containerModules: [HistoryContainerModule],
|
|
35
|
+
});
|
package/src/env.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
|
|
3
|
+
* SPDX-License-Identifier: MIT
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
declare module '*.vue' {
|
|
7
|
+
import type { DefineComponent } from 'vue';
|
|
8
|
+
const component: DefineComponent<object, object, unknown>;
|
|
9
|
+
export default component;
|
|
10
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
|
|
3
|
+
* SPDX-License-Identifier: MIT
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { injectable } from 'inversify';
|
|
7
|
+
import { type OperationContribution, type OperationRegistry } from '@flowgram-vue/history';
|
|
8
|
+
|
|
9
|
+
import { operationMetas } from './operation-metas';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* 表单历史操作
|
|
13
|
+
*/
|
|
14
|
+
@injectable()
|
|
15
|
+
export class HistoryNodeRegisters implements OperationContribution {
|
|
16
|
+
registerOperationMeta(operationRegistry: OperationRegistry): void {
|
|
17
|
+
operationMetas.forEach(operationMeta => {
|
|
18
|
+
operationRegistry.registerOperationMeta(operationMeta);
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
|
|
3
|
+
* SPDX-License-Identifier: MIT
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { type OperationMeta } from '@flowgram-vue/history';
|
|
7
|
+
import { FlowDocument } from '@flowgram-vue/document';
|
|
8
|
+
import { type PluginContext } from '@flowgram-vue/core';
|
|
9
|
+
|
|
10
|
+
import { getFormModelV2, shouldChangeFormValuesMerge } from '../utils';
|
|
11
|
+
import { ChangeFormValuesOperationValue, NodeOperationType } from '../types';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* 表单修改操作
|
|
15
|
+
*/
|
|
16
|
+
export const changeFormValueOperationMeta: OperationMeta<
|
|
17
|
+
ChangeFormValuesOperationValue,
|
|
18
|
+
PluginContext,
|
|
19
|
+
void
|
|
20
|
+
> = {
|
|
21
|
+
type: NodeOperationType.changeFormValues,
|
|
22
|
+
inverse: (op) => ({
|
|
23
|
+
...op,
|
|
24
|
+
value: {
|
|
25
|
+
...op.value,
|
|
26
|
+
value: op.value.oldValue,
|
|
27
|
+
oldValue: op.value.value,
|
|
28
|
+
},
|
|
29
|
+
}),
|
|
30
|
+
apply: ({ value: { value, path, id } }, ctx: PluginContext) => {
|
|
31
|
+
const document = ctx.get<FlowDocument>(FlowDocument);
|
|
32
|
+
const formModel = getFormModelV2(document.getNode(id));
|
|
33
|
+
|
|
34
|
+
if (!formModel) {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
if (!path) {
|
|
38
|
+
formModel.updateFormValues(value);
|
|
39
|
+
} else {
|
|
40
|
+
formModel.setValueIn(path, value);
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
shouldMerge: shouldChangeFormValuesMerge as OperationMeta['shouldMerge'],
|
|
44
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
|
|
3
|
+
* SPDX-License-Identifier: MIT
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { OperationMeta } from '@flowgram-vue/history';
|
|
7
|
+
|
|
8
|
+
import { changeFormValueOperationMeta } from './change-form-values';
|
|
9
|
+
|
|
10
|
+
export const operationMetas: OperationMeta[] = [changeFormValueOperationMeta];
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
|
|
3
|
+
* SPDX-License-Identifier: MIT
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export enum NodeOperationType {
|
|
7
|
+
changeFormValues = 'changeFormValues',
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface ChangeFormValuesOperationValue {
|
|
11
|
+
id: string;
|
|
12
|
+
path: string;
|
|
13
|
+
value: unknown;
|
|
14
|
+
oldValue: unknown;
|
|
15
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
|
|
3
|
+
* SPDX-License-Identifier: MIT
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { get } from 'lodash-es';
|
|
7
|
+
import { FormModelV2, isFormModelV2 } from '@flowgram-vue/node';
|
|
8
|
+
import { HistoryService, Operation } from '@flowgram-vue/history';
|
|
9
|
+
import { StackOperation } from '@flowgram-vue/history';
|
|
10
|
+
import { FlowNodeFormData } from '@flowgram-vue/form-core';
|
|
11
|
+
import { FlowNodeEntity } from '@flowgram-vue/document';
|
|
12
|
+
|
|
13
|
+
import { ChangeFormValuesOperationValue, NodeOperationType } from '../types';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* 获取v2版本的formModel
|
|
17
|
+
* @param node 节点
|
|
18
|
+
* @returns
|
|
19
|
+
*/
|
|
20
|
+
export function getFormModelV2(node: FlowNodeEntity | undefined): FormModelV2 | undefined {
|
|
21
|
+
if (!node) {
|
|
22
|
+
return undefined;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const formModel = node?.getData(FlowNodeFormData)?.getFormModel<FormModelV2>();
|
|
26
|
+
|
|
27
|
+
if (!formModel || !isFormModelV2(formModel)) {
|
|
28
|
+
return undefined;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return formModel;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* 表单合并策略
|
|
36
|
+
* @param op 操作
|
|
37
|
+
* @param prev 上一个操作
|
|
38
|
+
* @param element 操作栈元素
|
|
39
|
+
* @returns
|
|
40
|
+
*/
|
|
41
|
+
export function shouldChangeFormValuesMerge(
|
|
42
|
+
op: Operation<ChangeFormValuesOperationValue | undefined>,
|
|
43
|
+
prev: Operation<ChangeFormValuesOperationValue | undefined>,
|
|
44
|
+
element: StackOperation
|
|
45
|
+
) {
|
|
46
|
+
if (!prev) {
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (Date.now() - element.getTimestamp() < 500) {
|
|
51
|
+
if (
|
|
52
|
+
op.type === prev.type && // 相同类型
|
|
53
|
+
op.value?.id === prev.value?.id && // 相同节点
|
|
54
|
+
op.value?.path === prev.value?.path // 相同路径
|
|
55
|
+
) {
|
|
56
|
+
return {
|
|
57
|
+
type: op.type,
|
|
58
|
+
value: {
|
|
59
|
+
...op.value,
|
|
60
|
+
value: op.value?.value,
|
|
61
|
+
oldValue: prev.value?.oldValue,
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* 监听表单值变化
|
|
72
|
+
* @param formModel 表单模型
|
|
73
|
+
* @param node 节点
|
|
74
|
+
* @param historyService 历史服务
|
|
75
|
+
*/
|
|
76
|
+
export function attachFormValuesChange(
|
|
77
|
+
formModel: FormModelV2,
|
|
78
|
+
node: FlowNodeEntity,
|
|
79
|
+
historyService: HistoryService
|
|
80
|
+
) {
|
|
81
|
+
formModel.onFormValuesChange((event) => {
|
|
82
|
+
historyService.pushOperation(
|
|
83
|
+
{
|
|
84
|
+
type: NodeOperationType.changeFormValues,
|
|
85
|
+
value: {
|
|
86
|
+
id: node.id,
|
|
87
|
+
path: event.name,
|
|
88
|
+
value: event.name ? get(event.values, event.name) : event.values,
|
|
89
|
+
oldValue: event.name ? get(event.prevValues, event.name) : event.prevValues,
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
{ noApply: true }
|
|
93
|
+
);
|
|
94
|
+
});
|
|
95
|
+
}
|