@tmagic/editor 1.5.15 → 1.5.17

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.
@@ -26,7 +26,7 @@ import { cloneDeep } from 'lodash-es';
26
26
 
27
27
  import type { CodeBlockContent } from '@tmagic/core';
28
28
  import { TMagicButton, tMagicMessageBox } from '@tmagic/design';
29
- import type { ContainerChangeEventData, FieldProps } from '@tmagic/form';
29
+ import type { ContainerChangeEventData, DataSourceMethodsConfig, FieldProps } from '@tmagic/form';
30
30
  import { type ColumnConfig, MagicTable } from '@tmagic/table';
31
31
 
32
32
  import CodeBlockEditor from '@editor/components/CodeBlockEditor.vue';
@@ -37,16 +37,9 @@ defineOptions({
37
37
  name: 'MFieldsDataSourceMethods',
38
38
  });
39
39
 
40
- const props = withDefaults(
41
- defineProps<
42
- FieldProps<{
43
- type: 'data-source-methods';
44
- }>
45
- >(),
46
- {
47
- disabled: false,
48
- },
49
- );
40
+ const props = withDefaults(defineProps<FieldProps<DataSourceMethodsConfig>>(), {
41
+ disabled: false,
42
+ });
50
43
 
51
44
  const emit = defineEmits(['change']);
52
45
 
@@ -32,7 +32,7 @@ import { inject, Ref, ref } from 'vue';
32
32
 
33
33
  import type { MockSchema } from '@tmagic/core';
34
34
  import { TMagicButton, tMagicMessageBox, TMagicSwitch } from '@tmagic/design';
35
- import { type FieldProps, type FormConfig, type FormState, MFormBox } from '@tmagic/form';
35
+ import { type DataSourceMocksConfig, type FieldProps, type FormConfig, type FormState, MFormBox } from '@tmagic/form';
36
36
  import { type ColumnConfig, MagicTable } from '@tmagic/table';
37
37
  import { getDefaultValueFromFields } from '@tmagic/utils';
38
38
 
@@ -47,16 +47,9 @@ defineOptions({
47
47
  name: 'MFieldsDataSourceMocks',
48
48
  });
49
49
 
50
- const props = withDefaults(
51
- defineProps<
52
- FieldProps<{
53
- type: 'data-source-mocks';
54
- }>
55
- >(),
56
- {
57
- disabled: false,
58
- },
59
- );
50
+ const props = withDefaults(defineProps<FieldProps<DataSourceMocksConfig>>(), {
51
+ disabled: false,
52
+ });
60
53
 
61
54
  const emit = defineEmits(['change']);
62
55
 
@@ -24,11 +24,18 @@ import { computed, inject } from 'vue';
24
24
  import { Edit, View } from '@element-plus/icons-vue';
25
25
 
26
26
  import { TMagicButton, TMagicTooltip } from '@tmagic/design';
27
- import { type FieldProps, filterFunction, type FormState, MSelect, type SelectConfig } from '@tmagic/form';
27
+ import {
28
+ type DataSourceSelect,
29
+ type FieldProps,
30
+ filterFunction,
31
+ type FormState,
32
+ MSelect,
33
+ type SelectConfig,
34
+ } from '@tmagic/form';
28
35
 
29
36
  import MIcon from '@editor/components/Icon.vue';
30
37
  import { useServices } from '@editor/hooks/use-services';
31
- import type { DataSourceSelect, EventBus } from '@editor/type';
38
+ import type { EventBus } from '@editor/type';
32
39
  import { SideItemKey } from '@editor/type';
33
40
 
34
41
  defineOptions({
@@ -18,8 +18,8 @@ import { computed, inject } from 'vue';
18
18
  import type { DisplayCond } from '@tmagic/core';
19
19
  import {
20
20
  type ContainerChangeEventData,
21
+ type DisplayCondsConfig,
21
22
  type FieldProps,
22
- type FilterFunction,
23
23
  filterFunction,
24
24
  type FormState,
25
25
  type GroupListConfig,
@@ -37,17 +37,9 @@ const emit = defineEmits<{
37
37
  change: [value: DisplayCond[], eventData?: ContainerChangeEventData];
38
38
  }>();
39
39
 
40
- const props = withDefaults(
41
- defineProps<
42
- FieldProps<{
43
- titlePrefix?: string;
44
- parentFields?: string[] | FilterFunction<string[]>;
45
- }>
46
- >(),
47
- {
48
- disabled: false,
49
- },
50
- );
40
+ const props = withDefaults(defineProps<FieldProps<DisplayCondsConfig>>(), {
41
+ disabled: false,
42
+ });
51
43
 
52
44
  const { dataSourceService } = useServices();
53
45
  const mForm = inject<FormState | undefined>('mForm');
@@ -60,7 +60,10 @@ import { TMagicButton } from '@tmagic/design';
60
60
  import type {
61
61
  CascaderOption,
62
62
  ChildConfig,
63
+ CodeSelectColConfig,
63
64
  ContainerChangeEventData,
65
+ DataSourceMethodSelectConfig,
66
+ EventSelectConfig,
64
67
  FieldProps,
65
68
  FormState,
66
69
  OnChangeHandlerData,
@@ -70,7 +73,6 @@ import { MContainer as MFormContainer, MPanel } from '@tmagic/form';
70
73
  import { DATA_SOURCE_FIELDS_CHANGE_EVENT_PREFIX, traverseNode } from '@tmagic/utils';
71
74
 
72
75
  import { useServices } from '@editor/hooks/use-services';
73
- import type { CodeSelectColConfig, DataSourceMethodSelectConfig, EventSelectConfig } from '@editor/type';
74
76
  import { getCascaderOptionsFromFields } from '@editor/utils';
75
77
 
76
78
  defineOptions({
@@ -63,7 +63,7 @@ import { ref, watchEffect } from 'vue';
63
63
  import { Delete, Plus } from '@element-plus/icons-vue';
64
64
 
65
65
  import { TMagicButton, TMagicInput } from '@tmagic/design';
66
- import type { FieldProps, FormItem } from '@tmagic/form';
66
+ import type { FieldProps, KeyValueConfig } from '@tmagic/form';
67
67
 
68
68
  import CodeIcon from '@editor/icons/CodeIcon.vue';
69
69
  import MagicCodeEditor from '@editor/layouts/CodeEditor.vue';
@@ -72,19 +72,9 @@ defineOptions({
72
72
  name: 'MFieldsKeyValue',
73
73
  });
74
74
 
75
- const props = withDefaults(
76
- defineProps<
77
- FieldProps<
78
- {
79
- type: 'key-value';
80
- advanced?: boolean;
81
- } & FormItem
82
- >
83
- >(),
84
- {
85
- disabled: false,
86
- },
87
- );
75
+ const props = withDefaults(defineProps<FieldProps<KeyValueConfig>>(), {
76
+ disabled: false,
77
+ });
88
78
 
89
79
  const emit = defineEmits<{
90
80
  change: [value: Record<string, any>];
@@ -20,11 +20,10 @@ import { computed } from 'vue';
20
20
  import { Edit } from '@element-plus/icons-vue';
21
21
 
22
22
  import { Id, NodeType } from '@tmagic/core';
23
- import { FieldProps } from '@tmagic/form';
23
+ import { FieldProps, type PageFragmentSelectConfig } from '@tmagic/form';
24
24
 
25
25
  import Icon from '@editor/components/Icon.vue';
26
26
  import { useServices } from '@editor/hooks/use-services';
27
- import type { PageFragmentSelectConfig } from '@editor/type';
28
27
 
29
28
  defineOptions({
30
29
  name: 'MFieldsPageFragmentSelect',
@@ -47,7 +47,7 @@ import { throttle } from 'lodash-es';
47
47
 
48
48
  import type { Id, MNode } from '@tmagic/core';
49
49
  import { TMagicButton, TMagicTooltip } from '@tmagic/design';
50
- import type { FieldProps, FormItem, FormState } from '@tmagic/form';
50
+ import type { FieldProps, FormState, UISelectConfig } from '@tmagic/form';
51
51
  import { getIdFromEl } from '@tmagic/utils';
52
52
 
53
53
  import { useServices } from '@editor/hooks/use-services';
@@ -57,7 +57,7 @@ defineOptions({
57
57
  name: 'MFieldsUISelect',
58
58
  });
59
59
 
60
- const props = defineProps<FieldProps<{ type: 'ui-select' } & FormItem>>();
60
+ const props = defineProps<FieldProps<UISelectConfig>>();
61
61
 
62
62
  const emit = defineEmits(['change']);
63
63
 
@@ -278,20 +278,21 @@ export const initServiceEvents = (
278
278
  });
279
279
  };
280
280
 
281
+ const getPageIdByNode = (node: MComponent) => {
282
+ let pageId: Id | undefined;
283
+
284
+ if (isPage(node)) {
285
+ pageId = node.id;
286
+ } else {
287
+ const info = editorService.getNodeInfo(node.id);
288
+ pageId = info.page?.id;
289
+ }
290
+
291
+ return pageId;
292
+ };
293
+
281
294
  const collectIdle = (nodes: MComponent[], deep: boolean, type?: DepTargetType) =>
282
- Promise.all(
283
- nodes.map((node) => {
284
- let pageId: Id | undefined;
285
-
286
- if (isPage(node)) {
287
- pageId = node.id;
288
- } else {
289
- const info = editorService.getNodeInfo(node.id);
290
- pageId = info.page?.id;
291
- }
292
- return depService.collectIdle([node], { pageId }, deep, type);
293
- }),
294
- );
295
+ Promise.all(nodes.map((node) => depService.collectIdle([node], { pageId: getPageIdByNode(node) }, deep, type)));
295
296
 
296
297
  watch(
297
298
  () => editorService.get('stage'),
@@ -338,7 +339,8 @@ export const initServiceEvents = (
338
339
 
339
340
  if (Array.isArray(value.items)) {
340
341
  depService.clearIdleTasks();
341
- collectIdle(value.items, true).then(() => {
342
+
343
+ (typeof Worker === 'undefined' ? collectIdle(value.items, true) : depService.collectByWorker(value)).then(() => {
342
344
  updateStageNodes(value.items);
343
345
  });
344
346
  } else {
@@ -629,16 +631,12 @@ export const initServiceEvents = (
629
631
  root.dataSourceDeps = {};
630
632
  }
631
633
  root.dataSourceDeps[target.id] = target.deps;
632
- }
633
-
634
- if (target.type === DepTargetType.DATA_SOURCE_COND) {
634
+ } else if (target.type === DepTargetType.DATA_SOURCE_COND) {
635
635
  if (!root.dataSourceCondDeps) {
636
636
  root.dataSourceCondDeps = {};
637
637
  }
638
638
  root.dataSourceCondDeps[target.id] = target.deps;
639
- }
640
-
641
- if (target.type === DepTargetType.DATA_SOURCE_METHOD) {
639
+ } else if (target.type === DepTargetType.DATA_SOURCE_METHOD) {
642
640
  if (!root.dataSourceMethodDeps) {
643
641
  root.dataSourceMethodDeps = {};
644
642
  }
@@ -17,12 +17,14 @@
17
17
  */
18
18
  import { reactive, shallowReactive } from 'vue';
19
19
  import { throttle } from 'lodash-es';
20
+ import serialize from 'serialize-javascript';
20
21
 
21
- import type { DepExtendedData, Id, MNode, Target, TargetNode } from '@tmagic/core';
22
- import { DepTargetType, Watcher } from '@tmagic/core';
22
+ import type { DepData, DepExtendedData, Id, MApp, MNode, Target, TargetNode } from '@tmagic/core';
23
+ import { DepTargetType, traverseTarget, Watcher } from '@tmagic/core';
23
24
  import { isPage } from '@tmagic/utils';
24
25
 
25
- import { IdleTask } from '@editor/utils/idle-task';
26
+ import { IdleTask } from '@editor/utils/dep/idle-task';
27
+ import Work from '@editor/utils/dep/worker.ts?worker&inline';
26
28
 
27
29
  import BaseService from './BaseService';
28
30
 
@@ -50,6 +52,8 @@ class Dep extends BaseService {
50
52
 
51
53
  private watcher = new Watcher({ initialTargets: reactive({}) });
52
54
 
55
+ private waitingWorker?: Promise<void>;
56
+
53
57
  constructor() {
54
58
  super();
55
59
 
@@ -114,7 +118,11 @@ class Dep extends BaseService {
114
118
  this.emit('ds-collected', nodes, deep);
115
119
  }
116
120
 
117
- public collectIdle(nodes: MNode[], depExtendedData: DepExtendedData = {}, deep = false, type?: DepTargetType) {
121
+ public async collectIdle(nodes: MNode[], depExtendedData: DepExtendedData = {}, deep = false, type?: DepTargetType) {
122
+ if (this.waitingWorker) {
123
+ await this.waitingWorker;
124
+ }
125
+
118
126
  this.set('collecting', true);
119
127
  let startTask = false;
120
128
  this.watcher.collectByCallback(nodes, type, ({ node, target }) => {
@@ -141,6 +149,48 @@ class Dep extends BaseService {
141
149
  });
142
150
  }
143
151
 
152
+ public collectByWorker(dsl: MApp) {
153
+ this.set('collecting', true);
154
+
155
+ const { promise, resolve: waitingResolve } = Promise.withResolvers<void>();
156
+
157
+ this.waitingWorker = promise;
158
+
159
+ return new Promise<Record<string, Record<string, DepData>>>((resolve) => {
160
+ const worker = new Work();
161
+ worker.postMessage({
162
+ dsl: serialize(dsl),
163
+ });
164
+ worker.onmessage = (e) => {
165
+ resolve(e.data);
166
+ };
167
+ worker.onerror = () => {
168
+ resolve({});
169
+ };
170
+ }).then((depsData) => {
171
+ traverseTarget(this.watcher.getTargetsList(), (target) => {
172
+ if (depsData[target.type]?.[target.id]) {
173
+ target.deps = reactive(depsData[target.type][target.id]);
174
+
175
+ if (target.type === DepTargetType.DATA_SOURCE && dsl.dataSourceDeps) {
176
+ dsl.dataSourceDeps[target.id] = target.deps;
177
+ } else if (target.type === DepTargetType.DATA_SOURCE_COND && dsl.dataSourceCondDeps) {
178
+ dsl.dataSourceCondDeps[target.id] = target.deps;
179
+ } else if (target.type === DepTargetType.DATA_SOURCE_METHOD) {
180
+ dsl.dataSourceMethodDeps[target.id] = target.deps;
181
+ }
182
+ }
183
+ });
184
+
185
+ this.set('collecting', false);
186
+ this.emit('collected', dsl.items, true);
187
+ this.emit('ds-collected', dsl.items, true);
188
+ waitingResolve();
189
+
190
+ return depsData;
191
+ });
192
+ }
193
+
144
194
  public collectNode(node: MNode, target: Target, depExtendedData: DepExtendedData = {}, deep = false) {
145
195
  // 先删除原有依赖,重新收集
146
196
  if (isPage(node)) {
package/src/type.ts CHANGED
@@ -21,27 +21,8 @@ import type EventEmitter from 'events';
21
21
  import Sortable, { type Options, type SortableEvent } from 'sortablejs';
22
22
  import type { PascalCasedProperties } from 'type-fest';
23
23
 
24
- import type {
25
- CodeBlockContent,
26
- CodeBlockDSL,
27
- DataSourceFieldType,
28
- DataSourceSchema,
29
- Id,
30
- MApp,
31
- MContainer,
32
- MNode,
33
- MPage,
34
- MPageFragment,
35
- } from '@tmagic/core';
36
- import type {
37
- ChildConfig,
38
- FilterFunction,
39
- FormConfig,
40
- FormItem,
41
- FormState,
42
- Input,
43
- TableColumnConfig,
44
- } from '@tmagic/form';
24
+ import type { CodeBlockContent, CodeBlockDSL, Id, MApp, MContainer, MNode, MPage, MPageFragment } from '@tmagic/core';
25
+ import type { FormConfig, TableColumnConfig } from '@tmagic/form';
45
26
  import type StageCore from '@tmagic/stage';
46
27
  import type {
47
28
  ContainerHighlightType,
@@ -562,25 +543,6 @@ export interface HistoryState {
562
543
  canUndo: boolean;
563
544
  }
564
545
 
565
- export interface EventSelectConfig {
566
- name: string;
567
- type: 'event-select';
568
- src: 'datasource' | 'component';
569
- labelWidth?: string;
570
- /** 事件名称表单配置 */
571
- eventNameConfig?: FormItem;
572
- /** 动作类型配置 */
573
- actionTypeConfig?: FormItem;
574
- /** 联动组件配置 */
575
- targetCompConfig?: FormItem;
576
- /** 联动组件动作配置 */
577
- compActionConfig?: FormItem;
578
- /** 联动代码配置 */
579
- codeActionConfig?: FormItem;
580
- /** 联动数据源配置 */
581
- dataSourceActionConfig?: FormItem;
582
- }
583
-
584
546
  export enum KeyBindingCommand {
585
547
  /** 复制 */
586
548
  COPY_NODE = 'tmagic-system-copy-node',
@@ -636,69 +598,6 @@ export interface KeyBindingCacheItem {
636
598
  bound: boolean;
637
599
  }
638
600
 
639
- export interface CodeSelectColConfig extends FormItem {
640
- type: 'code-select-col';
641
- /** 是否可以编辑代码块,disable表示的是是否可以选择代码块 */
642
- notEditable?: boolean | FilterFunction;
643
- }
644
-
645
- export interface PageFragmentSelectConfig extends FormItem {
646
- type: 'page-fragment-select';
647
- }
648
-
649
- export interface DataSourceSelect extends FormItem, Input {
650
- type: 'data-source-select';
651
- /** 数据源类型: base、http... */
652
- dataSourceType?: string;
653
- /** 是否要编译成数据源的data。
654
- * id: 不编译,就是要数据源id;
655
- * value: 要编译(数据源data)
656
- * */
657
- value?: 'id' | 'value';
658
- /** 是否可以编辑数据源,disable表示的是是否可以选择数据源 */
659
- notEditable?: boolean | FilterFunction;
660
- }
661
-
662
- export interface DataSourceMethodSelectConfig extends FormItem {
663
- type: 'data-source-method-select';
664
- /** 是否可以编辑数据源,disable表示的是是否可以选择数据源 */
665
- notEditable?: boolean | FilterFunction;
666
- }
667
-
668
- export interface DataSourceFieldSelectConfig extends FormItem {
669
- type: 'data-source-field-select';
670
- /**
671
- * 是否要编译成数据源的data。
672
- * key: 不编译,就是要数据源id和field name;
673
- * value: 要编译(数据源data[`${filed}`])
674
- * */
675
- value?: 'key' | 'value';
676
- /** 是否严格的遵守父子节点不互相关联 */
677
- checkStrictly?:
678
- | boolean
679
- | ((
680
- mForm: FormState | undefined,
681
- data: {
682
- model: Record<any, any>;
683
- values: Record<any, any>;
684
- parent?: Record<any, any>;
685
- formValue: Record<any, any>;
686
- prop: string;
687
- config: DataSourceFieldSelectConfig;
688
- dataSource?: DataSourceSchema;
689
- },
690
- ) => boolean);
691
- dataSourceFieldType?: DataSourceFieldType[];
692
- fieldConfig?: ChildConfig;
693
- /** 是否可以编辑数据源,disable表示的是是否可以选择数据源 */
694
- notEditable?: boolean | FilterFunction;
695
- }
696
-
697
- export interface CondOpSelectConfig extends FormItem {
698
- type: 'cond-op';
699
- parentFields?: string[];
700
- }
701
-
702
601
  /** 可新增的数据源类型选项 */
703
602
  export interface DatasourceTypeOption {
704
603
  /** 数据源类型 */
@@ -1,7 +1,7 @@
1
- import type { FormConfig } from '@tmagic/form';
1
+ import { defineFormConfig } from '@tmagic/form';
2
2
 
3
- export default function (): FormConfig {
4
- return [
3
+ export default () =>
4
+ defineFormConfig([
5
5
  {
6
6
  name: 'id',
7
7
  type: 'hidden',
@@ -26,5 +26,4 @@ export default function (): FormConfig {
26
26
  name: 'description',
27
27
  text: '描述',
28
28
  },
29
- ];
30
- }
29
+ ]);
@@ -1,6 +1,6 @@
1
- import { FormConfig } from '@tmagic/form';
1
+ import { defineFormConfig } from '@tmagic/form';
2
2
 
3
- export default [
3
+ export default defineFormConfig([
4
4
  {
5
5
  name: 'autoFetch',
6
6
  text: '自动请求',
@@ -59,4 +59,4 @@ export default [
59
59
  },
60
60
  ],
61
61
  },
62
- ] as FormConfig;
62
+ ]);
@@ -0,0 +1,63 @@
1
+ import {
2
+ createCodeBlockTarget,
3
+ createDataSourceCondTarget,
4
+ createDataSourceMethodTarget,
5
+ createDataSourceTarget,
6
+ type DepData,
7
+ DepTargetType,
8
+ type Id,
9
+ type MApp,
10
+ traverseTarget,
11
+ Watcher,
12
+ } from '@tmagic/core';
13
+
14
+ import { error } from '../logger';
15
+
16
+ onmessage = (e) => {
17
+ const watcher = new Watcher({ initialTargets: {} });
18
+
19
+ const { dsl } = e.data;
20
+
21
+ try {
22
+ // eslint-disable-next-line no-eval
23
+ const mApp: MApp = eval(`(${dsl})`);
24
+
25
+ if (!mApp) {
26
+ postMessage({});
27
+ }
28
+
29
+ if (mApp.codeBlocks) {
30
+ for (const [id, code] of Object.entries(mApp.codeBlocks)) {
31
+ watcher.addTarget(createCodeBlockTarget(id, code));
32
+ }
33
+ }
34
+
35
+ if (mApp.dataSources) {
36
+ for (const ds of mApp.dataSources) {
37
+ watcher.addTarget(createDataSourceTarget(ds, {}));
38
+ watcher.addTarget(createDataSourceMethodTarget(ds, {}));
39
+ watcher.addTarget(createDataSourceCondTarget(ds, {}));
40
+ }
41
+ }
42
+
43
+ watcher.collectByCallback(mApp.items, undefined, ({ node, target }) => {
44
+ watcher.collectItem(node, target, { pageId: node.id }, true);
45
+ });
46
+
47
+ const data: Record<string, Record<Id, DepData>> = {
48
+ [DepTargetType.DATA_SOURCE]: {},
49
+ [DepTargetType.DATA_SOURCE_METHOD]: {},
50
+ [DepTargetType.DATA_SOURCE_COND]: {},
51
+ [DepTargetType.CODE_BLOCK]: {},
52
+ };
53
+
54
+ traverseTarget(watcher.getTargetsList(), (target) => {
55
+ data[target.type][target.id] = target.deps;
56
+ });
57
+
58
+ postMessage(data);
59
+ } catch (e: any) {
60
+ error(e);
61
+ postMessage({});
62
+ }
63
+ };
@@ -22,7 +22,7 @@ export * from './logger';
22
22
  export * from './editor';
23
23
  export * from './operator';
24
24
  export * from './data-source';
25
- export * from './idle-task';
25
+ export * from './dep/idle-task';
26
26
  export * from './scroll-viewer';
27
27
  export * from './tree';
28
28
  export * from './undo-redo';