@tmagic/editor 1.8.0-beta.4 → 1.8.0-beta.6

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.
Files changed (76) hide show
  1. package/dist/es/components/CompareForm.vue_vue_type_script_setup_true_lang.js +1 -1
  2. package/dist/es/components/ToolButton.vue_vue_type_script_setup_true_lang.js +6 -6
  3. package/dist/es/fields/CodeSelectCol.vue_vue_type_script_setup_true_lang.js +4 -1
  4. package/dist/es/fields/DataSourceFieldSelect/FieldSelect.vue_vue_type_script_setup_true_lang.js +8 -2
  5. package/dist/es/fields/DataSourceFields.vue_vue_type_script_setup_true_lang.js +25 -8
  6. package/dist/es/fields/DataSourceMethodSelect.vue_vue_type_script_setup_true_name_true_lang.js +6 -4
  7. package/dist/es/fields/DataSourceMethods.vue_vue_type_script_setup_true_lang.js +25 -12
  8. package/dist/es/fields/StyleSetter/components/Border.vue_vue_type_script_setup_true_lang.js +27 -5
  9. package/dist/es/index.js +6 -3
  10. package/dist/es/initService.js +1 -1
  11. package/dist/es/layouts/Framework.vue_vue_type_script_setup_true_lang.js +1 -1
  12. package/dist/es/layouts/history-list/Bucket.vue_vue_type_script_setup_true_lang.js +19 -55
  13. package/dist/es/layouts/history-list/BucketTab.vue_vue_type_script_setup_true_lang.js +22 -39
  14. package/dist/es/layouts/history-list/GroupRow.vue_vue_type_script_setup_true_lang.js +149 -103
  15. package/dist/es/layouts/history-list/HistoryDiffDialog.vue_vue_type_script_setup_true_lang.js +32 -8
  16. package/dist/es/layouts/history-list/HistoryListPanel.vue_vue_type_script_setup_true_lang.js +335 -213
  17. package/dist/es/layouts/history-list/InitialRow.vue_vue_type_script_setup_true_lang.js +36 -7
  18. package/dist/es/layouts/history-list/PageTab.vue_vue_type_script_setup_true_lang.js +47 -60
  19. package/dist/es/layouts/history-list/composables.js +73 -32
  20. package/dist/es/layouts/page-bar/PageBar.vue_vue_type_script_setup_true_lang.js +4 -2
  21. package/dist/es/layouts/sidebar/Sidebar.vue_vue_type_script_setup_true_lang.js +5 -1
  22. package/dist/es/layouts/sidebar/data-source/DataSourceConfigPanel.vue_vue_type_script_setup_true_lang.js +16 -3
  23. package/dist/es/layouts/sidebar/data-source/DataSourceListPanel.vue_vue_type_script_setup_true_lang.js +23 -1
  24. package/dist/es/services/codeBlock.js +96 -37
  25. package/dist/es/services/dataSource.js +70 -26
  26. package/dist/es/services/editor.js +266 -104
  27. package/dist/es/services/history.js +271 -212
  28. package/dist/es/services/ui.js +3 -0
  29. package/dist/es/style.css +53 -7
  30. package/dist/es/utils/data-source/index.js +2 -0
  31. package/dist/es/utils/editor.js +103 -49
  32. package/dist/es/utils/history.js +232 -0
  33. package/dist/es/utils/indexed-db.js +86 -0
  34. package/dist/es/utils/undo-redo.js +60 -1
  35. package/dist/style.css +53 -7
  36. package/dist/tmagic-editor.umd.cjs +2064 -1000
  37. package/package.json +7 -7
  38. package/src/components/CompareForm.vue +3 -1
  39. package/src/components/ToolButton.vue +2 -2
  40. package/src/fields/CodeSelectCol.vue +7 -1
  41. package/src/fields/DataSourceFieldSelect/FieldSelect.vue +16 -2
  42. package/src/fields/DataSourceFields.vue +37 -8
  43. package/src/fields/DataSourceMethodSelect.vue +9 -4
  44. package/src/fields/DataSourceMethods.vue +42 -21
  45. package/src/fields/StyleSetter/components/Border.vue +15 -6
  46. package/src/index.ts +1 -0
  47. package/src/initService.ts +1 -1
  48. package/src/layouts/Framework.vue +1 -1
  49. package/src/layouts/history-list/Bucket.vue +34 -71
  50. package/src/layouts/history-list/BucketTab.vue +46 -54
  51. package/src/layouts/history-list/GroupRow.vue +146 -111
  52. package/src/layouts/history-list/HistoryDiffDialog.vue +94 -68
  53. package/src/layouts/history-list/HistoryListPanel.vue +298 -115
  54. package/src/layouts/history-list/InitialRow.vue +28 -9
  55. package/src/layouts/history-list/PageTab.vue +57 -51
  56. package/src/layouts/history-list/composables.ts +157 -36
  57. package/src/layouts/page-bar/PageBar.vue +4 -2
  58. package/src/layouts/sidebar/Sidebar.vue +6 -1
  59. package/src/layouts/sidebar/data-source/DataSourceConfigPanel.vue +30 -2
  60. package/src/layouts/sidebar/data-source/DataSourceListPanel.vue +26 -1
  61. package/src/services/codeBlock.ts +113 -37
  62. package/src/services/dataSource.ts +94 -40
  63. package/src/services/editor.ts +376 -136
  64. package/src/services/history.ts +306 -209
  65. package/src/services/ui.ts +7 -0
  66. package/src/theme/history-list-panel.scss +72 -5
  67. package/src/theme/page-bar.scss +0 -4
  68. package/src/theme/style-setter/border.scss +4 -1
  69. package/src/type.ts +183 -64
  70. package/src/utils/data-source/index.ts +2 -0
  71. package/src/utils/editor.ts +166 -60
  72. package/src/utils/history.ts +308 -0
  73. package/src/utils/index.ts +2 -0
  74. package/src/utils/indexed-db.ts +122 -0
  75. package/src/utils/undo-redo.ts +88 -0
  76. package/types/index.d.ts +813 -302
@@ -1,6 +1,18 @@
1
- import { createCommentVNode, createElementBlock, createElementVNode, defineComponent, normalizeClass, openBlock, withModifiers } from "vue";
1
+ import { formatHistoryFullTime, formatHistoryTime } from "./composables.js";
2
+ import { computed, createCommentVNode, createElementBlock, createElementVNode, defineComponent, normalizeClass, openBlock, toDisplayString, withModifiers } from "vue";
2
3
  //#region packages/editor/src/layouts/history-list/InitialRow.vue?vue&type=script&setup=true&lang.ts
3
4
  var _hoisted_1 = ["title"];
5
+ var _hoisted_2 = { class: "m-editor-history-list-item-desc" };
6
+ var _hoisted_3 = {
7
+ key: 0,
8
+ class: "m-editor-history-list-item-saved",
9
+ title: "该记录为最近一次保存的状态"
10
+ };
11
+ var _hoisted_4 = {
12
+ key: 1,
13
+ class: "m-editor-history-list-item-actions"
14
+ };
15
+ var _hoisted_5 = ["title"];
4
16
  var InitialRow_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineComponent({
5
17
  name: "MEditorHistoryListInitialRow",
6
18
  __name: "InitialRow",
@@ -9,7 +21,8 @@ var InitialRow_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ def
9
21
  gotoEnabled: {
10
22
  type: Boolean,
11
23
  default: true
12
- }
24
+ },
25
+ marker: { default: void 0 }
13
26
  },
14
27
  emits: ["goto-initial"],
15
28
  setup(__props, { emit: __emit }) {
@@ -17,10 +30,21 @@ var InitialRow_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ def
17
30
  * 「初始状态」记录行:渲染于历史列表底部,作为整个栈的"零点"。
18
31
  * - 点击该行会把对应栈撤销到 cursor === 0(即没有任何已应用步骤),等同于回到所有修改之前。
19
32
  * - 当对应栈本身已处于 cursor === 0 时(isCurrent=true),用户已在初始状态,点击不再触发动作。
33
+ * - 当上层传入 `marker`(设置 root 时为该页生成的「未修改的初始状态」标记)时,
34
+ * 用标记的文案与时间渲染本行;标记不进入撤销/重做栈,仅作为该页基线展示。
20
35
  *
21
36
  * 该行不是真实 step,仅作为 UI 入口;上层负责把"点击"翻译为 `service.goto*(0)`。
22
37
  */
23
38
  const props = __props;
39
+ const desc = computed(() => props.marker?.historyDescription || "未修改的初始状态");
40
+ /** 基线(初始状态)是否为最近一次保存点:仅页面栈的 `initial` 基线 step 会被 markSaved 标记。 */
41
+ const saved = computed(() => Boolean(props.marker?.saved));
42
+ const time = computed(() => formatHistoryTime(props.marker?.timestamp));
43
+ const timeTitle = computed(() => formatHistoryFullTime(props.marker?.timestamp));
44
+ const rowTitle = computed(() => {
45
+ const base = props.marker?.historyDescription || "未修改的初始状态";
46
+ return props.isCurrent ? `当前已回到${base}` : `点击回到${base}`;
47
+ });
24
48
  const emit = __emit;
25
49
  const onClick = () => {
26
50
  if (props.isCurrent) return;
@@ -32,20 +56,25 @@ var InitialRow_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ def
32
56
  "is-current": __props.isCurrent,
33
57
  "is-clickable": !__props.isCurrent
34
58
  }]),
35
- title: __props.isCurrent ? "当前已回到未修改的初始状态" : "点击回到未修改的初始状态"
59
+ title: rowTitle.value
36
60
  }, [
37
61
  _cache[0] || (_cache[0] = createElementVNode("span", {
38
62
  class: "m-editor-history-list-item-index",
39
63
  title: "历史步骤编号 #0(未修改的初始状态)"
40
64
  }, "#0", -1)),
41
65
  _cache[1] || (_cache[1] = createElementVNode("span", { class: "m-editor-history-list-item-op op-initial" }, "初始", -1)),
42
- _cache[2] || (_cache[2] = createElementVNode("span", { class: "m-editor-history-list-item-desc" }, "未修改的初始状态", -1)),
43
- __props.gotoEnabled && !__props.isCurrent ? (openBlock(), createElementBlock("span", {
44
- key: 0,
66
+ createElementVNode("span", _hoisted_2, toDisplayString(desc.value), 1),
67
+ saved.value ? (openBlock(), createElementBlock("span", _hoisted_3, "已保存")) : createCommentVNode("v-if", true),
68
+ __props.gotoEnabled && !__props.isCurrent ? (openBlock(), createElementBlock("span", _hoisted_4, [createElementVNode("span", {
45
69
  class: "m-editor-history-list-item-goto",
46
70
  title: "回到该记录",
47
71
  onClick: withModifiers(onClick, ["stop"])
48
- }, "回到")) : createCommentVNode("v-if", true)
72
+ }, "回到")])) : createCommentVNode("v-if", true),
73
+ time.value ? (openBlock(), createElementBlock("span", {
74
+ key: 2,
75
+ class: "m-editor-history-list-item-time",
76
+ title: timeTitle.value
77
+ }, toDisplayString(time.value), 9, _hoisted_5)) : createCommentVNode("v-if", true)
49
78
  ], 10, _hoisted_1);
50
79
  };
51
80
  }
@@ -1,4 +1,4 @@
1
- import { describePageGroup, describePageStep, formatHistoryFullTime, formatHistoryTime, groupSource, groupTimestamp, isPageStepRevertable } from "./composables.js";
1
+ import { describePageGroup, describePageStep, isHistoryGroupExpanded, isPageStepRevertable, toRowGroup } from "./composables.js";
2
2
  import GroupRow_default from "./GroupRow.js";
3
3
  import InitialRow_default from "./InitialRow.js";
4
4
  import { TMagicScrollbar } from "@tmagic/design";
@@ -8,99 +8,86 @@ var _hoisted_1 = {
8
8
  key: 0,
9
9
  class: "m-editor-history-list-empty"
10
10
  };
11
- var _hoisted_2 = { class: "m-editor-history-list-ul" };
11
+ var _hoisted_2 = {
12
+ key: 0,
13
+ class: "m-editor-history-list-toolbar"
14
+ };
15
+ var _hoisted_3 = { class: "m-editor-history-list-ul" };
12
16
  var PageTab_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineComponent({
13
17
  name: "MEditorHistoryListPageTab",
14
18
  __name: "PageTab",
15
19
  props: {
16
20
  list: {},
17
- expanded: {}
21
+ expanded: {},
22
+ marker: {}
18
23
  },
19
24
  emits: [
20
25
  "toggle",
21
26
  "goto",
22
27
  "goto-initial",
23
28
  "diff-step",
24
- "revert-step"
29
+ "revert-step",
30
+ "select",
31
+ "clear"
25
32
  ],
26
33
  setup(__props) {
27
34
  const props = __props;
28
35
  /**
29
36
  * 当前 step 是否可查看差异:
30
37
  * - 仅 update 操作;
31
- * - 单节点更新(updatedItems.length === 1),且 oldNode / newNode 都存在。
38
+ * - 单节点更新(diff.length === 1),且 oldSchema / newSchema 都存在。
32
39
  * 多节点更新难以选定单一对比目标,统一不展示差异入口。
33
40
  */
34
41
  const isPageStepDiffable = (step) => {
35
42
  if (step.opType !== "update") return false;
36
- const items = step.updatedItems ?? [];
43
+ const items = step.diff ?? [];
37
44
  if (items.length !== 1) return false;
38
- return Boolean(items[0]?.oldNode && items[0]?.newNode);
45
+ return Boolean(items[0]?.oldSchema && items[0]?.newSchema);
46
+ };
47
+ /** 页面历史的描述 / 可操作性判定集合,注入给统一的 `toRowGroup`。 */
48
+ const descriptor = {
49
+ describeGroup: describePageGroup,
50
+ describeStep: describePageStep,
51
+ isStepDiffable: isPageStepDiffable,
52
+ isStepRevertable: isPageStepRevertable
39
53
  };
54
+ const rowKey = (group) => `pg-${group.steps[0]?.index}`;
55
+ const toRow = (group) => toRowGroup(group, rowKey(group), descriptor);
40
56
  /**
41
57
  * 是否处于"初始状态"——即对应页面历史栈 cursor===0:
42
- * 当 list 中所有 group 的 applied 都为 false 时即为该状态。
43
- * 没有任何 group 的情况由外层"暂无操作记录"分支兜底,本计算可以不考虑。
58
+ * 当 list 中所有 group 的 applied 都为 false 时即为该状态(空列表 `every` 返回 true,
59
+ * 即仅有 marker、无任何操作记录时也视为处于初始状态)。
44
60
  */
45
- const isInitial = computed(() => props.list.length > 0 && props.list.every((g) => !g.applied));
61
+ const isInitial = computed(() => props.list.every((g) => !g.applied));
46
62
  return (_ctx, _cache) => {
47
- return !__props.list.length ? (openBlock(), createElementBlock("div", _hoisted_1, "暂无操作记录")) : (openBlock(), createBlock(unref(TMagicScrollbar), {
48
- key: 1,
49
- "max-height": "360px"
50
- }, {
51
- default: withCtx(() => [createElementVNode("ul", _hoisted_2, [
63
+ return !__props.list.length && !__props.marker ? (openBlock(), createElementBlock("div", _hoisted_1, "暂无操作记录")) : (openBlock(), createElementBlock(Fragment, { key: 1 }, [__props.list.length ? (openBlock(), createElementBlock("div", _hoisted_2, [createElementVNode("span", {
64
+ class: "m-editor-history-list-clear",
65
+ title: "清空当前页面的历史记录",
66
+ onClick: _cache[0] || (_cache[0] = ($event) => _ctx.$emit("clear"))
67
+ }, "清空")])) : createCommentVNode("v-if", true), createVNode(unref(TMagicScrollbar), { "max-height": "360px" }, {
68
+ default: withCtx(() => [createElementVNode("ul", _hoisted_3, [
52
69
  (openBlock(true), createElementBlock(Fragment, null, renderList(__props.list, (group) => {
53
70
  return openBlock(), createBlock(GroupRow_default, {
54
- key: `pg-${group.steps[0]?.index}`,
55
- "group-key": `pg-${group.steps[0]?.index}`,
56
- applied: group.applied,
57
- merged: group.steps.length > 1,
58
- "op-type": group.opType,
59
- desc: unref(describePageGroup)(group),
60
- source: unref(groupSource)(group),
61
- time: unref(formatHistoryTime)(unref(groupTimestamp)(group)),
62
- "time-title": unref(formatHistoryFullTime)(unref(groupTimestamp)(group)),
63
- "step-count": group.steps.length,
64
- "sub-steps": group.steps.map((s) => ({
65
- index: s.index,
66
- applied: s.applied,
67
- isCurrent: s.isCurrent,
68
- desc: unref(describePageStep)(s.step),
69
- diffable: isPageStepDiffable(s.step),
70
- revertable: s.applied && unref(isPageStepRevertable)(s.step),
71
- source: s.step.source,
72
- time: unref(formatHistoryTime)(s.step.timestamp),
73
- timeTitle: unref(formatHistoryFullTime)(s.step.timestamp)
74
- })),
75
- "is-current": group.isCurrent,
76
- expanded: !!__props.expanded[`pg-${group.steps[0]?.index}`],
77
- onToggle: _cache[0] || (_cache[0] = (key) => _ctx.$emit("toggle", key)),
78
- onGoto: _cache[1] || (_cache[1] = (index) => _ctx.$emit("goto", index)),
79
- onDiffStep: _cache[2] || (_cache[2] = (index) => _ctx.$emit("diff-step", index)),
80
- onRevertStep: _cache[3] || (_cache[3] = (index) => _ctx.$emit("revert-step", index))
81
- }, null, 8, [
82
- "group-key",
83
- "applied",
84
- "merged",
85
- "op-type",
86
- "desc",
87
- "source",
88
- "time",
89
- "time-title",
90
- "step-count",
91
- "sub-steps",
92
- "is-current",
93
- "expanded"
94
- ]);
71
+ key: rowKey(group),
72
+ group: toRow(group),
73
+ expanded: unref(isHistoryGroupExpanded)(__props.expanded, rowKey(group)),
74
+ "select-enabled": true,
75
+ onToggle: _cache[1] || (_cache[1] = (key) => _ctx.$emit("toggle", key)),
76
+ onGoto: _cache[2] || (_cache[2] = (index) => _ctx.$emit("goto", index)),
77
+ onDiffStep: _cache[3] || (_cache[3] = (index) => _ctx.$emit("diff-step", index)),
78
+ onRevertStep: _cache[4] || (_cache[4] = (index) => _ctx.$emit("revert-step", index)),
79
+ onSelect: _cache[5] || (_cache[5] = (index) => _ctx.$emit("select", index))
80
+ }, null, 8, ["group", "expanded"]);
95
81
  }), 128)),
96
- createCommentVNode("\n 初始状态项:永远位于列表底部(页面 tab 倒序展示,最底部=最早),\n 作为\"未修改\"零点。当所有 group 都未 applied 时它即为当前位置。\n "),
82
+ createCommentVNode("\n 初始状态项:永远位于列表底部(页面 tab 倒序展示,最底部=最早),\n 作为\"未修改\"零点。当所有 group 都未 applied 时它即为当前位置。\n 设置 root 时生成的「未修改的初始状态」标记(marker)会作为该行的文案与时间来源。\n "),
97
83
  createVNode(InitialRow_default, {
98
84
  "is-current": isInitial.value,
99
- onGotoInitial: _cache[4] || (_cache[4] = ($event) => _ctx.$emit("goto-initial"))
100
- }, null, 8, ["is-current"])
85
+ marker: __props.marker,
86
+ onGotoInitial: _cache[6] || (_cache[6] = ($event) => _ctx.$emit("goto-initial"))
87
+ }, null, 8, ["is-current", "marker"])
101
88
  ])]),
102
89
  _: 1
103
- }));
90
+ })], 64));
104
91
  };
105
92
  }
106
93
  });
@@ -2,6 +2,8 @@ import { useServices } from "../../hooks/use-services.js";
2
2
  import { datetimeFormatter } from "@tmagic/form";
3
3
  import { computed, reactive } from "vue";
4
4
  //#region packages/editor/src/layouts/history-list/composables.ts
5
+ /** 合并组默认展开;仅当 expanded[key] === false 时为收起。 */
6
+ var isHistoryGroupExpanded = (expanded, key) => expanded[key] !== false;
5
7
  /**
6
8
  * 历史记录面板共享逻辑:
7
9
  * - 暴露三类历史的聚合数据(页面 / 数据源 / 代码块);
@@ -15,10 +17,11 @@ var useHistoryList = () => {
15
17
  /**
16
18
  * 折叠状态:key 形如 `pg-${组内首步 index}` / `ds-${id}-${组内首步 index}` / `cb-${id}-${组内首步 index}`。
17
19
  * 用组内首步的稳定 index(而非展示位置)作为 key,确保历史数据更新后已展开的分组状态保持不变。
20
+ * 合并组默认展开;仅当值为 `false` 时表示收起。
18
21
  */
19
22
  const expanded = reactive({});
20
23
  const toggleGroup = (key) => {
21
- expanded[key] = !expanded[key];
24
+ expanded[key] = expanded[key] === false;
22
25
  };
23
26
  const pageGroups = computed(() => historyService.getPageHistoryGroups());
24
27
  const dataSourceGroups = computed(() => historyService.getDataSourceHistoryGroups());
@@ -80,6 +83,7 @@ var HISTORY_SOURCE_LABELS = {
80
83
  "component-panel": "组件面板",
81
84
  props: "配置面板",
82
85
  code: "源码",
86
+ "root-code": "DSL源码",
83
87
  "stage-contextmenu": "画布菜单",
84
88
  "tree-contextmenu": "树菜单",
85
89
  toolbar: "工具栏",
@@ -87,6 +91,8 @@ var HISTORY_SOURCE_LABELS = {
87
91
  rollback: "回滚",
88
92
  api: "接口",
89
93
  ai: "AI",
94
+ initial: "初始值",
95
+ sync: "同步",
90
96
  unknown: "未知"
91
97
  };
92
98
  /** 操作途径文案:用于历史面板展示「画布 / 树面板 / 配置面板…」标签。 */
@@ -95,6 +101,37 @@ var sourceLabel = (source = "unknown") => {
95
101
  };
96
102
  /** 取一组历史步骤里最后一步(最近一次)的操作途径,用于组头部展示。 */
97
103
  var groupSource = (group) => group.steps[group.steps.length - 1]?.step.source;
104
+ /**
105
+ * 把一个历史分组(页面 / bucket)派生为 GroupRow 直接消费的视图模型 {@link HistoryRowGroup}。
106
+ * 统一了原先 PageTab / Bucket 各自内联的 sub-steps 映射逻辑:描述、可差异、可回滚、时间、途径
107
+ * 全部在此一次性算好,组件层只负责渲染。
108
+ */
109
+ var toRowGroup = (group, key, descriptor) => {
110
+ const { describeGroup, describeStep, isStepDiffable, isStepRevertable } = descriptor;
111
+ const timestamp = groupTimestamp(group);
112
+ return {
113
+ key,
114
+ applied: group.applied,
115
+ isCurrent: Boolean(group.isCurrent),
116
+ opType: group.opType,
117
+ desc: describeGroup(group),
118
+ source: groupSource(group),
119
+ time: formatHistoryTime(timestamp),
120
+ timeTitle: formatHistoryFullTime(timestamp),
121
+ subSteps: group.steps.map((s) => ({
122
+ index: s.index,
123
+ applied: s.applied,
124
+ isCurrent: s.isCurrent,
125
+ saved: s.step.saved,
126
+ desc: describeStep(s.step),
127
+ diffable: isStepDiffable ? isStepDiffable(s.step) : false,
128
+ revertable: s.applied && (isStepRevertable ? isStepRevertable(s.step) : true),
129
+ source: s.step.source,
130
+ time: formatHistoryTime(s.step.timestamp),
131
+ timeTitle: formatHistoryFullTime(s.step.timestamp)
132
+ }))
133
+ };
134
+ };
98
135
  var nameOf = (node) => node?.name || node?.type || `${node?.id ?? ""}`;
99
136
  /**
100
137
  * 默认描述里展示「名称 (id: xxx)」,便于区分同名实体。
@@ -113,24 +150,24 @@ var pickLastDescription = (descs) => {
113
150
  var describePageStep = (step) => {
114
151
  if (step.historyDescription) return step.historyDescription;
115
152
  const { opType } = step;
153
+ const items = step.diff ?? [];
116
154
  if (opType === "add") {
117
- const count = step.nodes?.length ?? 0;
118
- const node = step.nodes?.[0];
155
+ const count = items.length;
156
+ const node = items[0]?.newSchema;
119
157
  return `新增 ${count} 个节点${count === 1 && node ? `(${labelWithId(nameOf(node), node.id)})` : ""}`;
120
158
  }
121
159
  if (opType === "remove") {
122
- const count = step.removedItems?.length ?? 0;
123
- const node = step.removedItems?.[0]?.node;
160
+ const count = items.length;
161
+ const node = items[0]?.oldSchema;
124
162
  return `删除 ${count} 个节点${count === 1 && node ? `(${labelWithId(nameOf(node), node.id)})` : ""}`;
125
163
  }
126
- const updated = step.updatedItems ?? [];
127
- if (!updated.length) return "修改节点";
128
- if (updated.length === 1) {
129
- const { newNode, changeRecords } = updated[0];
164
+ if (!items.length) return "修改节点";
165
+ if (items.length === 1) {
166
+ const { newSchema, changeRecords } = items[0];
130
167
  const propPath = changeRecords?.[0]?.propPath;
131
- return `修改 ${labelWithId(nameOf(newNode), newNode?.id)}${propPath ? ` · ${propPath}` : ""}`;
168
+ return `修改 ${labelWithId(nameOf(newSchema), newSchema?.id)}${propPath ? ` · ${propPath}` : ""}`;
132
169
  }
133
- return `修改 ${updated.length} 个节点`;
170
+ return `修改 ${items.length} 个节点`;
134
171
  };
135
172
  /**
136
173
  * 合并组的展示文案:
@@ -144,7 +181,7 @@ var describePageGroup = (group) => {
144
181
  if (group.steps.length === 1) return describePageStep(group.steps[0].step);
145
182
  const paths = /* @__PURE__ */ new Set();
146
183
  group.steps.forEach((s) => {
147
- s.step.updatedItems?.[0]?.changeRecords?.forEach((r) => r.propPath && paths.add(r.propPath));
184
+ s.step.diff?.[0]?.changeRecords?.forEach((r) => r.propPath && paths.add(r.propPath));
148
185
  });
149
186
  const pathList = Array.from(paths).slice(0, 3).join(", ");
150
187
  const target = labelWithId(group.targetName ?? (group.targetId !== void 0 ? `${group.targetId}` : "节点"), group.targetId);
@@ -152,10 +189,11 @@ var describePageGroup = (group) => {
152
189
  };
153
190
  var describeDataSourceStep = (step) => {
154
191
  if (step.historyDescription) return step.historyDescription;
155
- if (step.oldSchema === null && step.newSchema) return `创建 ${labelWithId(step.newSchema.title, step.newSchema.id ?? step.id)}`;
156
- if (step.newSchema === null && step.oldSchema) return `删除 ${labelWithId(step.oldSchema.title, step.oldSchema.id ?? step.id)}`;
157
- const propPath = step.changeRecords?.[0]?.propPath;
158
- const title = labelWithId(step.newSchema?.title || step.oldSchema?.title, step.id);
192
+ const { oldSchema, newSchema, changeRecords } = step.diff?.[0] ?? {};
193
+ if (!oldSchema && newSchema) return `创建 ${labelWithId(newSchema.title, newSchema.id ?? step.id)}`;
194
+ if (!newSchema && oldSchema) return `删除 ${labelWithId(oldSchema.title, oldSchema.id ?? step.id)}`;
195
+ const propPath = changeRecords?.[0]?.propPath;
196
+ const title = labelWithId(newSchema?.title || oldSchema?.title, step.id);
159
197
  return propPath ? `修改 ${title} · ${propPath}` : `修改 ${title}`;
160
198
  };
161
199
  var describeDataSourceGroup = (group) => {
@@ -164,18 +202,19 @@ var describeDataSourceGroup = (group) => {
164
202
  if (group.steps.length === 1) return describeDataSourceStep(group.steps[0].step);
165
203
  const paths = /* @__PURE__ */ new Set();
166
204
  group.steps.forEach((s) => {
167
- s.step.changeRecords?.forEach((r) => r.propPath && paths.add(r.propPath));
205
+ s.step.diff?.[0]?.changeRecords?.forEach((r) => r.propPath && paths.add(r.propPath));
168
206
  });
169
207
  const pathList = Array.from(paths).slice(0, 3).join(", ");
170
- const target = labelWithId(group.steps[group.steps.length - 1].step.newSchema?.title || group.steps[0].step.oldSchema?.title, group.id);
208
+ const target = labelWithId(group.steps[group.steps.length - 1].step.diff?.[0]?.newSchema?.title || group.steps[0].step.diff?.[0]?.oldSchema?.title, group.id);
171
209
  return pathList ? `修改 ${target} · ${pathList}${paths.size > 3 ? "…" : ""}` : `修改 ${target}`;
172
210
  };
173
211
  var describeCodeBlockStep = (step) => {
174
212
  if (step.historyDescription) return step.historyDescription;
175
- if (step.oldContent === null && step.newContent) return `创建 ${labelWithId(step.newContent.name, step.newContent.id ?? step.id)}`;
176
- if (step.newContent === null && step.oldContent) return `删除 ${labelWithId(step.oldContent.name, step.oldContent.id ?? step.id)}`;
177
- const propPath = step.changeRecords?.[0]?.propPath;
178
- const title = labelWithId(step.newContent?.name || step.oldContent?.name, step.id);
213
+ const { oldSchema: oldContent, newSchema: newContent, changeRecords } = step.diff?.[0] ?? {};
214
+ if (!oldContent && newContent) return `创建 ${labelWithId(newContent.name, newContent.id ?? step.id)}`;
215
+ if (!newContent && oldContent) return `删除 ${labelWithId(oldContent.name, oldContent.id ?? step.id)}`;
216
+ const propPath = changeRecords?.[0]?.propPath;
217
+ const title = labelWithId(newContent?.name || oldContent?.name, step.id);
179
218
  return propPath ? `修改 ${title} · ${propPath}` : `修改 ${title}`;
180
219
  };
181
220
  var describeCodeBlockGroup = (group) => {
@@ -184,10 +223,10 @@ var describeCodeBlockGroup = (group) => {
184
223
  if (group.steps.length === 1) return describeCodeBlockStep(group.steps[0].step);
185
224
  const paths = /* @__PURE__ */ new Set();
186
225
  group.steps.forEach((s) => {
187
- s.step.changeRecords?.forEach((r) => r.propPath && paths.add(r.propPath));
226
+ s.step.diff?.[0]?.changeRecords?.forEach((r) => r.propPath && paths.add(r.propPath));
188
227
  });
189
228
  const pathList = Array.from(paths).slice(0, 3).join(", ");
190
- const target = labelWithId(group.steps[group.steps.length - 1].step.newContent?.name || group.steps[0].step.oldContent?.name, group.id);
229
+ const target = labelWithId(group.steps[group.steps.length - 1].step.diff?.[0]?.newSchema?.name || group.steps[0].step.diff?.[0]?.oldSchema?.name, group.id);
191
230
  return pathList ? `修改 ${target} · ${pathList}${paths.size > 3 ? "…" : ""}` : `修改 ${target}`;
192
231
  };
193
232
  /**
@@ -198,27 +237,29 @@ var describeCodeBlockGroup = (group) => {
198
237
  */
199
238
  var isPageStepRevertable = (step) => {
200
239
  if (step.opType !== "update") return true;
201
- const items = step.updatedItems ?? [];
240
+ const items = step.diff ?? [];
202
241
  if (!items.length) return false;
203
242
  return items.every((item) => Boolean(item.changeRecords?.length));
204
243
  };
205
244
  /**
206
245
  * 数据源 step 是否支持「回滚」:
207
- * - 新增(oldSchema=null)/ 删除(newSchema=null):不依赖 changeRecords,始终可回滚;
246
+ * - 新增(无 oldSchema)/ 删除(无 newSchema):不依赖 changeRecords,始终可回滚;
208
247
  * - 更新(前后 schema 都存在):必须有 changeRecords 才支持局部反向 patch,否则不支持回滚。
209
248
  */
210
249
  var isDataSourceStepRevertable = (step) => {
211
- if (step.oldSchema === null || step.newSchema === null) return true;
212
- return Boolean(step.changeRecords?.length);
250
+ const item = step.diff?.[0];
251
+ if (!item?.oldSchema || !item?.newSchema) return true;
252
+ return Boolean(item.changeRecords?.length);
213
253
  };
214
254
  /**
215
255
  * 代码块 step 是否支持「回滚」:
216
- * - 新增(oldContent=null)/ 删除(newContent=null):不依赖 changeRecords,始终可回滚;
256
+ * - 新增(无 oldSchema)/ 删除(无 newSchema):不依赖 changeRecords,始终可回滚;
217
257
  * - 更新(前后 content 都存在):必须有 changeRecords 才支持局部反向 patch,否则不支持回滚。
218
258
  */
219
259
  var isCodeBlockStepRevertable = (step) => {
220
- if (step.oldContent === null || step.newContent === null) return true;
221
- return Boolean(step.changeRecords?.length);
260
+ const item = step.diff?.[0];
261
+ if (!item?.oldSchema || !item?.newSchema) return true;
262
+ return Boolean(item.changeRecords?.length);
222
263
  };
223
264
  //#endregion
224
- export { describeCodeBlockGroup, describeCodeBlockStep, describeDataSourceGroup, describeDataSourceStep, describePageGroup, describePageStep, formatHistoryFullTime, formatHistoryTime, groupSource, groupTimestamp, isCodeBlockStepRevertable, isDataSourceStepRevertable, isPageStepRevertable, opLabel, sourceLabel, useHistoryList };
265
+ export { describeCodeBlockGroup, describeCodeBlockStep, describeDataSourceGroup, describeDataSourceStep, describePageGroup, describePageStep, formatHistoryFullTime, formatHistoryTime, isCodeBlockStepRevertable, isDataSourceStepRevertable, isHistoryGroupExpanded, isPageStepRevertable, opLabel, sourceLabel, toRowGroup, useHistoryList };
@@ -4,7 +4,7 @@ import AddButton_default from "./AddButton.js";
4
4
  import PageBarScrollContainer_default from "./PageBarScrollContainer.js";
5
5
  import PageList_default from "./PageList.js";
6
6
  import Search_default from "./Search.js";
7
- import { TMagicIcon, TMagicPopover } from "@tmagic/design";
7
+ import { TMagicIcon, TMagicPopover, tMagicMessageBox } from "@tmagic/design";
8
8
  import { NodeType } from "@tmagic/core";
9
9
  import { Fragment, computed, createElementBlock, createElementVNode, createVNode, defineComponent, normalizeClass, openBlock, ref, renderList, renderSlot, toDisplayString, unref, useTemplateRef, watch, withCtx } from "vue";
10
10
  import { CaretBottom, Delete, DocumentCopy } from "@element-plus/icons-vue";
@@ -54,7 +54,8 @@ var PageBar_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ define
54
54
  top: 0
55
55
  });
56
56
  };
57
- const remove = (node) => {
57
+ const remove = async (node) => {
58
+ await tMagicMessageBox.confirm("确定删除该页面吗?");
58
59
  editorService.remove(node);
59
60
  };
60
61
  const pageBarScrollContainerRef = useTemplateRef("pageBarScrollContainer");
@@ -121,6 +122,7 @@ var PageBar_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ define
121
122
  type: "button",
122
123
  text: "删除",
123
124
  icon: unref(Delete),
125
+ buttonProps: { type: "danger" },
124
126
  handler: () => remove(item)
125
127
  } }, null, 8, ["data"])])])]),
126
128
  _: 2
@@ -71,7 +71,11 @@ var Sidebar_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ define
71
71
  });
72
72
  }
73
73
  }, { immediate: true });
74
- const activeTabName = ref(props.data?.status);
74
+ const activeTabName = computed({
75
+ get: () => uiService.get("sideBarActiveTabName"),
76
+ set: (value) => uiService.set("sideBarActiveTabName", value)
77
+ });
78
+ uiService.set("sideBarActiveTabName", props.data?.status || "");
75
79
  const getItemConfig = (data) => {
76
80
  const map = {
77
81
  [SideItemKey.COMPONENT_LIST]: {
@@ -4,7 +4,7 @@ import { useNextFloatBoxPosition } from "../../../hooks/use-next-float-box-posit
4
4
  import FloatingBox_default from "../../../components/FloatingBox.js";
5
5
  import { MFormBox } from "@tmagic/form";
6
6
  import { tMagicMessage } from "@tmagic/design";
7
- import { createBlock, createVNode, defineComponent, inject, isRef, mergeModels, nextTick, openBlock, ref, unref, useModel, watch, watchEffect, withCtx } from "vue";
7
+ import { computed, createBlock, createVNode, defineComponent, inject, isRef, mergeModels, nextTick, openBlock, provide, ref, unref, useModel, watch, watchEffect, withCtx } from "vue";
8
8
  //#region packages/editor/src/layouts/sidebar/data-source/DataSourceConfigPanel.vue?vue&type=script&setup=true&lang.ts
9
9
  var DataSourceConfigPanel_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineComponent({
10
10
  name: "MEditorDataSourceConfigPanel",
@@ -12,7 +12,9 @@ var DataSourceConfigPanel_vue_vue_type_script_setup_true_lang_default = /* @__PU
12
12
  props: /* @__PURE__ */ mergeModels({
13
13
  title: {},
14
14
  values: {},
15
- disabled: { type: Boolean }
15
+ disabled: { type: Boolean },
16
+ editMethodName: {},
17
+ editFieldPath: {}
16
18
  }, {
17
19
  "visible": {
18
20
  type: Boolean,
@@ -37,9 +39,20 @@ var DataSourceConfigPanel_vue_vue_type_script_setup_true_lang_default = /* @__PU
37
39
  const dataSourceConfig = ref([]);
38
40
  const { height: editorHeight } = useEditorContentHeight();
39
41
  const { boxPosition, calcBoxPosition } = useNextFloatBoxPosition(uiService, inject("parentFloating", ref(null)));
42
+ /** 供「方法定义」tab 内的字段消费,用于打开数据源详情后自动打开指定方法 */
43
+ provide("editingDataSourceMethodName", computed(() => props.editMethodName));
44
+ /** 供「数据定义」tab 内的字段消费,用于打开数据源详情后自动打开指定字段 */
45
+ provide("editingDataSourceFieldPath", computed(() => props.editFieldPath || []));
40
46
  watchEffect(() => {
41
47
  initValues.value = props.values;
42
- dataSourceConfig.value = dataSourceService.getFormConfig(initValues.value.type);
48
+ const config = dataSourceService.getFormConfig(initValues.value.type);
49
+ let activeTab = "";
50
+ if (props.editMethodName) activeTab = "methods";
51
+ else if (props.editFieldPath?.length) activeTab = "fields";
52
+ dataSourceConfig.value = activeTab ? config.map((item) => item.type === "tab" ? {
53
+ ...item,
54
+ active: activeTab
55
+ } : item) : config;
43
56
  });
44
57
  const submitHandler = (values, data) => {
45
58
  emit("submit", values, data);
@@ -7,7 +7,7 @@ import DataSourceConfigPanel_default from "./DataSourceConfigPanel.js";
7
7
  import DataSourceList_default from "./DataSourceList.js";
8
8
  import { useContentMenu } from "./useContentMenu.js";
9
9
  import { TMagicScrollbar, tMagicMessageBox } from "@tmagic/design";
10
- import { Fragment, Teleport, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createVNode, defineComponent, inject, openBlock, renderSlot, unref, useTemplateRef, watch, withCtx } from "vue";
10
+ import { Fragment, Teleport, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createVNode, defineComponent, inject, openBlock, ref, renderSlot, unref, useTemplateRef, watch, withCtx } from "vue";
11
11
  import { mergeWith } from "lodash-es";
12
12
  //#region packages/editor/src/layouts/sidebar/data-source/DataSourceListPanel.vue?vue&type=script&setup=true&lang.ts
13
13
  var _hoisted_1 = { class: "search-wrapper" };
@@ -24,7 +24,13 @@ var DataSourceListPanel_vue_vue_type_script_setup_true_lang_default = /* @__PURE
24
24
  const eventBus = inject("eventBus");
25
25
  const { dataSourceService } = useServices();
26
26
  const { editDialog, dataSourceValues, dialogTitle, editable, editHandler, submitDataSourceHandler } = useDataSourceEdit(dataSourceService);
27
+ /** 打开数据源详情时需要直接定位并打开的方法名,为空则正常展示「数据定义」tab */
28
+ const editMethodName = ref("");
29
+ /** 打开数据源详情时需要直接定位并打开的字段路径,为空则不自动打开字段配置 */
30
+ const editFieldPath = ref([]);
27
31
  const editDialogCloseHandler = () => {
32
+ editMethodName.value = "";
33
+ editFieldPath.value = [];
28
34
  if (dataSourceListRef.value) for (const [, status] of dataSourceListRef.value.nodeStatusMap.entries()) status.selected = false;
29
35
  };
30
36
  watch(dataSourceValues, (dataSourceValues) => {
@@ -62,6 +68,18 @@ var DataSourceListPanel_vue_vue_type_script_setup_true_lang_default = /* @__PURE
62
68
  dataSourceListRef.value?.filter(val);
63
69
  };
64
70
  eventBus?.on("edit-data-source", (id) => {
71
+ editMethodName.value = "";
72
+ editFieldPath.value = [];
73
+ editHandler(id);
74
+ });
75
+ eventBus?.on("edit-data-source-method", (id, methodName) => {
76
+ editMethodName.value = methodName;
77
+ editFieldPath.value = [];
78
+ editHandler(id);
79
+ });
80
+ eventBus?.on("edit-data-source-field", (id, fieldPath) => {
81
+ editMethodName.value = "";
82
+ editFieldPath.value = fieldPath;
65
83
  editHandler(id);
66
84
  });
67
85
  eventBus?.on("remove-data-source", (id) => {
@@ -110,12 +128,16 @@ var DataSourceListPanel_vue_vue_type_script_setup_true_lang_default = /* @__PURE
110
128
  disabled: !unref(editable),
111
129
  values: unref(dataSourceValues),
112
130
  title: unref(dialogTitle),
131
+ "edit-method-name": editMethodName.value,
132
+ "edit-field-path": editFieldPath.value,
113
133
  onSubmit: unref(submitDataSourceHandler),
114
134
  onClose: editDialogCloseHandler
115
135
  }, null, 8, [
116
136
  "disabled",
117
137
  "values",
118
138
  "title",
139
+ "edit-method-name",
140
+ "edit-field-path",
119
141
  "onSubmit"
120
142
  ]),
121
143
  (openBlock(), createBlock(Teleport, { to: "body" }, [menuData.value.length ? (openBlock(), createBlock(ContentMenu_default, {