Skip to content

Commit de6da70

Browse files
authored
feat: add mcp tools for utils (opentiny#1627)
* feat: add mcp tools for utils * fix: optimize code * fix: review issue
1 parent 4ed9a3c commit de6da70

File tree

15 files changed

+652
-24
lines changed

15 files changed

+652
-24
lines changed

packages/plugins/bridge/index.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,15 @@
1212

1313
import entry from './src/Main.vue'
1414
import metaData from './meta'
15+
import mcp from './src/mcp'
16+
import useUtils from './src/js/useUtils'
1517
import './src/styles/vars.less'
1618

1719
export default {
1820
...metaData,
19-
entry
21+
entry,
22+
mcp,
23+
metas: [useUtils]
2024
}
25+
26+
export { useUtils }

packages/plugins/bridge/package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,9 @@
2626
"homepage": "https://opentiny.design/tiny-engine",
2727
"dependencies": {
2828
"@opentiny/tiny-engine-common": "workspace:*",
29-
"@opentiny/tiny-engine-meta-register": "workspace:*"
29+
"@opentiny/tiny-engine-meta-register": "workspace:*",
30+
"@opentiny/tiny-engine-utils": "workspace:*",
31+
"zod": "^3.25.76"
3032
},
3133
"devDependencies": {
3234
"@opentiny/tiny-engine-vite-plugin-meta-comments": "workspace:*",

packages/plugins/bridge/src/BridgeManage.vue

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030

3131
<script lang="ts">
3232
/* metaService: engine.plugins.bridge.BridgeManage */
33-
import { watchEffect, ref, reactive } from 'vue'
33+
import { ref, reactive, watch } from 'vue'
3434
import { Search } from '@opentiny/vue'
3535
import { iconSearch } from '@opentiny/vue-icon'
3636
import { SearchEmpty, SvgButton } from '@opentiny/tiny-engine-common'
@@ -43,8 +43,10 @@ import {
4343
setResource,
4444
setCategory,
4545
getType,
46-
setResourceNamesByType
46+
setResourceNamesByType,
47+
getResource
4748
} from './js/resource'
49+
import { getMetaApi, META_SERVICE } from '@opentiny/tiny-engine-meta-register'
4850
4951
export default {
5052
components: {
@@ -80,8 +82,27 @@ export default {
8082
list.value = filterResourceSearchValue(state.resourceList)
8183
}
8284
83-
watchEffect(async () => {
84-
refresh(props.name)
85+
watch(
86+
() => props.name,
87+
() => {
88+
refresh(props.name)
89+
},
90+
{ immediate: true }
91+
)
92+
93+
const { getUpdateCount, getLastOperation } = getMetaApi(META_SERVICE.UseUtils) || { getUpdateCount: ref(0) }
94+
watch(getUpdateCount, async () => {
95+
await refresh(props.name)
96+
97+
const { id, type } = getLastOperation()
98+
99+
if (['add', 'update'].includes(type) && String(id) === String(getResource()?.id)) {
100+
const editItem = state.resourceList.find((item) => String(item.id) === String(id))
101+
102+
if (editItem) {
103+
setResource(editItem)
104+
}
105+
}
85106
})
86107
87108
const add = (type) => {

packages/plugins/bridge/src/BridgeSetting.vue

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,13 @@ export default {
277277
setCategory(value)
278278
}
279279
280+
// 元服务上一次操作的数据为删除且删除当前编辑的数据,需要关闭当前面板
281+
watch(getMetaApi(META_SERVICE.UseUtils).getLastOperation, (lastOperation) => {
282+
if (lastOperation.type === 'delete' && lastOperation.id === getResource()?.id) {
283+
closePanel()
284+
}
285+
})
286+
280287
return {
281288
align,
282289
PLUGIN_NAME,

packages/plugins/bridge/src/Main.vue

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,16 @@
2020

2121
<script lang="ts">
2222
/* metaService: engine.plugins.bridge.Main */
23-
import { ref, reactive, computed, provide } from 'vue'
23+
import { ref, reactive, computed, provide, onActivated, type Ref } from 'vue'
2424
import { PluginPanel, SvgButton } from '@opentiny/tiny-engine-common'
25-
import { useLayout } from '@opentiny/tiny-engine-meta-register'
25+
import { useLayout, getMetaApi, META_SERVICE } from '@opentiny/tiny-engine-meta-register'
2626
import { RESOURCE_TYPE } from './js/resource'
2727
import BridgeManage from './BridgeManage.vue'
2828
import BridgeSetting, { openPanel, closePanel } from './BridgeSetting.vue'
2929
import { RESOURCE_TIP } from './js/resource'
3030
31+
type BridgeManageInstance = InstanceType<typeof BridgeManage>
32+
3133
/* metaComponent: engine.plugins.bridge */
3234
export default {
3335
components: {
@@ -41,9 +43,9 @@ export default {
4143
type: Array
4244
}
4345
},
44-
setup(props, { emit }) {
46+
setup(_props, { emit }) {
4547
const activedName = ref(RESOURCE_TYPE.Util)
46-
const utilsRef = ref(null)
48+
const utilsRef: Ref<BridgeManageInstance | null> = ref(null)
4749
const tips = computed(() => RESOURCE_TIP[activedName.value])
4850
const docsContent =
4951
'资源管理插件提供「工具类方法」功能,支持自定义函数和npm包引用,实现代码复用。轻松添加公共函数或第三方库,应用内全局调用,提升开发效率。'
@@ -59,14 +61,19 @@ export default {
5961
openPanel()
6062
}
6163
62-
const refreshList = (type) => {
63-
utilsRef.value.refresh(type)
64+
const refreshList = (type: string) => {
65+
utilsRef.value?.refresh(type)
6466
}
6567
66-
const addResource = (type) => {
67-
utilsRef.value.add(type)
68+
const addResource = (type: string) => {
69+
utilsRef.value?.add(type)
6870
}
6971
72+
onActivated(() => {
73+
utilsRef.value?.refresh(activedName.value)
74+
getMetaApi(META_SERVICE.UseUtils).refreshUtils()
75+
})
76+
7077
return {
7178
PLUGIN_NAME,
7279
addResource,

packages/plugins/bridge/src/http.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,22 +14,22 @@ import { getMetaApi, META_SERVICE } from '@opentiny/tiny-engine-meta-register'
1414
import { generateBridge, generateUtil } from '@opentiny/tiny-engine-common/js/vscodeGenerateFile'
1515

1616
// 资源管理 -- 获取列表
17-
export const fetchResourceList = (appId, type) =>
17+
export const fetchResourceList = (appId: number, type: 'utils' | 'bridge') =>
1818
getMetaApi(META_SERVICE.Http).get(`/app-center/api/apps/extension/list?app=${appId}&category=${type}`)
1919

2020
// 资源管理 -- 获取资源详情
2121
export const fetchResourceDetail = () => getMetaApi(META_SERVICE.Http).get(`/app-center/api/apps/extension`)
2222

2323
// 资源管理 -- 新增
24-
export const requestAddReSource = (params) =>
24+
export const requestAddReSource = (params: Record<string, any>) =>
2525
getMetaApi(META_SERVICE.Http).post('/app-center/api/apps/extension/create', params)
2626

2727
// 资源管理 -- 修改
28-
export const requestUpdateReSource = (params) =>
28+
export const requestUpdateReSource = (params: Record<string, any>) =>
2929
getMetaApi(META_SERVICE.Http).post(`/app-center/api/apps/extension/update`, params)
3030

3131
// 资源管理 -- 删除
32-
export const requestDeleteReSource = (params) =>
32+
export const requestDeleteReSource = (params: string) =>
3333
getMetaApi(META_SERVICE.Http).get(`/app-center/api/apps/extension/delete?${params}`)
3434

3535
// 本地生成桥接工具类
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/**
2+
* Copyright (c) 2023 - present TinyEngine Authors.
3+
* Copyright (c) 2023 - present Huawei Cloud Computing Technologies Co., Ltd.
4+
*
5+
* Use of this source code is governed by an MIT-style license.
6+
*
7+
* THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL,
8+
* BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR
9+
* A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS.
10+
*
11+
*/
12+
13+
// 资源类型:utils 和 bridge
14+
// utils: 工具类
15+
// bridge: 桥接源
16+
export const RESOURCE_CATEGORY = {
17+
Util: 'utils',
18+
Bridge: 'bridge'
19+
} as const
20+
21+
// utils 类型: npm 和 function
22+
export const RESOURCE_TYPE = {
23+
Npm: 'npm',
24+
Function: 'function'
25+
} as const

packages/plugins/bridge/src/js/resource.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ const TempBridge = [
9999
export const RESOURCE_TYPE = {
100100
Util: 'utils',
101101
Bridge: 'bridge'
102-
}
102+
} as const
103103

104104
export const RESOURCE_CATEGORY = {
105105
Npm: 'npm',
@@ -206,6 +206,8 @@ export const saveResource = async (data, callback, emit) => {
206206
}
207207
}
208208

209+
getMetaApi(META_SERVICE.UseUtils).refreshUtils()
210+
209211
// 更新画布工具函数环境,保证渲染最新工具类返回值, 并触发画布的强制刷新
210212
generateBridgeUtil(getAppId())
211213
useNotify({
@@ -239,6 +241,8 @@ export const deleteData = (name, callback, emit) => {
239241
return
240242
}
241243

244+
getMetaApi(META_SERVICE.UseUtils).refreshUtils()
245+
242246
useResource().appSchemaState[state.type].splice(index, 1)
243247

244248
generateBridgeUtil(getAppId())
Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
// origin resource state code too mess up.
2+
3+
import { reactive, ref } from 'vue'
4+
import { fetchResourceList, requestAddReSource, requestUpdateReSource, requestDeleteReSource } from '../http'
5+
import { defineService, getMetaApi, META_SERVICE, useResource } from '@opentiny/tiny-engine-meta-register'
6+
import { RESOURCE_CATEGORY } from './constants'
7+
8+
export interface INpmUtilItem {
9+
category: 'utils'
10+
content: {
11+
destructuring: boolean
12+
exportName: string
13+
main: string
14+
package: string
15+
version: string
16+
}
17+
id: number
18+
name: string
19+
type: 'npm'
20+
app: number
21+
}
22+
23+
export interface IFunctionUtilItem {
24+
category: 'utils'
25+
content: {
26+
type: 'JSFunction'
27+
value: string
28+
}
29+
id: number
30+
name: string
31+
type: 'function'
32+
app: number
33+
}
34+
35+
export type IUtilItem = INpmUtilItem | IFunctionUtilItem
36+
37+
const state = reactive<{
38+
utils: IUtilItem[]
39+
}>({
40+
utils: []
41+
})
42+
43+
// 临时用来通知 BridgeManage 刷新列表
44+
const updateCount = ref(0)
45+
const lastOperation = ref<{ id: number | null; type: 'add' | 'update' | 'delete' }>({ id: null, type: 'add' })
46+
47+
const syncUtilsItemToAppSchemaState = (data: IUtilItem) => {
48+
const index = useResource().appSchemaState[RESOURCE_CATEGORY.Util].findIndex((item) => item.name === data.name)
49+
const { content, name, type } = data
50+
51+
if (index === -1) {
52+
useResource().appSchemaState[RESOURCE_CATEGORY.Util].push({ content, name, type })
53+
return
54+
}
55+
56+
useResource().appSchemaState[RESOURCE_CATEGORY.Util][index] = { content, name, type }
57+
}
58+
59+
const refreshUtils = async () => {
60+
const result = (await fetchResourceList(
61+
getMetaApi(META_SERVICE.GlobalService).getBaseInfo().id,
62+
RESOURCE_CATEGORY.Util
63+
)) as IUtilItem[]
64+
65+
state.utils = result.map(({ category, content, id, name, type, app }) => {
66+
return {
67+
category,
68+
content,
69+
id,
70+
name,
71+
type,
72+
app
73+
} as IUtilItem
74+
})
75+
}
76+
77+
const getUtilById = (id: number) => {
78+
return state.utils.find((item) => item.id === id)
79+
}
80+
81+
const getUtilByName = (name: string) => {
82+
return state.utils.find((item) => item.name === name)
83+
}
84+
85+
const addUtils = async (data: Omit<IUtilItem, 'id'>) => {
86+
const result = await requestAddReSource(data)
87+
88+
if (!result) {
89+
return
90+
}
91+
92+
lastOperation.value = { id: null, type: 'add' }
93+
updateCount.value++
94+
95+
syncUtilsItemToAppSchemaState(result)
96+
await refreshUtils()
97+
98+
return result
99+
}
100+
101+
const updateUtils = async (data: IUtilItem) => {
102+
const result = await requestUpdateReSource(data)
103+
104+
if (!result) {
105+
return
106+
}
107+
108+
lastOperation.value = { id: result.id, type: 'update' }
109+
updateCount.value++
110+
111+
syncUtilsItemToAppSchemaState(result)
112+
await refreshUtils()
113+
114+
return result
115+
}
116+
117+
const deleteUtils = async (id: number) => {
118+
const params = `app=${getMetaApi(META_SERVICE.GlobalService).getBaseInfo().id}&id=${id}`
119+
const result = await requestDeleteReSource(params)
120+
121+
if (!result) {
122+
return
123+
}
124+
125+
lastOperation.value = { id, type: 'delete' }
126+
updateCount.value++
127+
128+
const utilItem = getUtilById(id)
129+
const index = useResource().appSchemaState[RESOURCE_CATEGORY.Util].findIndex((item) => item.name === utilItem?.name)
130+
131+
if (index !== -1) {
132+
useResource().appSchemaState[RESOURCE_CATEGORY.Util].splice(index, 1)
133+
}
134+
135+
await refreshUtils()
136+
137+
return result
138+
}
139+
140+
const getUtils = () => state.utils
141+
const setUtils = (utils: IUtilItem[]) => {
142+
state.utils = utils
143+
}
144+
145+
export default defineService({
146+
id: META_SERVICE.UseUtils,
147+
type: 'MetaService',
148+
initialState: {
149+
utils: []
150+
},
151+
options: {},
152+
init: () => {
153+
refreshUtils()
154+
},
155+
apis: () => ({
156+
getUtils: () => getUtils(),
157+
setUtils: (utils: IUtilItem[]) => setUtils(utils),
158+
addUtils: (data: Omit<IUtilItem, 'id'>) => addUtils(data),
159+
updateUtils: (data: IUtilItem) => updateUtils(data),
160+
deleteUtils: (id: number) => deleteUtils(id),
161+
getUtilById: (id: number) => getUtilById(id),
162+
refreshUtils: () => refreshUtils(),
163+
getUtilByName: (name: string) => getUtilByName(name),
164+
getUpdateCount: () => updateCount.value,
165+
getLastOperation: () => lastOperation.value
166+
})
167+
})

0 commit comments

Comments
 (0)