@tmagic/editor 1.4.8 → 1.4.9

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 (143) hide show
  1. package/package.json +11 -11
  2. package/src/Editor.vue +211 -0
  3. package/src/components/CodeBlockEditor.vue +268 -0
  4. package/src/components/CodeParams.vue +60 -0
  5. package/src/components/ContentMenu.vue +193 -0
  6. package/src/components/FloatingBox.vue +178 -0
  7. package/src/components/Icon.vue +27 -0
  8. package/src/components/Resizer.vue +23 -0
  9. package/src/components/ScrollBar.vue +151 -0
  10. package/src/components/ScrollViewer.vue +128 -0
  11. package/src/components/SearchInput.vue +37 -0
  12. package/src/components/SplitView.vue +186 -0
  13. package/src/components/ToolButton.vue +138 -0
  14. package/src/components/Tree.vue +71 -0
  15. package/src/components/TreeNode.vue +150 -0
  16. package/src/editorProps.ts +117 -0
  17. package/src/fields/Code.vue +50 -0
  18. package/src/fields/CodeLink.vue +80 -0
  19. package/src/fields/CodeSelect.vue +132 -0
  20. package/src/fields/CodeSelectCol.vue +139 -0
  21. package/src/fields/DataSourceFieldSelect.vue +149 -0
  22. package/src/fields/DataSourceFields.vue +323 -0
  23. package/src/fields/DataSourceInput.vue +339 -0
  24. package/src/fields/DataSourceMethodSelect.vue +153 -0
  25. package/src/fields/DataSourceMethods.vue +104 -0
  26. package/src/fields/DataSourceMocks.vue +255 -0
  27. package/src/fields/DataSourceSelect.vue +98 -0
  28. package/src/fields/EventSelect.vue +375 -0
  29. package/src/fields/KeyValue.vue +137 -0
  30. package/src/fields/PageFragmentSelect.vue +63 -0
  31. package/src/fields/UISelect.vue +135 -0
  32. package/src/hooks/index.ts +24 -0
  33. package/src/hooks/use-code-block-edit.ts +83 -0
  34. package/src/hooks/use-data-source-edit.ts +46 -0
  35. package/src/hooks/use-data-source-method.ts +100 -0
  36. package/src/hooks/use-editor-content-height.ts +26 -0
  37. package/src/hooks/use-filter.ts +55 -0
  38. package/src/hooks/use-float-box.ts +76 -0
  39. package/src/hooks/use-getso.ts +35 -0
  40. package/src/hooks/use-next-float-box-position.ts +29 -0
  41. package/src/hooks/use-node-status.ts +48 -0
  42. package/src/hooks/use-stage.ts +129 -0
  43. package/src/hooks/use-window-rect.ts +20 -0
  44. package/src/icons/AppManageIcon.vue +15 -0
  45. package/src/icons/CenterIcon.vue +13 -0
  46. package/src/icons/CodeIcon.vue +28 -0
  47. package/src/icons/FolderMinusIcon.vue +22 -0
  48. package/src/icons/PinIcon.vue +25 -0
  49. package/src/icons/PinnedIcon.vue +25 -0
  50. package/src/index.ts +118 -0
  51. package/src/initService.ts +448 -0
  52. package/src/layouts/AddPageBox.vue +55 -0
  53. package/src/layouts/CodeEditor.vue +226 -0
  54. package/src/layouts/Framework.vue +163 -0
  55. package/src/layouts/NavMenu.vue +200 -0
  56. package/src/layouts/PropsPanel.vue +131 -0
  57. package/src/layouts/page-bar/AddButton.vue +48 -0
  58. package/src/layouts/page-bar/PageBar.vue +159 -0
  59. package/src/layouts/page-bar/PageBarScrollContainer.vue +156 -0
  60. package/src/layouts/page-bar/SwitchTypeButton.vue +45 -0
  61. package/src/layouts/sidebar/ComponentListPanel.vue +134 -0
  62. package/src/layouts/sidebar/Sidebar.vue +278 -0
  63. package/src/layouts/sidebar/code-block/CodeBlockList.vue +160 -0
  64. package/src/layouts/sidebar/code-block/CodeBlockListPanel.vue +70 -0
  65. package/src/layouts/sidebar/data-source/DataSourceConfigPanel.vue +84 -0
  66. package/src/layouts/sidebar/data-source/DataSourceList.vue +172 -0
  67. package/src/layouts/sidebar/data-source/DataSourceListPanel.vue +106 -0
  68. package/src/layouts/sidebar/layer/LayerMenu.vue +128 -0
  69. package/src/layouts/sidebar/layer/LayerNodeTool.vue +32 -0
  70. package/src/layouts/sidebar/layer/LayerPanel.vue +119 -0
  71. package/src/layouts/sidebar/layer/use-click.ts +113 -0
  72. package/src/layouts/sidebar/layer/use-drag.ts +167 -0
  73. package/src/layouts/sidebar/layer/use-keybinding.ts +54 -0
  74. package/src/layouts/sidebar/layer/use-node-status.ts +114 -0
  75. package/src/layouts/workspace/Breadcrumb.vue +35 -0
  76. package/src/layouts/workspace/Workspace.vue +46 -0
  77. package/src/layouts/workspace/viewer/NodeListMenu.vue +115 -0
  78. package/src/layouts/workspace/viewer/Stage.vue +246 -0
  79. package/src/layouts/workspace/viewer/StageOverlay.vue +68 -0
  80. package/src/layouts/workspace/viewer/ViewerMenu.vue +145 -0
  81. package/src/services/BaseService.ts +230 -0
  82. package/src/services/codeBlock.ts +327 -0
  83. package/src/services/componentList.ts +58 -0
  84. package/src/services/dataSource.ts +216 -0
  85. package/src/services/dep.ts +152 -0
  86. package/src/services/editor.ts +1135 -0
  87. package/src/services/events.ts +93 -0
  88. package/src/services/history.ts +126 -0
  89. package/src/services/keybinding.ts +220 -0
  90. package/src/services/props.ts +286 -0
  91. package/src/services/stageOverlay.ts +212 -0
  92. package/src/services/storage.ts +155 -0
  93. package/src/services/ui.ts +156 -0
  94. package/src/shims-vue.d.ts +6 -0
  95. package/src/theme/breadcrumb.scss +6 -0
  96. package/src/theme/code-block.scss +6 -0
  97. package/src/theme/code-editor.scss +38 -0
  98. package/src/theme/common/var.scss +14 -0
  99. package/src/theme/component-list-panel.scss +95 -0
  100. package/src/theme/content-menu.scss +76 -0
  101. package/src/theme/data-source-field.scss +12 -0
  102. package/src/theme/data-source-fields.scss +13 -0
  103. package/src/theme/data-source-input.scss +18 -0
  104. package/src/theme/data-source-methods.scss +13 -0
  105. package/src/theme/data-source.scss +28 -0
  106. package/src/theme/event.scss +37 -0
  107. package/src/theme/floating-box.scss +32 -0
  108. package/src/theme/framework.scss +69 -0
  109. package/src/theme/icon.scss +12 -0
  110. package/src/theme/index.scss +10 -0
  111. package/src/theme/key-value.scss +20 -0
  112. package/src/theme/layer-panel.scss +26 -0
  113. package/src/theme/layout.scss +9 -0
  114. package/src/theme/nav-menu.scss +78 -0
  115. package/src/theme/page-bar.scss +89 -0
  116. package/src/theme/page-fragment-select.scss +14 -0
  117. package/src/theme/props-panel.scss +55 -0
  118. package/src/theme/resizer.scss +66 -0
  119. package/src/theme/ruler.scss +38 -0
  120. package/src/theme/search-input.scss +14 -0
  121. package/src/theme/sidebar.scss +79 -0
  122. package/src/theme/stage.scss +76 -0
  123. package/src/theme/theme.scss +27 -0
  124. package/src/theme/tree.scss +89 -0
  125. package/src/theme/workspace.scss +9 -0
  126. package/src/type.ts +749 -0
  127. package/src/utils/compose.ts +52 -0
  128. package/src/utils/config.ts +29 -0
  129. package/src/utils/content-menu.ts +95 -0
  130. package/src/utils/data-source/formConfigs/base.ts +30 -0
  131. package/src/utils/data-source/formConfigs/http.ts +60 -0
  132. package/src/utils/data-source/index.ts +243 -0
  133. package/src/utils/editor.ts +313 -0
  134. package/src/utils/idle-task.ts +72 -0
  135. package/src/utils/index.ts +24 -0
  136. package/src/utils/keybinding-config.ts +125 -0
  137. package/src/utils/logger.ts +47 -0
  138. package/src/utils/monaco-editor.ts +8 -0
  139. package/src/utils/operator.ts +106 -0
  140. package/src/utils/props.ts +504 -0
  141. package/src/utils/scroll-viewer.ts +165 -0
  142. package/src/utils/tree.ts +15 -0
  143. package/src/utils/undo-redo.ts +76 -0
@@ -0,0 +1,50 @@
1
+ <template>
2
+ <MagicCodeEditor
3
+ :height="config.height"
4
+ :init-values="model[name]"
5
+ :language="config.language"
6
+ :options="{
7
+ ...config.options,
8
+ readOnly: disabled,
9
+ }"
10
+ :parse="config.parse"
11
+ @save="save"
12
+ ></MagicCodeEditor>
13
+ </template>
14
+
15
+ <script lang="ts" setup>
16
+ import type { FieldProps, FormItem } from '@tmagic/form';
17
+
18
+ import MagicCodeEditor from '@editor/layouts/CodeEditor.vue';
19
+
20
+ defineOptions({
21
+ name: 'MFieldsVsCode',
22
+ });
23
+
24
+ const emit = defineEmits<{
25
+ change: [value: string | any];
26
+ }>();
27
+
28
+ const props = withDefaults(
29
+ defineProps<
30
+ FieldProps<
31
+ {
32
+ language?: string;
33
+ options?: {
34
+ [key: string]: any;
35
+ };
36
+ height?: string;
37
+ parse?: boolean;
38
+ } & FormItem
39
+ >
40
+ >(),
41
+ {
42
+ disabled: false,
43
+ },
44
+ );
45
+
46
+ const save = (v: string | any) => {
47
+ props.model[props.name] = v;
48
+ emit('change', v);
49
+ };
50
+ </script>
@@ -0,0 +1,80 @@
1
+ <template>
2
+ <m-fields-link :config="formConfig" :model="modelValue" name="form" @change="changeHandler"></m-fields-link>
3
+ </template>
4
+
5
+ <script lang="ts" setup>
6
+ import { computed, reactive, watch } from 'vue';
7
+ import serialize from 'serialize-javascript';
8
+
9
+ import type { FieldProps, FormItem } from '@tmagic/form';
10
+
11
+ import { getConfig } from '@editor/utils/config';
12
+
13
+ defineOptions({
14
+ name: 'MFieldsCodeLink',
15
+ });
16
+
17
+ const props = defineProps<
18
+ FieldProps<
19
+ {
20
+ type: 'code-link';
21
+ formTitle?: string;
22
+ codeOptions?: Object;
23
+ } & FormItem
24
+ >
25
+ >();
26
+
27
+ const emit = defineEmits(['change']);
28
+
29
+ const formConfig = computed(() => {
30
+ const { codeOptions, ...config } = props.config;
31
+ return {
32
+ ...config,
33
+ text: '',
34
+ type: 'link',
35
+ form: [
36
+ {
37
+ name: props.name,
38
+ type: 'vs-code',
39
+ options: {
40
+ tabSize: 2,
41
+ ...(codeOptions || {}),
42
+ },
43
+ },
44
+ ],
45
+ };
46
+ });
47
+
48
+ const modelValue = reactive<{ form: Record<string, string> }>({
49
+ form: {
50
+ [props.name]: '',
51
+ },
52
+ });
53
+
54
+ watch(
55
+ () => props.model[props.name],
56
+ (value) => {
57
+ modelValue.form = {
58
+ [props.name]: serialize(value, {
59
+ space: 2,
60
+ unsafe: true,
61
+ }).replace(/"(\w+)":\s/g, '$1: '),
62
+ };
63
+ },
64
+ {
65
+ immediate: true,
66
+ },
67
+ );
68
+
69
+ const changeHandler = (v: Record<string, any>) => {
70
+ if (!props.name || !props.model) return;
71
+
72
+ try {
73
+ const parseDSL = getConfig('parseDSL');
74
+ props.model[props.name] = parseDSL(`(${v[props.name]})`);
75
+ emit('change', props.model[props.name]);
76
+ } catch (e) {
77
+ console.error(e);
78
+ }
79
+ };
80
+ </script>
@@ -0,0 +1,132 @@
1
+ <template>
2
+ <div class="m-fields-code-select" :class="config.className">
3
+ <TMagicCard>
4
+ <MContainer
5
+ :config="codeConfig"
6
+ :size="size"
7
+ :prop="prop"
8
+ :disabled="disabled"
9
+ :lastValues="lastValues"
10
+ :model="model[name]"
11
+ @change="changeHandler"
12
+ >
13
+ </MContainer>
14
+ </TMagicCard>
15
+ </div>
16
+ </template>
17
+
18
+ <script lang="ts" setup>
19
+ import { computed, inject, watch } from 'vue';
20
+ import { isEmpty } from 'lodash-es';
21
+
22
+ import { TMagicCard } from '@tmagic/design';
23
+ import type { FieldProps, FormItem } from '@tmagic/form';
24
+ import { FormState, MContainer } from '@tmagic/form';
25
+ import { HookCodeType, HookType } from '@tmagic/schema';
26
+
27
+ import type { Services } from '@editor/type';
28
+
29
+ defineOptions({
30
+ name: 'MFieldsCodeSelect',
31
+ });
32
+
33
+ const emit = defineEmits(['change']);
34
+
35
+ const services = inject<Services>('services');
36
+
37
+ const props = withDefaults(
38
+ defineProps<
39
+ FieldProps<
40
+ {
41
+ className?: string;
42
+ } & FormItem
43
+ >
44
+ >(),
45
+ {},
46
+ );
47
+
48
+ const codeConfig = computed(() => ({
49
+ type: 'group-list',
50
+ name: 'hookData',
51
+ enableToggleMode: false,
52
+ expandAll: true,
53
+ title: (mForm: FormState, { model, index }: any) => {
54
+ if (model.codeType === HookCodeType.DATA_SOURCE_METHOD) {
55
+ if (Array.isArray(model.codeId)) {
56
+ if (model.codeId.length < 2) {
57
+ return index;
58
+ }
59
+
60
+ const ds = services?.dataSourceService.getDataSourceById(model.codeId[0]);
61
+ return `${ds?.title} / ${model.codeId[1]}`;
62
+ }
63
+
64
+ return Array.isArray(model.codeId) ? model.codeId.join('/') : index;
65
+ }
66
+ return model.codeId || index;
67
+ },
68
+ items: [
69
+ {
70
+ type: 'row',
71
+ items: [
72
+ {
73
+ type: 'select',
74
+ name: 'codeType',
75
+ span: 8,
76
+ options: [
77
+ { value: HookCodeType.CODE, text: '代码块' },
78
+ { value: HookCodeType.DATA_SOURCE_METHOD, text: '数据源方法' },
79
+ ],
80
+ defaultValue: 'code',
81
+ onChange: (mForm: FormState, v: HookCodeType, { model }: any) => {
82
+ if (v === HookCodeType.DATA_SOURCE_METHOD) {
83
+ model.codeId = [];
84
+ } else {
85
+ model.codeId = '';
86
+ }
87
+
88
+ return v;
89
+ },
90
+ },
91
+ {
92
+ type: 'code-select-col',
93
+ name: 'codeId',
94
+ span: 16,
95
+ labelWidth: 0,
96
+ display: (mForm: FormState, { model }: any) => model.codeType !== HookCodeType.DATA_SOURCE_METHOD,
97
+ notEditable: () => !services?.codeBlockService.getEditStatus(),
98
+ },
99
+ {
100
+ type: 'data-source-method-select',
101
+ name: 'codeId',
102
+ span: 16,
103
+ labelWidth: 0,
104
+ display: (mForm: FormState, { model }: any) => model.codeType === HookCodeType.DATA_SOURCE_METHOD,
105
+ notEditable: () => !services?.dataSourceService.get('editable'),
106
+ },
107
+ ],
108
+ },
109
+ ],
110
+ }));
111
+
112
+ watch(
113
+ () => props.model[props.name],
114
+ (value) => {
115
+ // 兼容旧的数据结构
116
+ if (isEmpty(value)) {
117
+ // 空值或者空数组
118
+ props.model[props.name] = {
119
+ hookType: HookType.CODE,
120
+ hookData: [],
121
+ };
122
+ }
123
+ },
124
+ {
125
+ immediate: true,
126
+ },
127
+ );
128
+
129
+ const changeHandler = async () => {
130
+ emit('change', props.model[props.name]);
131
+ };
132
+ </script>
@@ -0,0 +1,139 @@
1
+ <template>
2
+ <div class="m-fields-code-select-col">
3
+ <div class="code-select-container">
4
+ <!-- 代码块下拉框 -->
5
+ <MContainer
6
+ class="select"
7
+ :config="selectConfig"
8
+ :model="model"
9
+ :size="size"
10
+ @change="onParamsChangeHandler"
11
+ ></MContainer>
12
+
13
+ <!-- 查看/编辑按钮 -->
14
+ <TMagicButton
15
+ v-if="model[name] && hasCodeBlockSidePanel"
16
+ class="m-fields-select-action-button"
17
+ :size="size"
18
+ @click="editCode(model[name])"
19
+ >
20
+ <MIcon :icon="!notEditable ? Edit : View"></MIcon>
21
+ </TMagicButton>
22
+ </div>
23
+
24
+ <!-- 参数填写框 -->
25
+ <CodeParams
26
+ v-if="paramsConfig.length"
27
+ name="params"
28
+ :key="model[name]"
29
+ :model="model"
30
+ :size="size"
31
+ :params-config="paramsConfig"
32
+ @change="onParamsChangeHandler"
33
+ ></CodeParams>
34
+ </div>
35
+ </template>
36
+
37
+ <script lang="ts" setup>
38
+ import { computed, inject, ref, watch } from 'vue';
39
+ import { Edit, View } from '@element-plus/icons-vue';
40
+ import { isEmpty, map } from 'lodash-es';
41
+
42
+ import { TMagicButton } from '@tmagic/design';
43
+ import { createValues, type FieldProps, filterFunction, type FormState, MContainer } from '@tmagic/form';
44
+ import type { Id } from '@tmagic/schema';
45
+
46
+ import CodeParams from '@editor/components/CodeParams.vue';
47
+ import MIcon from '@editor/components/Icon.vue';
48
+ import type { CodeParamStatement, CodeSelectColConfig, EventBus, Services } from '@editor/type';
49
+ import { SideItemKey } from '@editor/type';
50
+
51
+ defineOptions({
52
+ name: 'MFieldsCodeSelectCol',
53
+ });
54
+
55
+ const mForm = inject<FormState | undefined>('mForm');
56
+ const services = inject<Services>('services');
57
+ const eventBus = inject<EventBus>('eventBus');
58
+ const emit = defineEmits(['change']);
59
+
60
+ const props = withDefaults(defineProps<FieldProps<CodeSelectColConfig>>(), {
61
+ disabled: false,
62
+ });
63
+
64
+ const notEditable = computed(() => filterFunction(mForm, props.config.notEditable, props));
65
+
66
+ const hasCodeBlockSidePanel = computed(() =>
67
+ (services?.uiService.get('sideBarItems') || []).find((item) => item.$key === SideItemKey.CODE_BLOCK),
68
+ );
69
+
70
+ /**
71
+ * 根据代码块id获取代码块参数配置
72
+ * @param codeId 代码块ID
73
+ */
74
+ const getParamItemsConfig = (codeId?: Id): CodeParamStatement[] => {
75
+ if (!codeDsl.value || !codeId) return [];
76
+
77
+ const paramStatements = codeDsl.value[codeId]?.params;
78
+
79
+ if (isEmpty(paramStatements)) return [];
80
+
81
+ return paramStatements.map((paramState: CodeParamStatement) => ({
82
+ labelWidth: '100px',
83
+ text: paramState.name,
84
+ ...paramState,
85
+ }));
86
+ };
87
+
88
+ const codeDsl = computed(() => services?.codeBlockService.getCodeDsl());
89
+ const paramsConfig = ref<CodeParamStatement[]>(getParamItemsConfig(props.model[props.name]));
90
+
91
+ watch(
92
+ () => props.model[props.name],
93
+ (v, preV) => {
94
+ if (v !== preV) {
95
+ paramsConfig.value = getParamItemsConfig(v);
96
+ }
97
+ },
98
+ );
99
+
100
+ const selectConfig = {
101
+ type: 'select',
102
+ name: props.name,
103
+ disable: props.disabled,
104
+ options: () => {
105
+ if (codeDsl.value) {
106
+ return map(codeDsl.value, (value, key) => ({
107
+ text: `${value.name}(${key})`,
108
+ label: `${value.name}(${key})`,
109
+ value: key,
110
+ }));
111
+ }
112
+ return [];
113
+ },
114
+ onChange: (formState: any, codeId: Id, { model }: any) => {
115
+ // 通过下拉框选择的codeId变化后修正model的值,避免写入其他codeId的params
116
+ paramsConfig.value = getParamItemsConfig(codeId);
117
+
118
+ if (paramsConfig.value.length) {
119
+ model.params = createValues(formState, paramsConfig.value, {}, model.params);
120
+ } else {
121
+ model.params = {};
122
+ }
123
+
124
+ return codeId;
125
+ },
126
+ };
127
+
128
+ /**
129
+ * 参数值修改更新
130
+ */
131
+ const onParamsChangeHandler = (value: any) => {
132
+ props.model.params = value.params;
133
+ emit('change', props.model);
134
+ };
135
+
136
+ const editCode = (id: string) => {
137
+ eventBus?.emit('edit-code', id);
138
+ };
139
+ </script>
@@ -0,0 +1,149 @@
1
+ <template>
2
+ <div class="m-fields-data-source-field-select">
3
+ <component
4
+ :is="tagName"
5
+ :config="showDataSourceFieldSelect || !config.fieldConfig ? cascaderConfig : config.fieldConfig"
6
+ :model="model"
7
+ :name="name"
8
+ :disabled="disabled"
9
+ :size="size"
10
+ :last-values="lastValues"
11
+ :init-values="initValues"
12
+ :values="values"
13
+ :prop="`${prop}${prop ? '.' : ''}${name}`"
14
+ @change="onChangeHandler"
15
+ ></component>
16
+
17
+ <TMagicButton
18
+ v-if="(showDataSourceFieldSelect || !config.fieldConfig) && selectedDataSourceId && hasDataSourceSidePanel"
19
+ class="m-fields-select-action-button"
20
+ :size="size"
21
+ @click="editHandler(selectedDataSourceId)"
22
+ ><MIcon :icon="!notEditable ? Edit : View"></MIcon
23
+ ></TMagicButton>
24
+
25
+ <TMagicButton
26
+ v-if="config.fieldConfig"
27
+ style="margin-left: 5px"
28
+ :type="showDataSourceFieldSelect ? 'primary' : 'default'"
29
+ :size="size"
30
+ @click="showDataSourceFieldSelect = !showDataSourceFieldSelect"
31
+ ><MIcon :icon="Coin"></MIcon
32
+ ></TMagicButton>
33
+ </div>
34
+ </template>
35
+
36
+ <script setup lang="ts">
37
+ import { computed, inject, ref, resolveComponent, watch } from 'vue';
38
+ import { Coin, Edit, View } from '@element-plus/icons-vue';
39
+
40
+ import { TMagicButton } from '@tmagic/design';
41
+ import type { CascaderConfig, FieldProps, FormState } from '@tmagic/form';
42
+ import { filterFunction, MCascader } from '@tmagic/form';
43
+ import { DATA_SOURCE_FIELDS_SELECT_VALUE_PREFIX } from '@tmagic/utils';
44
+
45
+ import MIcon from '@editor/components/Icon.vue';
46
+ import type { DataSourceFieldSelectConfig, EventBus, Services } from '@editor/type';
47
+ import { SideItemKey } from '@editor/type';
48
+ import { getCascaderOptionsFromFields } from '@editor/utils';
49
+
50
+ defineOptions({
51
+ name: 'MFieldsDataSourceFieldSelect',
52
+ });
53
+
54
+ const services = inject<Services>('services');
55
+ const eventBus = inject<EventBus>('eventBus');
56
+ const emit = defineEmits(['change']);
57
+
58
+ const props = withDefaults(defineProps<FieldProps<DataSourceFieldSelectConfig>>(), {
59
+ disabled: false,
60
+ });
61
+
62
+ const notEditable = computed(() => filterFunction(mForm, props.config.notEditable, props));
63
+
64
+ const hasDataSourceSidePanel = computed(() =>
65
+ (services?.uiService.get('sideBarItems') || []).find((item) => item.$key === SideItemKey.DATA_SOURCE),
66
+ );
67
+
68
+ const selectedDataSourceId = computed(() => {
69
+ const value = props.model[props.name];
70
+ if (!Array.isArray(value) || !value.length) {
71
+ return '';
72
+ }
73
+
74
+ return value[0].replace(DATA_SOURCE_FIELDS_SELECT_VALUE_PREFIX, '');
75
+ });
76
+
77
+ const dataSources = computed(() => services?.dataSourceService.get('dataSources'));
78
+
79
+ const cascaderConfig = computed<CascaderConfig>(() => {
80
+ const valueIsKey = props.config.value === 'key';
81
+
82
+ return {
83
+ type: 'cascader',
84
+ checkStrictly: props.config.checkStrictly ?? !valueIsKey,
85
+ popperClass: 'm-editor-data-source-field-select-popper',
86
+ options: () => {
87
+ const options =
88
+ dataSources.value?.map((ds) => ({
89
+ label: ds.title || ds.id,
90
+ value: valueIsKey ? ds.id : `${DATA_SOURCE_FIELDS_SELECT_VALUE_PREFIX}${ds.id}`,
91
+ children: getCascaderOptionsFromFields(ds.fields, props.config.dataSourceFieldType),
92
+ })) || [];
93
+ return options.filter((option) => option.children.length);
94
+ },
95
+ };
96
+ });
97
+
98
+ const showDataSourceFieldSelect = ref(false);
99
+
100
+ watch(
101
+ () => props.model[props.name],
102
+ (value) => {
103
+ if (
104
+ Array.isArray(value) &&
105
+ typeof value[0] === 'string' &&
106
+ value[0].startsWith(DATA_SOURCE_FIELDS_SELECT_VALUE_PREFIX)
107
+ ) {
108
+ showDataSourceFieldSelect.value = true;
109
+ } else {
110
+ showDataSourceFieldSelect.value = false;
111
+ }
112
+ },
113
+ {
114
+ immediate: true,
115
+ },
116
+ );
117
+
118
+ const mForm = inject<FormState | undefined>('mForm');
119
+
120
+ const type = computed((): string => {
121
+ let type = props.config.fieldConfig?.type;
122
+ if (typeof type === 'function') {
123
+ type = type(mForm, {
124
+ model: props.model,
125
+ });
126
+ }
127
+ if (type === 'form') return '';
128
+ if (type === 'container') return '';
129
+ return type?.replace(/([A-Z])/g, '-$1').toLowerCase() || (props.config.items ? '' : 'text');
130
+ });
131
+
132
+ const tagName = computed(() => {
133
+ if (showDataSourceFieldSelect.value || !props.config.fieldConfig) {
134
+ return MCascader;
135
+ }
136
+
137
+ const component = resolveComponent(`m-${props.config.items ? 'form' : 'fields'}-${type.value}`);
138
+ if (typeof component !== 'string') return component;
139
+ return 'm-fields-text';
140
+ });
141
+
142
+ const onChangeHandler = (value: any) => {
143
+ emit('change', value);
144
+ };
145
+
146
+ const editHandler = (id: string) => {
147
+ eventBus?.emit('edit-data-source', id);
148
+ };
149
+ </script>