@tmagic/editor 1.8.0-beta.3 → 1.8.0-beta.5
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/es/components/CompareForm.vue_vue_type_script_setup_true_lang.js +15 -1
- package/dist/es/components/ToolButton.vue_vue_type_script_setup_true_lang.js +6 -6
- package/dist/es/hooks/use-code-block-edit.js +6 -3
- package/dist/es/hooks/use-data-source-edit.js +5 -2
- package/dist/es/hooks/use-stage.js +6 -3
- package/dist/es/index.js +6 -3
- package/dist/es/initService.js +1 -1
- package/dist/es/layouts/Framework.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/es/layouts/NavMenu.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/es/layouts/history-list/Bucket.vue_vue_type_script_setup_true_lang.js +19 -51
- package/dist/es/layouts/history-list/BucketTab.vue_vue_type_script_setup_true_lang.js +22 -36
- package/dist/es/layouts/history-list/GroupRow.vue_vue_type_script_setup_true_lang.js +152 -93
- package/dist/es/layouts/history-list/HistoryDiffDialog.vue_vue_type_script_setup_true_lang.js +36 -10
- package/dist/es/layouts/history-list/HistoryListPanel.vue_vue_type_script_setup_true_lang.js +334 -208
- package/dist/es/layouts/history-list/InitialRow.vue_vue_type_script_setup_true_lang.js +28 -7
- package/dist/es/layouts/history-list/PageTab.vue_vue_type_script_setup_true_lang.js +47 -57
- package/dist/es/layouts/history-list/composables.js +118 -25
- package/dist/es/layouts/page-bar/PageBar.vue_vue_type_script_setup_true_lang.js +4 -2
- package/dist/es/layouts/props-panel/PropsPanel.vue_vue_type_script_setup_true_lang.js +5 -1
- package/dist/es/layouts/sidebar/ComponentListPanel.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/es/layouts/sidebar/Sidebar.vue_vue_type_script_setup_true_lang.js +5 -1
- package/dist/es/layouts/sidebar/code-block/CodeBlockList.vue_vue_type_script_setup_true_lang.js +3 -3
- package/dist/es/layouts/sidebar/code-block/CodeBlockListPanel.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/es/layouts/sidebar/code-block/useContentMenu.js +1 -1
- package/dist/es/layouts/sidebar/data-source/DataSourceListPanel.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/es/layouts/sidebar/data-source/useContentMenu.js +1 -1
- package/dist/es/layouts/sidebar/layer/LayerMenu.vue_vue_type_script_setup_true_lang.js +5 -5
- package/dist/es/layouts/sidebar/layer/LayerNodeTool.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/es/layouts/workspace/viewer/Stage.vue_vue_type_script_setup_true_lang.js +1 -1
- package/dist/es/layouts/workspace/viewer/ViewerMenu.vue_vue_type_script_setup_true_lang.js +8 -8
- package/dist/es/services/codeBlock.js +105 -42
- package/dist/es/services/dataSource.js +85 -35
- package/dist/es/services/editor.js +317 -122
- package/dist/es/services/history.js +270 -204
- package/dist/es/services/keybinding.js +3 -3
- package/dist/es/services/ui.js +3 -0
- package/dist/es/style.css +65 -10
- package/dist/es/utils/content-menu.js +17 -9
- package/dist/es/utils/editor.js +35 -1
- package/dist/es/utils/history.js +223 -0
- package/dist/es/utils/indexed-db.js +86 -0
- package/dist/es/utils/undo-redo.js +60 -1
- package/dist/style.css +65 -10
- package/dist/tmagic-editor.umd.cjs +2047 -954
- package/package.json +7 -7
- package/src/components/CompareForm.vue +21 -1
- package/src/components/ToolButton.vue +2 -2
- package/src/hooks/use-code-block-edit.ts +4 -3
- package/src/hooks/use-data-source-edit.ts +2 -2
- package/src/hooks/use-stage.ts +3 -3
- package/src/index.ts +1 -0
- package/src/initService.ts +1 -1
- package/src/layouts/Framework.vue +1 -1
- package/src/layouts/NavMenu.vue +1 -1
- package/src/layouts/history-list/Bucket.vue +34 -67
- package/src/layouts/history-list/BucketTab.vue +46 -51
- package/src/layouts/history-list/GroupRow.vue +150 -98
- package/src/layouts/history-list/HistoryDiffDialog.vue +96 -69
- package/src/layouts/history-list/HistoryListPanel.vue +298 -111
- package/src/layouts/history-list/InitialRow.vue +25 -9
- package/src/layouts/history-list/PageTab.vue +58 -48
- package/src/layouts/history-list/composables.ts +210 -29
- package/src/layouts/page-bar/PageBar.vue +4 -2
- package/src/layouts/props-panel/PropsPanel.vue +5 -1
- package/src/layouts/sidebar/ComponentListPanel.vue +9 -5
- package/src/layouts/sidebar/Sidebar.vue +6 -1
- package/src/layouts/sidebar/code-block/CodeBlockList.vue +5 -5
- package/src/layouts/sidebar/code-block/CodeBlockListPanel.vue +1 -1
- package/src/layouts/sidebar/code-block/useContentMenu.ts +1 -1
- package/src/layouts/sidebar/data-source/DataSourceListPanel.vue +1 -1
- package/src/layouts/sidebar/data-source/useContentMenu.ts +1 -1
- package/src/layouts/sidebar/layer/LayerMenu.vue +19 -11
- package/src/layouts/sidebar/layer/LayerNodeTool.vue +7 -4
- package/src/layouts/workspace/viewer/Stage.vue +1 -1
- package/src/layouts/workspace/viewer/ViewerMenu.vue +8 -8
- package/src/services/codeBlock.ts +129 -35
- package/src/services/dataSource.ts +105 -34
- package/src/services/editor.ts +470 -157
- package/src/services/history.ts +312 -203
- package/src/services/keybinding.ts +3 -3
- package/src/services/ui.ts +7 -0
- package/src/theme/history-list-panel.scss +87 -6
- package/src/theme/page-bar.scss +0 -4
- package/src/theme/props-panel.scss +3 -3
- package/src/type.ts +221 -61
- package/src/utils/content-menu.ts +18 -9
- package/src/utils/editor.ts +41 -1
- package/src/utils/history.ts +298 -0
- package/src/utils/index.ts +2 -0
- package/src/utils/indexed-db.ts +122 -0
- package/src/utils/undo-redo.ts +88 -0
- package/types/index.d.ts +871 -308
|
@@ -36,11 +36,11 @@ var ViewerMenu_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ def
|
|
|
36
36
|
display: () => canCenter.value,
|
|
37
37
|
handler: () => {
|
|
38
38
|
if (!nodes.value) return;
|
|
39
|
-
editorService.alignCenter(nodes.value);
|
|
39
|
+
editorService.alignCenter(nodes.value, { historySource: "stage-contextmenu" });
|
|
40
40
|
}
|
|
41
41
|
},
|
|
42
42
|
useCopyMenu(),
|
|
43
|
-
usePasteMenu(menuRef),
|
|
43
|
+
usePasteMenu("stage-contextmenu", menuRef),
|
|
44
44
|
{
|
|
45
45
|
type: "divider",
|
|
46
46
|
direction: "horizontal",
|
|
@@ -55,7 +55,7 @@ var ViewerMenu_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ def
|
|
|
55
55
|
icon: markRaw(Top),
|
|
56
56
|
display: () => !isPage(node.value) && !isPageFragment(node.value) && !props.isMultiSelect,
|
|
57
57
|
handler: () => {
|
|
58
|
-
editorService.moveLayer(1);
|
|
58
|
+
editorService.moveLayer(1, { historySource: "stage-contextmenu" });
|
|
59
59
|
}
|
|
60
60
|
},
|
|
61
61
|
{
|
|
@@ -64,7 +64,7 @@ var ViewerMenu_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ def
|
|
|
64
64
|
icon: markRaw(Bottom),
|
|
65
65
|
display: () => !isPage(node.value) && !isPageFragment(node.value) && !props.isMultiSelect,
|
|
66
66
|
handler: () => {
|
|
67
|
-
editorService.moveLayer(-1);
|
|
67
|
+
editorService.moveLayer(-1, { historySource: "stage-contextmenu" });
|
|
68
68
|
}
|
|
69
69
|
},
|
|
70
70
|
{
|
|
@@ -73,7 +73,7 @@ var ViewerMenu_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ def
|
|
|
73
73
|
icon: markRaw(Top),
|
|
74
74
|
display: () => !isPage(node.value) && !isPageFragment(node.value) && !props.isMultiSelect,
|
|
75
75
|
handler: () => {
|
|
76
|
-
editorService.moveLayer(LayerOffset.TOP);
|
|
76
|
+
editorService.moveLayer(LayerOffset.TOP, { historySource: "stage-contextmenu" });
|
|
77
77
|
}
|
|
78
78
|
},
|
|
79
79
|
{
|
|
@@ -82,16 +82,16 @@ var ViewerMenu_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ def
|
|
|
82
82
|
icon: markRaw(Bottom),
|
|
83
83
|
display: () => !isPage(node.value) && !isPageFragment(node.value) && !props.isMultiSelect,
|
|
84
84
|
handler: () => {
|
|
85
|
-
editorService.moveLayer(LayerOffset.BOTTOM);
|
|
85
|
+
editorService.moveLayer(LayerOffset.BOTTOM, { historySource: "stage-contextmenu" });
|
|
86
86
|
}
|
|
87
87
|
},
|
|
88
|
-
useMoveToMenu(services),
|
|
88
|
+
useMoveToMenu(services, "stage-contextmenu"),
|
|
89
89
|
{
|
|
90
90
|
type: "divider",
|
|
91
91
|
direction: "horizontal",
|
|
92
92
|
display: () => !isPage(node.value) && !isPageFragment(node.value) && !props.isMultiSelect
|
|
93
93
|
},
|
|
94
|
-
useDeleteMenu(),
|
|
94
|
+
useDeleteMenu("stage-contextmenu"),
|
|
95
95
|
{
|
|
96
96
|
type: "divider",
|
|
97
97
|
direction: "horizontal"
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { CODE_DRAFT_STORAGE_KEY } from "../type.js";
|
|
2
2
|
import BaseService from "./BaseService.js";
|
|
3
|
-
import history_default from "./history.js";
|
|
4
3
|
import { getEditorConfig } from "../utils/config.js";
|
|
4
|
+
import { describeRevertStep } from "../utils/history.js";
|
|
5
|
+
import history_default from "./history.js";
|
|
5
6
|
import storage_default, { Protocol } from "./storage.js";
|
|
6
7
|
import { COPY_CODE_STORAGE_KEY } from "../utils/editor.js";
|
|
7
8
|
import editor_default from "./editor.js";
|
|
@@ -20,17 +21,6 @@ var canUsePluginMethods = {
|
|
|
20
21
|
],
|
|
21
22
|
sync: ["setCodeDslByIdSync"]
|
|
22
23
|
};
|
|
23
|
-
/**
|
|
24
|
-
* 「回滚」生成的新 step 简短描述。仅 service 层使用。
|
|
25
|
-
*/
|
|
26
|
-
var describeRevertCodeBlockStep = (step) => {
|
|
27
|
-
const { oldContent, newContent, changeRecords, id } = step;
|
|
28
|
-
if (oldContent === null && newContent) return `撤回新增 ${newContent.name || newContent.id || id}`;
|
|
29
|
-
if (oldContent && newContent === null) return `还原已删除的 ${oldContent.name || oldContent.id || id}`;
|
|
30
|
-
const name = newContent?.name || oldContent?.name || `${id}`;
|
|
31
|
-
const propPath = changeRecords?.[0]?.propPath;
|
|
32
|
-
return propPath ? `还原 ${name} · ${propPath}` : `还原 ${name}`;
|
|
33
|
-
};
|
|
34
24
|
var CodeBlock = class extends BaseService {
|
|
35
25
|
state = reactive({
|
|
36
26
|
codeDsl: null,
|
|
@@ -39,6 +29,16 @@ var CodeBlock = class extends BaseService {
|
|
|
39
29
|
undeletableList: [],
|
|
40
30
|
paramsColConfig: void 0
|
|
41
31
|
});
|
|
32
|
+
/**
|
|
33
|
+
* 最近一次写入历史栈的代码块历史记录 uuid(单条写入场景:新增 / 更新)。
|
|
34
|
+
* 供 setCodeDslById(Sync)AndGetHistoryId 取回,普通方法不读取它。
|
|
35
|
+
*/
|
|
36
|
+
lastPushedHistoryId = null;
|
|
37
|
+
/**
|
|
38
|
+
* deleteCodeDslByIds 一次删除多个代码块时,按写入顺序收集的历史记录 uuid 列表。
|
|
39
|
+
* 在 deleteCodeDslByIds 入口处重置,供 deleteCodeDslByIdsAndGetHistoryId 取回。
|
|
40
|
+
*/
|
|
41
|
+
lastDeletedHistoryIds = [];
|
|
42
42
|
constructor() {
|
|
43
43
|
super([...canUsePluginMethods.async.map((methodName) => ({
|
|
44
44
|
name: methodName,
|
|
@@ -86,10 +86,12 @@ var CodeBlock = class extends BaseService {
|
|
|
86
86
|
* @param options.doNotPushHistory 是否不写入历史记录(默认 false)
|
|
87
87
|
* @returns {void}
|
|
88
88
|
*/
|
|
89
|
-
async setCodeDslById(id, codeConfig, { changeRecords, doNotPushHistory = false } = {}) {
|
|
89
|
+
async setCodeDslById(id, codeConfig, { changeRecords, doNotPushHistory = false, historyDescription, historySource } = {}) {
|
|
90
90
|
this.setCodeDslByIdSync(id, codeConfig, true, {
|
|
91
91
|
changeRecords,
|
|
92
|
-
doNotPushHistory
|
|
92
|
+
doNotPushHistory,
|
|
93
|
+
historyDescription,
|
|
94
|
+
historySource
|
|
93
95
|
});
|
|
94
96
|
}
|
|
95
97
|
/**
|
|
@@ -104,7 +106,7 @@ var CodeBlock = class extends BaseService {
|
|
|
104
106
|
* @param options.historyDescription 入栈时附带的人类可读描述,用于历史面板展示
|
|
105
107
|
* @returns {void}
|
|
106
108
|
*/
|
|
107
|
-
setCodeDslByIdSync(id, codeConfig, force = true, { changeRecords, doNotPushHistory = false, historyDescription } = {}) {
|
|
109
|
+
setCodeDslByIdSync(id, codeConfig, force = true, { changeRecords, doNotPushHistory = false, historyDescription, historySource } = {}) {
|
|
108
110
|
const codeDsl = this.getCodeDsl();
|
|
109
111
|
if (!codeDsl) throw new Error("dsl中没有codeBlocks");
|
|
110
112
|
if (codeDsl[id] && !force) return;
|
|
@@ -119,12 +121,13 @@ var CodeBlock = class extends BaseService {
|
|
|
119
121
|
...codeConfigProcessed
|
|
120
122
|
};
|
|
121
123
|
const newContent = cloneDeep$1(codeDsl[id]);
|
|
122
|
-
if (!doNotPushHistory) history_default.pushCodeBlock(id, {
|
|
124
|
+
if (!doNotPushHistory) this.lastPushedHistoryId = history_default.pushCodeBlock(id, {
|
|
123
125
|
oldContent,
|
|
124
126
|
newContent,
|
|
125
127
|
changeRecords,
|
|
126
|
-
historyDescription
|
|
127
|
-
|
|
128
|
+
historyDescription,
|
|
129
|
+
source: historySource
|
|
130
|
+
})?.uuid ?? null;
|
|
128
131
|
this.emit("addOrUpdate", id, codeDsl[id]);
|
|
129
132
|
}
|
|
130
133
|
/**
|
|
@@ -204,20 +207,53 @@ var CodeBlock = class extends BaseService {
|
|
|
204
207
|
* @param options 可选配置
|
|
205
208
|
* @param options.doNotPushHistory 是否不写入历史记录(默认 false)
|
|
206
209
|
*/
|
|
207
|
-
async deleteCodeDslByIds(codeIds, { doNotPushHistory = false, historyDescription } = {}) {
|
|
210
|
+
async deleteCodeDslByIds(codeIds, { doNotPushHistory = false, historyDescription, historySource } = {}) {
|
|
208
211
|
const currentDsl = await this.getCodeDsl();
|
|
209
212
|
if (!currentDsl) return;
|
|
213
|
+
this.lastDeletedHistoryIds = [];
|
|
210
214
|
codeIds.forEach((id) => {
|
|
211
215
|
const oldContent = currentDsl[id] ? cloneDeep$1(currentDsl[id]) : null;
|
|
212
216
|
delete currentDsl[id];
|
|
213
|
-
if (oldContent && !doNotPushHistory)
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
217
|
+
if (oldContent && !doNotPushHistory) {
|
|
218
|
+
const uuid = history_default.pushCodeBlock(id, {
|
|
219
|
+
oldContent,
|
|
220
|
+
newContent: null,
|
|
221
|
+
historyDescription,
|
|
222
|
+
source: historySource
|
|
223
|
+
})?.uuid;
|
|
224
|
+
if (uuid) this.lastDeletedHistoryIds.push(uuid);
|
|
225
|
+
}
|
|
218
226
|
this.emit("remove", id);
|
|
219
227
|
});
|
|
220
228
|
}
|
|
229
|
+
/**
|
|
230
|
+
* 下列 *AndGetHistoryId 方法与对应的写入方法行为完全一致,
|
|
231
|
+
* 唯一区别是返回值为本次写入历史栈的历史记录 uuid({@link CodeBlockStepValue.uuid}),
|
|
232
|
+
* 可用于精确引用 / 定位该条历史记录(埋点、revert、跨端同步等)。
|
|
233
|
+
*
|
|
234
|
+
* 当本次操作未写入历史(doNotPushHistory 为 true、或无对应记录)时:单条写入返回 null,批量删除返回空数组。
|
|
235
|
+
*/
|
|
236
|
+
/** 等价于 {@link setCodeDslById},但返回本次写入历史记录的 uuid(未入栈时返回 null)。 */
|
|
237
|
+
async setCodeDslByIdAndGetHistoryId(id, codeConfig, options = {}) {
|
|
238
|
+
this.lastPushedHistoryId = null;
|
|
239
|
+
await this.setCodeDslById(id, codeConfig, options);
|
|
240
|
+
return this.lastPushedHistoryId;
|
|
241
|
+
}
|
|
242
|
+
/** 等价于 {@link setCodeDslByIdSync},但返回本次写入历史记录的 uuid(未入栈时返回 null)。 */
|
|
243
|
+
setCodeDslByIdSyncAndGetHistoryId(id, codeConfig, force = true, options = {}) {
|
|
244
|
+
this.lastPushedHistoryId = null;
|
|
245
|
+
this.setCodeDslByIdSync(id, codeConfig, force, options);
|
|
246
|
+
return this.lastPushedHistoryId;
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* 等价于 {@link deleteCodeDslByIds},但返回本次写入的全部历史记录 uuid(按删除顺序)。
|
|
250
|
+
* 一次删除多个代码块会产生多条历史记录,因此返回数组;未写入任何历史时返回空数组。
|
|
251
|
+
*/
|
|
252
|
+
async deleteCodeDslByIdsAndGetHistoryId(codeIds, options = {}) {
|
|
253
|
+
this.lastDeletedHistoryIds = [];
|
|
254
|
+
await this.deleteCodeDslByIds(codeIds, options);
|
|
255
|
+
return [...this.lastDeletedHistoryIds];
|
|
256
|
+
}
|
|
221
257
|
setParamsColConfig(config) {
|
|
222
258
|
this.state.paramsColConfig = config;
|
|
223
259
|
}
|
|
@@ -293,10 +329,25 @@ var CodeBlock = class extends BaseService {
|
|
|
293
329
|
async revert(id, index) {
|
|
294
330
|
const entry = history_default.getCodeBlockStepList(id)[index];
|
|
295
331
|
if (!entry?.applied) return null;
|
|
296
|
-
const
|
|
332
|
+
const { oldSchema, newSchema, changeRecords } = entry.step.diff?.[0] ?? {};
|
|
333
|
+
if (oldSchema && newSchema && !changeRecords?.length) return null;
|
|
334
|
+
const description = `回滚 #${index + 1}: ${describeRevertStep(entry.step.id, entry.step.diff?.[0], (s) => s.name)}`;
|
|
297
335
|
return await this.applyRevertStep(entry.step, description);
|
|
298
336
|
}
|
|
299
337
|
/**
|
|
338
|
+
* 通过历史记录 uuid 回滚某条代码块历史步骤,语义同 {@link revert},
|
|
339
|
+
* 仅无需调用方再传 codeBlockId 与 index:内部会按 uuid({@link CodeBlockStepValue.uuid})
|
|
340
|
+
* 在全部代码块栈中定位对应步骤后再回滚。
|
|
341
|
+
*
|
|
342
|
+
* @param uuid 目标历史记录的 uuid,通常由 {@link setCodeDslByIdAndGetHistoryId} 等方法返回
|
|
343
|
+
* @returns 反向后产生的新 step;找不到对应 uuid / 未应用时返回 null
|
|
344
|
+
*/
|
|
345
|
+
async revertById(uuid) {
|
|
346
|
+
const location = history_default.findCodeBlockStepLocationByUuid(uuid);
|
|
347
|
+
if (!location) return null;
|
|
348
|
+
return await this.revert(location.id, location.index);
|
|
349
|
+
}
|
|
350
|
+
/**
|
|
300
351
|
* 生成代码块唯一id
|
|
301
352
|
* @returns {Id} 代码块唯一id
|
|
302
353
|
*/
|
|
@@ -361,16 +412,23 @@ var CodeBlock = class extends BaseService {
|
|
|
361
412
|
* 差异仅在于通过公开的 setCodeDslByIdSync / deleteCodeDslByIds 触发 push。
|
|
362
413
|
*/
|
|
363
414
|
async applyRevertStep(step, historyDescription) {
|
|
364
|
-
const { id
|
|
365
|
-
|
|
366
|
-
|
|
415
|
+
const { id } = step;
|
|
416
|
+
const { oldSchema, newSchema, changeRecords } = step.diff?.[0] ?? {};
|
|
417
|
+
if (!oldSchema && newSchema) {
|
|
418
|
+
await this.deleteCodeDslByIds([id], {
|
|
419
|
+
historyDescription,
|
|
420
|
+
historySource: "rollback"
|
|
421
|
+
});
|
|
367
422
|
return history_default.getCodeBlockStepList(id).slice(-1)[0]?.step ?? null;
|
|
368
423
|
}
|
|
369
|
-
if (
|
|
370
|
-
this.setCodeDslByIdSync(id, cloneDeep$1(
|
|
424
|
+
if (oldSchema && !newSchema) {
|
|
425
|
+
this.setCodeDslByIdSync(id, cloneDeep$1(oldSchema), true, {
|
|
426
|
+
historyDescription,
|
|
427
|
+
historySource: "rollback"
|
|
428
|
+
});
|
|
371
429
|
return history_default.getCodeBlockStepList(id).slice(-1)[0]?.step ?? null;
|
|
372
430
|
}
|
|
373
|
-
if (!
|
|
431
|
+
if (!oldSchema || !newSchema) return null;
|
|
374
432
|
if (changeRecords?.length) {
|
|
375
433
|
const current = this.getCodeContentById(id);
|
|
376
434
|
if (!current) return null;
|
|
@@ -381,16 +439,20 @@ var CodeBlock = class extends BaseService {
|
|
|
381
439
|
fallbackToFullReplace = true;
|
|
382
440
|
break;
|
|
383
441
|
}
|
|
384
|
-
const value = cloneDeep$1(getValueByKeyPath(record.propPath,
|
|
442
|
+
const value = cloneDeep$1(getValueByKeyPath(record.propPath, oldSchema));
|
|
385
443
|
setValueByKeyPath(record.propPath, value, patched);
|
|
386
444
|
}
|
|
387
|
-
this.setCodeDslByIdSync(id, fallbackToFullReplace ? cloneDeep$1(
|
|
445
|
+
this.setCodeDslByIdSync(id, fallbackToFullReplace ? cloneDeep$1(oldSchema) : patched, true, {
|
|
388
446
|
changeRecords,
|
|
389
|
-
historyDescription
|
|
447
|
+
historyDescription,
|
|
448
|
+
historySource: "rollback"
|
|
390
449
|
});
|
|
391
450
|
return history_default.getCodeBlockStepList(id).slice(-1)[0]?.step ?? null;
|
|
392
451
|
}
|
|
393
|
-
this.setCodeDslByIdSync(id, cloneDeep$1(
|
|
452
|
+
this.setCodeDslByIdSync(id, cloneDeep$1(oldSchema), true, {
|
|
453
|
+
historyDescription,
|
|
454
|
+
historySource: "rollback"
|
|
455
|
+
});
|
|
394
456
|
return history_default.getCodeBlockStepList(id).slice(-1)[0]?.step ?? null;
|
|
395
457
|
}
|
|
396
458
|
/**
|
|
@@ -408,19 +470,20 @@ var CodeBlock = class extends BaseService {
|
|
|
408
470
|
* @param reverse true=撤销,false=重做
|
|
409
471
|
*/
|
|
410
472
|
async applyHistoryStep(step, reverse) {
|
|
411
|
-
const { id
|
|
412
|
-
|
|
473
|
+
const { id } = step;
|
|
474
|
+
const { oldSchema, newSchema, changeRecords } = step.diff?.[0] ?? {};
|
|
475
|
+
if (!oldSchema && newSchema) {
|
|
413
476
|
if (reverse) await this.deleteCodeDslByIds([id], { doNotPushHistory: true });
|
|
414
|
-
else this.setCodeDslByIdSync(id, cloneDeep$1(
|
|
477
|
+
else this.setCodeDslByIdSync(id, cloneDeep$1(newSchema), true, { doNotPushHistory: true });
|
|
415
478
|
return;
|
|
416
479
|
}
|
|
417
|
-
if (
|
|
418
|
-
if (reverse) this.setCodeDslByIdSync(id, cloneDeep$1(
|
|
480
|
+
if (oldSchema && !newSchema) {
|
|
481
|
+
if (reverse) this.setCodeDslByIdSync(id, cloneDeep$1(oldSchema), true, { doNotPushHistory: true });
|
|
419
482
|
else await this.deleteCodeDslByIds([id], { doNotPushHistory: true });
|
|
420
483
|
return;
|
|
421
484
|
}
|
|
422
|
-
if (!
|
|
423
|
-
const sourceForValues = reverse ?
|
|
485
|
+
if (!oldSchema || !newSchema) return;
|
|
486
|
+
const sourceForValues = reverse ? oldSchema : newSchema;
|
|
424
487
|
if (changeRecords?.length) {
|
|
425
488
|
const current = this.getCodeContentById(id);
|
|
426
489
|
if (!current) return;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import BaseService from "./BaseService.js";
|
|
2
|
+
import { describeRevertStep } from "../utils/history.js";
|
|
2
3
|
import history_default from "./history.js";
|
|
3
4
|
import storage_default, { Protocol } from "./storage.js";
|
|
4
5
|
import { COPY_DS_STORAGE_KEY } from "../utils/editor.js";
|
|
@@ -26,18 +27,6 @@ var canUsePluginMethods = {
|
|
|
26
27
|
"createId"
|
|
27
28
|
]
|
|
28
29
|
};
|
|
29
|
-
/**
|
|
30
|
-
* 「回滚」生成的新 step 简短描述。
|
|
31
|
-
* 仅在 service 层使用,避免依赖 UI 层 composables。
|
|
32
|
-
*/
|
|
33
|
-
var describeRevertDataSourceStep = (step) => {
|
|
34
|
-
const { oldSchema, newSchema, changeRecords, id } = step;
|
|
35
|
-
if (oldSchema === null && newSchema) return `撤回新增 ${newSchema.title || newSchema.id || id}`;
|
|
36
|
-
if (oldSchema && newSchema === null) return `还原已删除的 ${oldSchema.title || oldSchema.id || id}`;
|
|
37
|
-
const title = newSchema?.title || oldSchema?.title || `${id}`;
|
|
38
|
-
const propPath = changeRecords?.[0]?.propPath;
|
|
39
|
-
return propPath ? `还原 ${title} · ${propPath}` : `还原 ${title}`;
|
|
40
|
-
};
|
|
41
30
|
var DataSource = class extends BaseService {
|
|
42
31
|
state = reactive({
|
|
43
32
|
datasourceTypeList: [],
|
|
@@ -48,6 +37,12 @@ var DataSource = class extends BaseService {
|
|
|
48
37
|
events: {},
|
|
49
38
|
methods: {}
|
|
50
39
|
});
|
|
40
|
+
/**
|
|
41
|
+
* 最近一次写入历史栈的数据源历史记录 uuid。
|
|
42
|
+
* 供 *AndGetHistoryId 系列方法在调用 add / update / remove 后取回本次产生的历史记录 id;
|
|
43
|
+
* 普通方法不读取它,调用前由 *AndGetHistoryId 重置为 null。
|
|
44
|
+
*/
|
|
45
|
+
lastPushedHistoryId = null;
|
|
51
46
|
constructor() {
|
|
52
47
|
super(canUsePluginMethods.sync.map((methodName) => ({
|
|
53
48
|
name: methodName,
|
|
@@ -91,17 +86,18 @@ var DataSource = class extends BaseService {
|
|
|
91
86
|
* @param options.doNotPushHistory 是否不写入历史记录(默认 false)
|
|
92
87
|
* @param options.historyDescription 入栈时附带的人类可读描述,用于历史面板展示
|
|
93
88
|
*/
|
|
94
|
-
add(config, { doNotPushHistory = false, historyDescription } = {}) {
|
|
89
|
+
add(config, { doNotPushHistory = false, historyDescription, historySource } = {}) {
|
|
95
90
|
const newConfig = {
|
|
96
91
|
...config,
|
|
97
92
|
id: config.id && !this.getDataSourceById(config.id) ? config.id : this.createId()
|
|
98
93
|
};
|
|
99
94
|
this.get("dataSources").push(newConfig);
|
|
100
|
-
if (!doNotPushHistory) history_default.pushDataSource(newConfig.id, {
|
|
95
|
+
if (!doNotPushHistory) this.lastPushedHistoryId = history_default.pushDataSource(newConfig.id, {
|
|
101
96
|
oldSchema: null,
|
|
102
97
|
newSchema: newConfig,
|
|
103
|
-
historyDescription
|
|
104
|
-
|
|
98
|
+
historyDescription,
|
|
99
|
+
source: historySource
|
|
100
|
+
})?.uuid ?? null;
|
|
105
101
|
this.emit("add", newConfig);
|
|
106
102
|
return newConfig;
|
|
107
103
|
}
|
|
@@ -113,18 +109,19 @@ var DataSource = class extends BaseService {
|
|
|
113
109
|
* @param data.doNotPushHistory 是否不写入历史记录(默认 false)
|
|
114
110
|
* @param data.historyDescription 入栈时附带的人类可读描述,用于历史面板展示
|
|
115
111
|
*/
|
|
116
|
-
update(config, { changeRecords = [], doNotPushHistory = false, historyDescription } = {}) {
|
|
112
|
+
update(config, { changeRecords = [], doNotPushHistory = false, historyDescription, historySource } = {}) {
|
|
117
113
|
const dataSources = this.get("dataSources");
|
|
118
114
|
const index = dataSources.findIndex((ds) => ds.id === config.id);
|
|
119
115
|
const oldConfig = dataSources[index];
|
|
120
116
|
const newConfig = cloneDeep$1(config);
|
|
121
117
|
dataSources[index] = newConfig;
|
|
122
|
-
if (!doNotPushHistory) history_default.pushDataSource(newConfig.id, {
|
|
118
|
+
if (!doNotPushHistory) this.lastPushedHistoryId = history_default.pushDataSource(newConfig.id, {
|
|
123
119
|
oldSchema: oldConfig ? cloneDeep$1(oldConfig) : null,
|
|
124
120
|
newSchema: newConfig,
|
|
125
121
|
changeRecords,
|
|
126
|
-
historyDescription
|
|
127
|
-
|
|
122
|
+
historyDescription,
|
|
123
|
+
source: historySource
|
|
124
|
+
})?.uuid ?? null;
|
|
128
125
|
this.emit("update", newConfig, {
|
|
129
126
|
oldConfig,
|
|
130
127
|
changeRecords
|
|
@@ -138,19 +135,45 @@ var DataSource = class extends BaseService {
|
|
|
138
135
|
* @param options.doNotPushHistory 是否不写入历史记录(默认 false)
|
|
139
136
|
* @param options.historyDescription 入栈时附带的人类可读描述,用于历史面板展示
|
|
140
137
|
*/
|
|
141
|
-
remove(id, { doNotPushHistory = false, historyDescription } = {}) {
|
|
138
|
+
remove(id, { doNotPushHistory = false, historyDescription, historySource } = {}) {
|
|
142
139
|
const dataSources = this.get("dataSources");
|
|
143
140
|
const index = dataSources.findIndex((ds) => ds.id === id);
|
|
144
141
|
const oldConfig = index !== -1 ? dataSources[index] : null;
|
|
145
142
|
dataSources.splice(index, 1);
|
|
146
|
-
if (oldConfig && !doNotPushHistory) history_default.pushDataSource(id, {
|
|
143
|
+
if (oldConfig && !doNotPushHistory) this.lastPushedHistoryId = history_default.pushDataSource(id, {
|
|
147
144
|
oldSchema: cloneDeep$1(oldConfig),
|
|
148
145
|
newSchema: null,
|
|
149
|
-
historyDescription
|
|
150
|
-
|
|
146
|
+
historyDescription,
|
|
147
|
+
source: historySource
|
|
148
|
+
})?.uuid ?? null;
|
|
151
149
|
this.emit("remove", id);
|
|
152
150
|
}
|
|
153
151
|
/**
|
|
152
|
+
* 下列 *AndGetHistoryId 方法与对应的 add / update / remove 行为完全一致,
|
|
153
|
+
* 唯一区别是返回值为本次写入历史栈的历史记录 uuid({@link DataSourceStepValue.uuid}),
|
|
154
|
+
* 而非数据源配置。可用于精确引用 / 定位该条历史记录(埋点、revert、跨端同步等)。
|
|
155
|
+
*
|
|
156
|
+
* 当本次操作未写入历史(doNotPushHistory 为 true、或无对应记录)时返回 null。
|
|
157
|
+
*/
|
|
158
|
+
/** 等价于 {@link add},但返回本次写入历史记录的 uuid(未入栈时返回 null)。 */
|
|
159
|
+
addAndGetHistoryId(config, options = {}) {
|
|
160
|
+
this.lastPushedHistoryId = null;
|
|
161
|
+
this.add(config, options);
|
|
162
|
+
return this.lastPushedHistoryId;
|
|
163
|
+
}
|
|
164
|
+
/** 等价于 {@link update},但返回本次写入历史记录的 uuid(未入栈时返回 null)。 */
|
|
165
|
+
updateAndGetHistoryId(config, options = {}) {
|
|
166
|
+
this.lastPushedHistoryId = null;
|
|
167
|
+
this.update(config, options);
|
|
168
|
+
return this.lastPushedHistoryId;
|
|
169
|
+
}
|
|
170
|
+
/** 等价于 {@link remove},但返回本次写入历史记录的 uuid(未入栈时返回 null)。 */
|
|
171
|
+
removeAndGetHistoryId(id, options = {}) {
|
|
172
|
+
this.lastPushedHistoryId = null;
|
|
173
|
+
this.remove(id, options);
|
|
174
|
+
return this.lastPushedHistoryId;
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
154
177
|
* 撤销指定数据源的最近一次变更。
|
|
155
178
|
*
|
|
156
179
|
* 内部走 add / update / remove,因此会自动触发 dataSourceService 的事件,
|
|
@@ -218,9 +241,24 @@ var DataSource = class extends BaseService {
|
|
|
218
241
|
revert(id, index) {
|
|
219
242
|
const entry = history_default.getDataSourceStepList(id)[index];
|
|
220
243
|
if (!entry?.applied) return null;
|
|
221
|
-
const
|
|
244
|
+
const { oldSchema, newSchema, changeRecords } = entry.step.diff?.[0] ?? {};
|
|
245
|
+
if (oldSchema && newSchema && !changeRecords?.length) return null;
|
|
246
|
+
const description = `回滚 #${index + 1}: ${describeRevertStep(entry.step.id, entry.step.diff?.[0], (s) => s.title)}`;
|
|
222
247
|
return this.applyRevertStep(entry.step, description);
|
|
223
248
|
}
|
|
249
|
+
/**
|
|
250
|
+
* 通过历史记录 uuid 回滚某条数据源历史步骤,语义同 {@link revert},
|
|
251
|
+
* 仅无需调用方再传 dataSourceId 与 index:内部会按 uuid({@link DataSourceStepValue.uuid})
|
|
252
|
+
* 在全部数据源栈中定位对应步骤后再回滚。
|
|
253
|
+
*
|
|
254
|
+
* @param uuid 目标历史记录的 uuid,通常由 {@link addAndGetHistoryId} 等方法返回
|
|
255
|
+
* @returns 反向后产生的新 step;找不到对应 uuid / 未应用时返回 null
|
|
256
|
+
*/
|
|
257
|
+
revertById(uuid) {
|
|
258
|
+
const location = history_default.findDataSourceStepLocationByUuid(uuid);
|
|
259
|
+
if (!location) return null;
|
|
260
|
+
return this.revert(location.id, location.index);
|
|
261
|
+
}
|
|
224
262
|
createId() {
|
|
225
263
|
return `ds_${guid()}`;
|
|
226
264
|
}
|
|
@@ -279,13 +317,20 @@ var DataSource = class extends BaseService {
|
|
|
279
317
|
* 同构,差异仅在于走对应的公共 add / update / remove 而不是带 doNotPushHistory 的版本。
|
|
280
318
|
*/
|
|
281
319
|
applyRevertStep(step, historyDescription) {
|
|
282
|
-
const { id
|
|
283
|
-
|
|
284
|
-
|
|
320
|
+
const { id } = step;
|
|
321
|
+
const { oldSchema, newSchema, changeRecords } = step.diff?.[0] ?? {};
|
|
322
|
+
if (!oldSchema && newSchema) {
|
|
323
|
+
this.remove(`${id}`, {
|
|
324
|
+
historyDescription,
|
|
325
|
+
historySource: "rollback"
|
|
326
|
+
});
|
|
285
327
|
return history_default.getDataSourceStepList(id).slice(-1)[0]?.step ?? null;
|
|
286
328
|
}
|
|
287
|
-
if (oldSchema && newSchema
|
|
288
|
-
this.add(cloneDeep$1(oldSchema), {
|
|
329
|
+
if (oldSchema && !newSchema) {
|
|
330
|
+
this.add(cloneDeep$1(oldSchema), {
|
|
331
|
+
historyDescription,
|
|
332
|
+
historySource: "rollback"
|
|
333
|
+
});
|
|
289
334
|
return history_default.getDataSourceStepList(id).slice(-1)[0]?.step ?? null;
|
|
290
335
|
}
|
|
291
336
|
if (!oldSchema || !newSchema) return null;
|
|
@@ -304,11 +349,15 @@ var DataSource = class extends BaseService {
|
|
|
304
349
|
}
|
|
305
350
|
this.update(fallbackToFullReplace ? cloneDeep$1(oldSchema) : patched, {
|
|
306
351
|
changeRecords,
|
|
307
|
-
historyDescription
|
|
352
|
+
historyDescription,
|
|
353
|
+
historySource: "rollback"
|
|
308
354
|
});
|
|
309
355
|
return history_default.getDataSourceStepList(id).slice(-1)[0]?.step ?? null;
|
|
310
356
|
}
|
|
311
|
-
this.update(cloneDeep$1(oldSchema), {
|
|
357
|
+
this.update(cloneDeep$1(oldSchema), {
|
|
358
|
+
historyDescription,
|
|
359
|
+
historySource: "rollback"
|
|
360
|
+
});
|
|
312
361
|
return history_default.getDataSourceStepList(id).slice(-1)[0]?.step ?? null;
|
|
313
362
|
}
|
|
314
363
|
/**
|
|
@@ -326,13 +375,14 @@ var DataSource = class extends BaseService {
|
|
|
326
375
|
* @param reverse true=撤销,false=重做
|
|
327
376
|
*/
|
|
328
377
|
applyHistoryStep(step, reverse) {
|
|
329
|
-
const { id
|
|
330
|
-
|
|
378
|
+
const { id } = step;
|
|
379
|
+
const { oldSchema, newSchema, changeRecords } = step.diff?.[0] ?? {};
|
|
380
|
+
if (!oldSchema && newSchema) {
|
|
331
381
|
if (reverse) this.remove(`${id}`, { doNotPushHistory: true });
|
|
332
382
|
else this.add(cloneDeep$1(newSchema), { doNotPushHistory: true });
|
|
333
383
|
return;
|
|
334
384
|
}
|
|
335
|
-
if (oldSchema && newSchema
|
|
385
|
+
if (oldSchema && !newSchema) {
|
|
336
386
|
if (reverse) this.add(cloneDeep$1(oldSchema), { doNotPushHistory: true });
|
|
337
387
|
else this.remove(`${id}`, { doNotPushHistory: true });
|
|
338
388
|
return;
|