add codemirror
This commit is contained in:
parent
97f89b0833
commit
34bc18085a
@ -7,6 +7,7 @@
|
|||||||
- 解决 issue#21 vscode插件界面bug,在高度有限情况下无法通过滚动完全显示连接按钮。
|
- 解决 issue#21 vscode插件界面bug,在高度有限情况下无法通过滚动完全显示连接按钮。
|
||||||
- 解决 issue#21 最后一个标签页关闭并恢复默认页面。
|
- 解决 issue#21 最后一个标签页关闭并恢复默认页面。
|
||||||
- 解决 issue#22 工具模块UI异常,现在 openmcp 支持解析 pydantic 进行 typing 的 python mcp 了。
|
- 解决 issue#22 工具模块UI异常,现在 openmcp 支持解析 pydantic 进行 typing 的 python mcp 了。
|
||||||
|
- 优化对象输入框,现在对象输入框具有语法高亮和受限度的自动补全了。
|
||||||
|
|
||||||
## [main] 0.1.1
|
## [main] 0.1.1
|
||||||
- 修复 SSH 连接 Ubuntu 的情况下的部分 bug
|
- 修复 SSH 连接 Ubuntu 的情况下的部分 bug
|
||||||
|
185
package-lock.json
generated
185
package-lock.json
generated
@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "openmcp",
|
"name": "openmcp",
|
||||||
"version": "0.1.1",
|
"version": "0.1.2",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "openmcp",
|
"name": "openmcp",
|
||||||
"version": "0.1.1",
|
"version": "0.1.2",
|
||||||
"workspaces": [
|
"workspaces": [
|
||||||
"service",
|
"service",
|
||||||
"renderer",
|
"renderer",
|
||||||
@ -510,6 +510,109 @@
|
|||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@codemirror/autocomplete": {
|
||||||
|
"version": "6.18.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.18.6.tgz",
|
||||||
|
"integrity": "sha512-PHHBXFomUs5DF+9tCOM/UoW6XQ4R44lLNNhRaW9PKPTU0D7lIjRg3ElxaJnTwsl/oHiR93WSXDBrekhoUGCPtg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@codemirror/language": "^6.0.0",
|
||||||
|
"@codemirror/state": "^6.0.0",
|
||||||
|
"@codemirror/view": "^6.17.0",
|
||||||
|
"@lezer/common": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@codemirror/commands": {
|
||||||
|
"version": "6.8.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-6.8.1.tgz",
|
||||||
|
"integrity": "sha512-KlGVYufHMQzxbdQONiLyGQDUW0itrLZwq3CcY7xpv9ZLRHqzkBSoteocBHtMCoY7/Ci4xhzSrToIeLg7FxHuaw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@codemirror/language": "^6.0.0",
|
||||||
|
"@codemirror/state": "^6.4.0",
|
||||||
|
"@codemirror/view": "^6.27.0",
|
||||||
|
"@lezer/common": "^1.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@codemirror/lang-json": {
|
||||||
|
"version": "6.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@codemirror/lang-json/-/lang-json-6.0.1.tgz",
|
||||||
|
"integrity": "sha512-+T1flHdgpqDDlJZ2Lkil/rLiRy684WMLc74xUnjJH48GQdfJo/pudlTRreZmKwzP8/tGdKf83wlbAdOCzlJOGQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@codemirror/language": "^6.0.0",
|
||||||
|
"@lezer/json": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@codemirror/language": {
|
||||||
|
"version": "6.11.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.11.0.tgz",
|
||||||
|
"integrity": "sha512-A7+f++LodNNc1wGgoRDTt78cOwWm9KVezApgjOMp1W4hM0898nsqBXwF+sbePE7ZRcjN7Sa1Z5m2oN27XkmEjQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@codemirror/state": "^6.0.0",
|
||||||
|
"@codemirror/view": "^6.23.0",
|
||||||
|
"@lezer/common": "^1.1.0",
|
||||||
|
"@lezer/highlight": "^1.0.0",
|
||||||
|
"@lezer/lr": "^1.0.0",
|
||||||
|
"style-mod": "^4.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@codemirror/lint": {
|
||||||
|
"version": "6.8.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@codemirror/lint/-/lint-6.8.5.tgz",
|
||||||
|
"integrity": "sha512-s3n3KisH7dx3vsoeGMxsbRAgKe4O1vbrnKBClm99PU0fWxmxsx5rR2PfqQgIt+2MMJBHbiJ5rfIdLYfB9NNvsA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@codemirror/state": "^6.0.0",
|
||||||
|
"@codemirror/view": "^6.35.0",
|
||||||
|
"crelt": "^1.0.5"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@codemirror/search": {
|
||||||
|
"version": "6.5.11",
|
||||||
|
"resolved": "https://registry.npmjs.org/@codemirror/search/-/search-6.5.11.tgz",
|
||||||
|
"integrity": "sha512-KmWepDE6jUdL6n8cAAqIpRmLPBZ5ZKnicE8oGU/s3QrAVID+0VhLFrzUucVKHG5035/BSykhExDL/Xm7dHthiA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@codemirror/state": "^6.0.0",
|
||||||
|
"@codemirror/view": "^6.0.0",
|
||||||
|
"crelt": "^1.0.5"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@codemirror/state": {
|
||||||
|
"version": "6.5.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@codemirror/state/-/state-6.5.2.tgz",
|
||||||
|
"integrity": "sha512-FVqsPqtPWKVVL3dPSxy8wEF/ymIEuVzF1PK3VbUgrxXpJUSHQWWZz4JMToquRxnkw+36LTamCZG2iua2Ptq0fA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@marijn/find-cluster-break": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@codemirror/theme-one-dark": {
|
||||||
|
"version": "6.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@codemirror/theme-one-dark/-/theme-one-dark-6.1.2.tgz",
|
||||||
|
"integrity": "sha512-F+sH0X16j/qFLMAfbciKTxVOwkdAS336b7AXTKOZhy8BR3eH/RelsnLgLFINrpST63mmN2OuwUt0W2ndUgYwUA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@codemirror/language": "^6.0.0",
|
||||||
|
"@codemirror/state": "^6.0.0",
|
||||||
|
"@codemirror/view": "^6.0.0",
|
||||||
|
"@lezer/highlight": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@codemirror/view": {
|
||||||
|
"version": "6.37.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.37.1.tgz",
|
||||||
|
"integrity": "sha512-Qy4CAUwngy/VQkEz0XzMKVRcckQuqLYWKqVpDDDghBe5FSXSqfVrJn49nw3ePZHxRUz4nRmb05Lgi+9csWo4eg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@codemirror/state": "^6.5.0",
|
||||||
|
"crelt": "^1.0.6",
|
||||||
|
"style-mod": "^4.1.0",
|
||||||
|
"w3c-keyname": "^2.2.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@cspotcode/source-map-support": {
|
"node_modules/@cspotcode/source-map-support": {
|
||||||
"version": "0.8.1",
|
"version": "0.8.1",
|
||||||
"resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz",
|
"resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz",
|
||||||
@ -1460,6 +1563,41 @@
|
|||||||
"@jridgewell/sourcemap-codec": "^1.4.14"
|
"@jridgewell/sourcemap-codec": "^1.4.14"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@lezer/common": {
|
||||||
|
"version": "1.2.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.2.3.tgz",
|
||||||
|
"integrity": "sha512-w7ojc8ejBqr2REPsWxJjrMFsA/ysDCFICn8zEOR9mrqzOu2amhITYuLD8ag6XZf0CFXDrhKqw7+tW8cX66NaDA==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/@lezer/highlight": {
|
||||||
|
"version": "1.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@lezer/highlight/-/highlight-1.2.1.tgz",
|
||||||
|
"integrity": "sha512-Z5duk4RN/3zuVO7Jq0pGLJ3qynpxUVsh7IbUbGj88+uV2ApSAn6kWg2au3iJb+0Zi7kKtqffIESgNcRXWZWmSA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@lezer/common": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@lezer/json": {
|
||||||
|
"version": "1.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@lezer/json/-/json-1.0.3.tgz",
|
||||||
|
"integrity": "sha512-BP9KzdF9Y35PDpv04r0VeSTKDeox5vVr3efE7eBbx3r4s3oNLfunchejZhjArmeieBH+nVOpgIiBJpEAv8ilqQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@lezer/common": "^1.2.0",
|
||||||
|
"@lezer/highlight": "^1.0.0",
|
||||||
|
"@lezer/lr": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@lezer/lr": {
|
||||||
|
"version": "1.4.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@lezer/lr/-/lr-1.4.2.tgz",
|
||||||
|
"integrity": "sha512-pu0K1jCIdnQ12aWNaAVU5bzi7Bd1w54J3ECgANPmYLtQKP0HBj2cE/5coBD66MT10xbtIuUr7tg0Shbsvk0mDA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@lezer/common": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@malept/cross-spawn-promise": {
|
"node_modules/@malept/cross-spawn-promise": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/@malept/cross-spawn-promise/-/cross-spawn-promise-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/@malept/cross-spawn-promise/-/cross-spawn-promise-1.1.1.tgz",
|
||||||
@ -1515,6 +1653,12 @@
|
|||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@marijn/find-cluster-break": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@marijn/find-cluster-break/-/find-cluster-break-1.0.2.tgz",
|
||||||
|
"integrity": "sha512-l0h88YhZFyKdXIFNfSWpyjStDjGHwZ/U7iobcK1cQQD8sejsONdQtTVU+1wVN1PBw40PiiHB1vA5S7VTfQiP9g==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/@modelcontextprotocol/sdk": {
|
"node_modules/@modelcontextprotocol/sdk": {
|
||||||
"version": "1.12.1",
|
"version": "1.12.1",
|
||||||
"resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.12.1.tgz",
|
"resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.12.1.tgz",
|
||||||
@ -4209,6 +4353,21 @@
|
|||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/codemirror": {
|
||||||
|
"version": "6.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/codemirror/-/codemirror-6.0.1.tgz",
|
||||||
|
"integrity": "sha512-J8j+nZ+CdWmIeFIGXEFbFPtpiYacFMDR8GlHK3IyHQJMCaVRfGx9NT+Hxivv1ckLWPvNdZqndbr/7lVhrf/Svg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@codemirror/autocomplete": "^6.0.0",
|
||||||
|
"@codemirror/commands": "^6.0.0",
|
||||||
|
"@codemirror/language": "^6.0.0",
|
||||||
|
"@codemirror/lint": "^6.0.0",
|
||||||
|
"@codemirror/search": "^6.0.0",
|
||||||
|
"@codemirror/state": "^6.0.0",
|
||||||
|
"@codemirror/view": "^6.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/color-convert": {
|
"node_modules/color-convert": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
||||||
@ -4549,6 +4708,12 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/crelt": {
|
||||||
|
"version": "1.0.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/crelt/-/crelt-1.0.6.tgz",
|
||||||
|
"integrity": "sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/cross-spawn": {
|
"node_modules/cross-spawn": {
|
||||||
"version": "7.0.6",
|
"version": "7.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
|
||||||
@ -9996,6 +10161,12 @@
|
|||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/style-mod": {
|
||||||
|
"version": "4.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/style-mod/-/style-mod-4.1.2.tgz",
|
||||||
|
"integrity": "sha512-wnD1HyVqpJUI2+eKZ+eo1UwghftP6yuFheBqqe+bWCotBjC2K1YnteJILRMs3SM4V/0dLEW1SC27MWP5y+mwmw==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/sumchecker": {
|
"node_modules/sumchecker": {
|
||||||
"version": "3.0.1",
|
"version": "3.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/sumchecker/-/sumchecker-3.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/sumchecker/-/sumchecker-3.0.1.tgz",
|
||||||
@ -10883,6 +11054,12 @@
|
|||||||
"typescript": ">=5.0.0"
|
"typescript": ">=5.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/w3c-keyname": {
|
||||||
|
"version": "2.2.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz",
|
||||||
|
"integrity": "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/wasm-feature-detect": {
|
"node_modules/wasm-feature-detect": {
|
||||||
"version": "1.8.0",
|
"version": "1.8.0",
|
||||||
"resolved": "https://registry.npmjs.org/wasm-feature-detect/-/wasm-feature-detect-1.8.0.tgz",
|
"resolved": "https://registry.npmjs.org/wasm-feature-detect/-/wasm-feature-detect-1.8.0.tgz",
|
||||||
@ -11367,6 +11544,10 @@
|
|||||||
"name": "@openmcp/renderer",
|
"name": "@openmcp/renderer",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@codemirror/autocomplete": "^6.18.6",
|
||||||
|
"@codemirror/lang-json": "^6.0.1",
|
||||||
|
"@codemirror/theme-one-dark": "^6.1.2",
|
||||||
|
"codemirror": "^6.0.1",
|
||||||
"core-js": "^3.8.3",
|
"core-js": "^3.8.3",
|
||||||
"element-plus": "^2.9.9",
|
"element-plus": "^2.9.9",
|
||||||
"katex": "^0.16.21",
|
"katex": "^0.16.21",
|
||||||
|
@ -16,6 +16,10 @@
|
|||||||
"type-check": "vue-tsc --build"
|
"type-check": "vue-tsc --build"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@codemirror/autocomplete": "^6.18.6",
|
||||||
|
"@codemirror/lang-json": "^6.0.1",
|
||||||
|
"@codemirror/theme-one-dark": "^6.1.2",
|
||||||
|
"codemirror": "^6.0.1",
|
||||||
"core-js": "^3.8.3",
|
"core-js": "^3.8.3",
|
||||||
"element-plus": "^2.9.9",
|
"element-plus": "^2.9.9",
|
||||||
"katex": "^0.16.21",
|
"katex": "^0.16.21",
|
||||||
|
@ -222,3 +222,9 @@ a {
|
|||||||
.el-dropdown-menu__item:hover {
|
.el-dropdown-menu__item:hover {
|
||||||
background-color: var(--background) !important;
|
background-color: var(--background) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* codemirror */
|
||||||
|
.ͼo,
|
||||||
|
.ͼo .cm-gutters {
|
||||||
|
background-color: transparent !important;
|
||||||
|
}
|
@ -1,23 +1,23 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="k-input-object">
|
<div class="k-input-object">
|
||||||
<textarea ref="textareaRef" v-model="inputValue" class="k-input-object__textarea"
|
<div :ref="el => editorContainer = el" class="k-input-object__editor"></div>
|
||||||
:class="{ 'is-invalid': isInvalid }" @input="handleInput" @blur="handleBlur"
|
|
||||||
@keydown="handleKeydown"
|
|
||||||
:placeholder="props.placeholder"
|
|
||||||
></textarea>
|
|
||||||
</div>
|
|
||||||
<div v-if="errorMessage" class="k-input-object__error">
|
<div v-if="errorMessage" class="k-input-object__error">
|
||||||
{{ errorMessage }}
|
{{ errorMessage }}
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts" setup>
|
||||||
import { defineComponent, ref, watch, nextTick } from 'vue';
|
import { ref, onMounted, watch, type PropType } from 'vue'
|
||||||
import { debounce } from 'lodash';
|
import { EditorView, basicSetup } from 'codemirror'
|
||||||
|
import type { Completion, CompletionContext } from "@codemirror/autocomplete"
|
||||||
|
import { jsonLanguage } from "@codemirror/lang-json"
|
||||||
|
|
||||||
export default defineComponent({
|
import { json } from '@codemirror/lang-json'
|
||||||
name: 'KInputObject',
|
import { oneDark } from '@codemirror/theme-one-dark'
|
||||||
props: {
|
import { debounce } from 'lodash'
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
modelValue: {
|
modelValue: {
|
||||||
type: Object,
|
type: Object,
|
||||||
default: () => ({})
|
default: () => ({})
|
||||||
@ -29,17 +29,33 @@ export default defineComponent({
|
|||||||
debounceTime: {
|
debounceTime: {
|
||||||
type: Number,
|
type: Number,
|
||||||
default: 500
|
default: 500
|
||||||
}
|
|
||||||
},
|
},
|
||||||
emits: ['update:modelValue', 'parse-error'],
|
schema: {
|
||||||
setup(props, { emit }) {
|
type: Object as PropType<{
|
||||||
const textareaRef = ref<HTMLTextAreaElement | null>(null)
|
type?: string;
|
||||||
const inputValue = ref<string>(JSON.stringify(props.modelValue, null, 2))
|
properties?: Record<string, {
|
||||||
const isInvalid = ref<boolean>(false)
|
type: string;
|
||||||
const errorMessage = ref<string>('')
|
description?: string;
|
||||||
|
default?: any;
|
||||||
|
enum?: any[];
|
||||||
|
}>;
|
||||||
|
required?: string[];
|
||||||
|
}>,
|
||||||
|
default: () => ({})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
// 防抖处理输入
|
const emit = defineEmits(['update:modelValue', 'parse-error'])
|
||||||
const debouncedParse = debounce((value: string) => {
|
|
||||||
|
const editorContainer = ref<any>(null);
|
||||||
|
const editorView = ref<EditorView | null>(null);
|
||||||
|
const isInvalid = ref(false);
|
||||||
|
const errorMessage = ref('');
|
||||||
|
|
||||||
|
const inputValue = ref<string>(JSON.stringify(props.modelValue, null, 2));
|
||||||
|
|
||||||
|
// 防抖处理输入
|
||||||
|
const debouncedParse = debounce((value: string) => {
|
||||||
if (value.trim() === '') {
|
if (value.trim() === '') {
|
||||||
errorMessage.value = '';
|
errorMessage.value = '';
|
||||||
isInvalid.value = false;
|
isInvalid.value = false;
|
||||||
@ -56,92 +72,128 @@ export default defineComponent({
|
|||||||
errorMessage.value = 'JSON 解析错误: ' + (error as Error).message;
|
errorMessage.value = 'JSON 解析错误: ' + (error as Error).message;
|
||||||
emit('parse-error', error);
|
emit('parse-error', error);
|
||||||
}
|
}
|
||||||
}, props.debounceTime)
|
}, props.debounceTime);
|
||||||
|
|
||||||
const handleInput = () => {
|
onMounted(() => {
|
||||||
debouncedParse(inputValue.value)
|
if (editorContainer.value) {
|
||||||
|
const extensions = [
|
||||||
|
basicSetup,
|
||||||
|
json(),
|
||||||
|
oneDark,
|
||||||
|
EditorView.updateListener.of(update => {
|
||||||
|
if (update.docChanged) {
|
||||||
|
const value = update.state.doc.toString()
|
||||||
|
debouncedParse(value)
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
]
|
||||||
|
|
||||||
const handleBlur = () => {
|
// 如果schema不为空,添加自动补全
|
||||||
// 立即执行最后一次防抖
|
if (Object.keys(props.schema).length > 0) {
|
||||||
debouncedParse.flush()
|
extensions.push(
|
||||||
}
|
jsonLanguage.data.of({
|
||||||
|
autocomplete: getJsonCompletion(props.schema)
|
||||||
// 当外部 modelValue 变化时更新输入框内容
|
})
|
||||||
watch(
|
|
||||||
() => props.modelValue,
|
|
||||||
(newVal) => {
|
|
||||||
const currentParsed = tryParse(inputValue.value)
|
|
||||||
if (!isDeepEqual(currentParsed, newVal)) {
|
|
||||||
inputValue.value = JSON.stringify(newVal, null, 2)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{ deep: true }
|
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// 辅助函数:尝试解析 JSON
|
editorView.value = new EditorView({
|
||||||
const tryParse = (value: string): any => {
|
doc: JSON.stringify(props.modelValue, null, 2),
|
||||||
|
extensions,
|
||||||
|
parent: editorContainer.value
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// 添加自动补全函数
|
||||||
|
function getJsonCompletion(schema: any) {
|
||||||
|
return (context: CompletionContext) => {
|
||||||
|
// 检查当前输入是否是标点符号
|
||||||
|
const charBefore = context.state.sliceDoc(context.pos - 1, context.pos)
|
||||||
|
if (/[,.{}[\]:]/.test(charBefore)) return null
|
||||||
|
|
||||||
|
const word = context.matchBefore(/\w*/)
|
||||||
|
if (!word) return null
|
||||||
|
|
||||||
|
// 检查当前是否在字符串内
|
||||||
|
const state = context.state
|
||||||
|
const pos = context.pos
|
||||||
|
const line = state.doc.lineAt(pos)
|
||||||
|
const textBefore = line.text.slice(0, pos - line.from)
|
||||||
|
|
||||||
|
// 如果前面有奇数个双引号,说明在字符串内,不触发补全
|
||||||
|
const quoteCount = (textBefore.match(/"/g) || []).length
|
||||||
|
if (quoteCount % 2 !== 0) return null
|
||||||
|
|
||||||
|
const completions: Completion[] = []
|
||||||
|
|
||||||
|
// 处理对象属性补全
|
||||||
|
if (schema.properties) {
|
||||||
|
Object.entries(schema.properties).forEach(([key, value]) => {
|
||||||
|
completions.push({
|
||||||
|
label: key,
|
||||||
|
type: "property",
|
||||||
|
apply: `"${key}": ${getDefaultValue(value as any)}`
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
from: word.from,
|
||||||
|
options: completions,
|
||||||
|
validFor: /^\w*$/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取默认值函数
|
||||||
|
function getDefaultValue(property: any): string {
|
||||||
|
if (property.default !== undefined) {
|
||||||
|
return JSON.stringify(property.default)
|
||||||
|
}
|
||||||
|
switch (property.type) {
|
||||||
|
case 'string': return '""'
|
||||||
|
case 'number': return '0'
|
||||||
|
case 'boolean': return 'false'
|
||||||
|
case 'object': return '{}'
|
||||||
|
case 'array': return '[]'
|
||||||
|
default: return 'null'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改 watch 逻辑
|
||||||
|
// watch(
|
||||||
|
// () => props.modelValue,
|
||||||
|
// (newVal) => {
|
||||||
|
// const currentParsed = tryParse(inputValue.value)
|
||||||
|
// if (!isDeepEqual(currentParsed, newVal)) {
|
||||||
|
// const newContent = JSON.stringify(newVal, null, 2)
|
||||||
|
// editorView.value?.dispatch({
|
||||||
|
// changes: {
|
||||||
|
// from: 0,
|
||||||
|
// to: editorView.value.state.doc.length,
|
||||||
|
// insert: newContent
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// { deep: true }
|
||||||
|
// )
|
||||||
|
|
||||||
|
// 辅助函数:尝试解析 JSON
|
||||||
|
const tryParse = (value: string): any => {
|
||||||
try {
|
try {
|
||||||
return JSON.parse(value)
|
return JSON.parse(value)
|
||||||
} catch {
|
} catch {
|
||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 辅助函数:深度比较对象
|
// 辅助函数:深度比较对象
|
||||||
const isDeepEqual = (obj1: any, obj2: any): boolean => {
|
const isDeepEqual = (obj1: any, obj2: any): boolean => {
|
||||||
return JSON.stringify(obj1) === JSON.stringify(obj2)
|
return JSON.stringify(obj1) === JSON.stringify(obj2)
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleKeydown = (event: KeyboardEvent) => {
|
|
||||||
if (event.key === '{') {
|
|
||||||
event.preventDefault();
|
|
||||||
const start = textareaRef.value!.selectionStart;
|
|
||||||
const end = textareaRef.value!.selectionEnd;
|
|
||||||
const value = inputValue.value;
|
|
||||||
const newValue = value.substring(0, start) + '{\n \n}' + value.substring(end);
|
|
||||||
inputValue.value = newValue;
|
|
||||||
nextTick(() => {
|
|
||||||
textareaRef.value!.setSelectionRange(start + 2, start + 2);
|
|
||||||
});
|
|
||||||
} else if (event.key === '"') {
|
|
||||||
event.preventDefault();
|
|
||||||
const start = textareaRef.value!.selectionStart;
|
|
||||||
const end = textareaRef.value!.selectionEnd;
|
|
||||||
const value = inputValue.value;
|
|
||||||
const newValue = value.substring(0, start) + '""' + value.substring(end);
|
|
||||||
inputValue.value = newValue;
|
|
||||||
nextTick(() => {
|
|
||||||
textareaRef.value!.setSelectionRange(start + 1, start + 1);
|
|
||||||
});
|
|
||||||
} else if (event.key === 'Tab') {
|
|
||||||
event.preventDefault();
|
|
||||||
const start = textareaRef.value!.selectionStart;
|
|
||||||
const end = textareaRef.value!.selectionEnd;
|
|
||||||
const value = inputValue.value;
|
|
||||||
const newValue = value.substring(0, start) + ' ' + value.substring(end);
|
|
||||||
inputValue.value = newValue;
|
|
||||||
nextTick(() => {
|
|
||||||
textareaRef.value!.setSelectionRange(start + 1, start + 1);
|
|
||||||
});
|
|
||||||
} else if (event.key === 'Enter' && inputValue.value.trim() === '') {
|
|
||||||
event.preventDefault();
|
|
||||||
inputValue.value = '{}';
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
|
||||||
textareaRef,
|
|
||||||
inputValue,
|
|
||||||
isInvalid,
|
|
||||||
errorMessage,
|
|
||||||
handleInput,
|
|
||||||
handleBlur,
|
|
||||||
handleKeydown,
|
|
||||||
props
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
@ -151,6 +203,7 @@ export default defineComponent({
|
|||||||
border-radius: .5em;
|
border-radius: .5em;
|
||||||
margin-bottom: 15px;
|
margin-bottom: 15px;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
.k-input-object__textarea {
|
.k-input-object__textarea {
|
||||||
@ -174,6 +227,24 @@ export default defineComponent({
|
|||||||
border-color: var(--el-color-error);
|
border-color: var(--el-color-error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.k-input-object__error {
|
||||||
|
color: var(--el-color-error);
|
||||||
|
font-size: 12px;
|
||||||
|
margin-top: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.k-input-object__editor {
|
||||||
|
width: 100%;
|
||||||
|
border: 1px solid var(--el-border-color-light);
|
||||||
|
border-radius: 4px;
|
||||||
|
overflow: hidden;
|
||||||
|
background-color: var(--el-bg-color-overlay);
|
||||||
|
}
|
||||||
|
|
||||||
|
.k-input-object__editor.is-invalid {
|
||||||
|
border-color: var(--el-color-error);
|
||||||
|
}
|
||||||
|
|
||||||
.k-input-object__error {
|
.k-input-object__error {
|
||||||
color: var(--el-color-error);
|
color: var(--el-color-error);
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
|
@ -38,6 +38,7 @@
|
|||||||
<k-input-object
|
<k-input-object
|
||||||
v-else-if="property.type === 'object'"
|
v-else-if="property.type === 'object'"
|
||||||
v-model="tabStorage.formData[name]"
|
v-model="tabStorage.formData[name]"
|
||||||
|
:schema="property"
|
||||||
:placeholder="property.description || t('enter') + ' ' + (property.title || name)"
|
:placeholder="property.description || t('enter') + ' ' + (property.title || name)"
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@ -84,14 +85,9 @@ if (!tabStorage.formData) {
|
|||||||
tabStorage.formData = {};
|
tabStorage.formData = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(tabStorage.formData);
|
|
||||||
|
|
||||||
|
|
||||||
const formRef = ref<FormInstance>();
|
const formRef = ref<FormInstance>();
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const currentTool = computed(() => {
|
const currentTool = computed(() => {
|
||||||
for (const client of mcpClientAdapter.clients) {
|
for (const client of mcpClientAdapter.clients) {
|
||||||
const tool = client.tools?.get(tabStorage.currentToolName);
|
const tool = client.tools?.get(tabStorage.currentToolName);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user