From 8ca9ecef743751e089cb953710b6165678a10887 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 24 Apr 2026 07:43:56 +0000 Subject: [PATCH 01/49] build(deps): bump github.com/blevesearch/bleve_index_api Bumps [github.com/blevesearch/bleve_index_api](https://github.com/blevesearch/bleve_index_api) from 1.3.10 to 1.3.11. - [Commits](https://github.com/blevesearch/bleve_index_api/compare/v1.3.10...v1.3.11) --- updated-dependencies: - dependency-name: github.com/blevesearch/bleve_index_api dependency-version: 1.3.11 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 9a52f7d01..6d6afeceb 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.25.5 require ( github.com/Masterminds/sprig v2.22.0+incompatible github.com/blevesearch/bleve/v2 v2.5.7 - github.com/blevesearch/bleve_index_api v1.3.10 + github.com/blevesearch/bleve_index_api v1.3.11 github.com/bradleyfalzon/ghinstallation/v2 v2.18.0 github.com/brianvoe/gofakeit/v6 v6.28.0 github.com/dop251/goja v0.0.0-20250309171923-bcd7cc6bf64c diff --git a/go.sum b/go.sum index 5fc4bf025..b98575b2a 100644 --- a/go.sum +++ b/go.sum @@ -24,8 +24,8 @@ github.com/bits-and-blooms/bitset v1.22.0 h1:Tquv9S8+SGaS3EhyA+up3FXzmkhxPGjQQCk github.com/bits-and-blooms/bitset v1.22.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= github.com/blevesearch/bleve/v2 v2.5.7 h1:2d9YrL5zrX5EBBW++GOaEKjE+NPWeZGaX77IM26m1Z8= github.com/blevesearch/bleve/v2 v2.5.7/go.mod h1:yj0NlS7ocGC4VOSAedqDDMktdh2935v2CSWOCDMHdSA= -github.com/blevesearch/bleve_index_api v1.3.10 h1:a7G+IOMa2xuO6f8vtutbTsqjVLpLuCuH3uoTZHkGiYg= -github.com/blevesearch/bleve_index_api v1.3.10/go.mod h1:xvd48t5XMeeioWQ5/jZvgLrV98flT2rdvEJ3l/ki4Ko= +github.com/blevesearch/bleve_index_api v1.3.11 h1:x29vbV8OjWfLcrDVd7Lr1q+BkLNS0JWNEig0MCVnKH4= +github.com/blevesearch/bleve_index_api v1.3.11/go.mod h1:xvd48t5XMeeioWQ5/jZvgLrV98flT2rdvEJ3l/ki4Ko= github.com/blevesearch/geo v0.2.4 h1:ECIGQhw+QALCZaDcogRTNSJYQXRtC8/m8IKiA706cqk= github.com/blevesearch/geo v0.2.4/go.mod h1:K56Q33AzXt2YExVHGObtmRSFYZKYGv0JEN5mdacJJR8= github.com/blevesearch/go-faiss v1.0.26 h1:4dRLolFgjPyjkaXwff4NfbZFdE/dfywbzDqporeQvXI= From cdeb3a8b8c7dc8aac5d25ac75e38b7905cc97570 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 24 Apr 2026 07:43:57 +0000 Subject: [PATCH 02/49] build(deps-dev): bump eslint from 10.2.0 to 10.2.1 in /webui Bumps [eslint](https://github.com/eslint/eslint) from 10.2.0 to 10.2.1. - [Release notes](https://github.com/eslint/eslint/releases) - [Commits](https://github.com/eslint/eslint/compare/v10.2.0...v10.2.1) --- updated-dependencies: - dependency-name: eslint dependency-version: 10.2.1 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- webui/package-lock.json | 16 ++++++++-------- webui/package.json | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/webui/package-lock.json b/webui/package-lock.json index 3f5b200fc..1253d7d9e 100644 --- a/webui/package-lock.json +++ b/webui/package-lock.json @@ -48,7 +48,7 @@ "@vue/eslint-config-prettier": "^10.2.0", "@vue/eslint-config-typescript": "^14.7.0", "@vue/tsconfig": "^0.9.1", - "eslint": "^10.2.0", + "eslint": "^10.2.1", "eslint-plugin-vue": "^10.8.0", "npm-run-all": "^4.1.5", "prettier": "^3.8.3", @@ -2695,18 +2695,18 @@ } }, "node_modules/eslint": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-10.2.0.tgz", - "integrity": "sha512-+L0vBFYGIpSNIt/KWTpFonPrqYvgKw1eUI5Vn7mEogrQcWtWYtNQ7dNqC+px/J0idT3BAkiWrhfS7k+Tum8TUA==", + "version": "10.2.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-10.2.1.tgz", + "integrity": "sha512-wiyGaKsDgqXvF40P8mDwiUp/KQjE1FdrIEJsM8PZ3XCiniTMXS3OHWWUe5FI5agoCnr8x4xPrTDZuxsBlNHl+Q==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.2", - "@eslint/config-array": "^0.23.4", - "@eslint/config-helpers": "^0.5.4", - "@eslint/core": "^1.2.0", - "@eslint/plugin-kit": "^0.7.0", + "@eslint/config-array": "^0.23.5", + "@eslint/config-helpers": "^0.5.5", + "@eslint/core": "^1.2.1", + "@eslint/plugin-kit": "^0.7.1", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", diff --git a/webui/package.json b/webui/package.json index 1f9f2d3ed..adbc7b0af 100644 --- a/webui/package.json +++ b/webui/package.json @@ -57,7 +57,7 @@ "@vue/eslint-config-prettier": "^10.2.0", "@vue/eslint-config-typescript": "^14.7.0", "@vue/tsconfig": "^0.9.1", - "eslint": "^10.2.0", + "eslint": "^10.2.1", "eslint-plugin-vue": "^10.8.0", "npm-run-all": "^4.1.5", "prettier": "^3.8.3", From 83b55df442bb8315cf6f2ec4bdccd61f8551f000 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 24 Apr 2026 07:51:58 +0000 Subject: [PATCH 03/49] build(deps): bump vue-router from 5.0.4 to 5.0.6 in /webui Bumps [vue-router](https://github.com/vuejs/router) from 5.0.4 to 5.0.6. - [Release notes](https://github.com/vuejs/router/releases) - [Commits](https://github.com/vuejs/router/compare/v5.0.4...v5.0.6) --- updated-dependencies: - dependency-name: vue-router dependency-version: 5.0.6 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- webui/package-lock.json | 8 ++++---- webui/package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/webui/package-lock.json b/webui/package-lock.json index 1253d7d9e..7461ac599 100644 --- a/webui/package-lock.json +++ b/webui/package-lock.json @@ -33,7 +33,7 @@ "ncp": "^2.0.0", "nodemailer": "^8.0.5", "vue": "^3.5.32", - "vue-router": "^5.0.4", + "vue-router": "^5.0.6", "vue3-ace-editor": "^2.2.4", "whatwg-mimetype": "^5.0.0", "xml-formatter": "^3.7.0" @@ -6859,9 +6859,9 @@ } }, "node_modules/vue-router": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-5.0.4.tgz", - "integrity": "sha512-lCqDLCI2+fKVRl2OzXuzdSWmxXFLQRxQbmHugnRpTMyYiT+hNaycV0faqG5FBHDXoYrZ6MQcX87BvbY8mQ20Bg==", + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-5.0.6.tgz", + "integrity": "sha512-9+kmUTGbKMyW9Asoy98IXXYIzrTMT7JDAdpDDeEkorHvybpUvBI2wsrSM5jFOXrFydpzRFJ9vAh+80DN2PGu9w==", "license": "MIT", "dependencies": { "@babel/generator": "^7.28.6", diff --git a/webui/package.json b/webui/package.json index adbc7b0af..c6fdf6a8d 100644 --- a/webui/package.json +++ b/webui/package.json @@ -42,7 +42,7 @@ "ncp": "^2.0.0", "nodemailer": "^8.0.5", "vue": "^3.5.32", - "vue-router": "^5.0.4", + "vue-router": "^5.0.6", "vue3-ace-editor": "^2.2.4", "whatwg-mimetype": "^5.0.0", "xml-formatter": "^3.7.0" From bfdb1d6930bd15ebb0d0066e308af03c1fe1cdaf Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 24 Apr 2026 07:59:58 +0000 Subject: [PATCH 04/49] build(deps): bump vue from 3.5.32 to 3.5.33 in /webui Bumps [vue](https://github.com/vuejs/core) from 3.5.32 to 3.5.33. - [Release notes](https://github.com/vuejs/core/releases) - [Changelog](https://github.com/vuejs/core/blob/main/CHANGELOG.md) - [Commits](https://github.com/vuejs/core/compare/v3.5.32...v3.5.33) --- updated-dependencies: - dependency-name: vue dependency-version: 3.5.33 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- webui/package-lock.json | 116 ++++++++++++++++++++-------------------- webui/package.json | 2 +- 2 files changed, 59 insertions(+), 59 deletions(-) diff --git a/webui/package-lock.json b/webui/package-lock.json index 7461ac599..644296fba 100644 --- a/webui/package-lock.json +++ b/webui/package-lock.json @@ -32,7 +32,7 @@ "mime-types": "^3.0.2", "ncp": "^2.0.0", "nodemailer": "^8.0.5", - "vue": "^3.5.32", + "vue": "^3.5.33", "vue-router": "^5.0.6", "vue3-ace-editor": "^2.2.4", "whatwg-mimetype": "^5.0.0", @@ -1178,53 +1178,53 @@ } }, "node_modules/@vue/compiler-core": { - "version": "3.5.32", - "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.32.tgz", - "integrity": "sha512-4x74Tbtqnda8s/NSD6e1Dr5p1c8HdMU5RWSjMSUzb8RTcUQqevDCxVAitcLBKT+ie3o0Dl9crc/S/opJM7qBGQ==", + "version": "3.5.33", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.33.tgz", + "integrity": "sha512-3PZLQwFw4Za3TC8t0FvTy3wI16Kt+pmwcgNZca4Pj9iWL2E72a/gZlpBtAJvEdDMdCxdG/qq0C7PN0bsJuv0Rw==", "license": "MIT", "dependencies": { "@babel/parser": "^7.29.2", - "@vue/shared": "3.5.32", + "@vue/shared": "3.5.33", "entities": "^7.0.1", "estree-walker": "^2.0.2", "source-map-js": "^1.2.1" } }, "node_modules/@vue/compiler-dom": { - "version": "3.5.32", - "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.32.tgz", - "integrity": "sha512-ybHAu70NtiEI1fvAUz3oXZqkUYEe5J98GjMDpTGl5iHb0T15wQYLR4wE3h9xfuTNA+Cm2f4czfe8B4s+CCH57Q==", + "version": "3.5.33", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.33.tgz", + "integrity": "sha512-PXq0yrfCLzzL07rbXO4awtXY1Z06LG2eu6Adg3RJFa/j3Cii217XxxLXG22N330gw7GmALCY0Z8RgXEviwgpjA==", "license": "MIT", "dependencies": { - "@vue/compiler-core": "3.5.32", - "@vue/shared": "3.5.32" + "@vue/compiler-core": "3.5.33", + "@vue/shared": "3.5.33" } }, "node_modules/@vue/compiler-sfc": { - "version": "3.5.32", - "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.32.tgz", - "integrity": "sha512-8UYUYo71cP/0YHMO814TRZlPuUUw3oifHuMR7Wp9SNoRSrxRQnhMLNlCeaODNn6kNTJsjFoQ/kqIj4qGvya4Xg==", + "version": "3.5.33", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.33.tgz", + "integrity": "sha512-UTUvRO9cY+rROrx/pvN9P5Z7FgA6QGfokUCfhQE4EnmUj3rVnK+CHI0LsEO1pg+I7//iRYMUfcNcCPe7tg0CoA==", "license": "MIT", "dependencies": { "@babel/parser": "^7.29.2", - "@vue/compiler-core": "3.5.32", - "@vue/compiler-dom": "3.5.32", - "@vue/compiler-ssr": "3.5.32", - "@vue/shared": "3.5.32", + "@vue/compiler-core": "3.5.33", + "@vue/compiler-dom": "3.5.33", + "@vue/compiler-ssr": "3.5.33", + "@vue/shared": "3.5.33", "estree-walker": "^2.0.2", "magic-string": "^0.30.21", - "postcss": "^8.5.8", + "postcss": "^8.5.10", "source-map-js": "^1.2.1" } }, "node_modules/@vue/compiler-ssr": { - "version": "3.5.32", - "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.32.tgz", - "integrity": "sha512-Gp4gTs22T3DgRotZ8aA/6m2jMR+GMztvBXUBEUOYOcST+giyGWJ4WvFd7QLHBkzTxkfOt8IELKNdpzITLbA2rw==", + "version": "3.5.33", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.33.tgz", + "integrity": "sha512-IErjYdnj1qIupG5xxiVIYiiRvDhGWV4zuh/RCrwfYpuL+HWQzeU6lCk/nF9r7olWMnjKxCAkOctT2qFWFkzb1A==", "license": "MIT", "dependencies": { - "@vue/compiler-dom": "3.5.32", - "@vue/shared": "3.5.32" + "@vue/compiler-dom": "3.5.33", + "@vue/shared": "3.5.33" } }, "node_modules/@vue/devtools-api": { @@ -1331,53 +1331,53 @@ } }, "node_modules/@vue/reactivity": { - "version": "3.5.32", - "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.32.tgz", - "integrity": "sha512-/ORasxSGvZ6MN5gc+uE364SxFdJ0+WqVG0CENXaGW58TOCdrAW76WWaplDtECeS1qphvtBZtR+3/o1g1zL4xPQ==", + "version": "3.5.33", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.33.tgz", + "integrity": "sha512-p8UfIqyIhb0rYGlSgSBV+lPhF2iUSBcRy7enhTmPqKWadHy9kcOFYF1AejYBP9P+avnd3OBbD49DU4pLWX/94A==", "license": "MIT", "dependencies": { - "@vue/shared": "3.5.32" + "@vue/shared": "3.5.33" } }, "node_modules/@vue/runtime-core": { - "version": "3.5.32", - "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.32.tgz", - "integrity": "sha512-pDrXCejn4UpFDFmMd27AcJEbHaLemaE5o4pbb7sLk79SRIhc6/t34BQA7SGNgYtbMnvbF/HHOftYBgFJtUoJUQ==", + "version": "3.5.33", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.33.tgz", + "integrity": "sha512-UpFF45RI9//a7rvq7RdOQblb4tup7hHG9QsmIrxkFQLzQ7R8/iNQ5LE15NhLZ1/WcHMU2b47u6P33CPUelHyIQ==", "license": "MIT", "dependencies": { - "@vue/reactivity": "3.5.32", - "@vue/shared": "3.5.32" + "@vue/reactivity": "3.5.33", + "@vue/shared": "3.5.33" } }, "node_modules/@vue/runtime-dom": { - "version": "3.5.32", - "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.32.tgz", - "integrity": "sha512-1CDVv7tv/IV13V8Nip1k/aaObVbWqRlVCVezTwx3K07p7Vxossp5JU1dcPNhJk3w347gonIUT9jQOGutyJrSVQ==", + "version": "3.5.33", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.33.tgz", + "integrity": "sha512-IOxMsAOwquhfITgmOgaPYl7/j8gKUxUFoflRc+u4LxyD3+783xne8vNta1PONVCvCV9A0w7hkyEepINDqfO0tw==", "license": "MIT", "dependencies": { - "@vue/reactivity": "3.5.32", - "@vue/runtime-core": "3.5.32", - "@vue/shared": "3.5.32", + "@vue/reactivity": "3.5.33", + "@vue/runtime-core": "3.5.33", + "@vue/shared": "3.5.33", "csstype": "^3.2.3" } }, "node_modules/@vue/server-renderer": { - "version": "3.5.32", - "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.32.tgz", - "integrity": "sha512-IOjm2+JQwRFS7W28HNuJeXQle9KdZbODFY7hFGVtnnghF51ta20EWAZJHX+zLGtsHhaU6uC9BGPV52KVpYryMQ==", + "version": "3.5.33", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.33.tgz", + "integrity": "sha512-0xylq/8/h44lVG0pZFknv1XIdEgymq2E9n59uTWJBG+dIgiT0TMCSsxrN7nO16Z0MU0MPjFcguBbZV8Itk52Hw==", "license": "MIT", "dependencies": { - "@vue/compiler-ssr": "3.5.32", - "@vue/shared": "3.5.32" + "@vue/compiler-ssr": "3.5.33", + "@vue/shared": "3.5.33" }, "peerDependencies": { - "vue": "3.5.32" + "vue": "3.5.33" } }, "node_modules/@vue/shared": { - "version": "3.5.32", - "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.32.tgz", - "integrity": "sha512-ksNyrmRQzWJJ8n3cRDuSF7zNNontuJg1YHnmWRJd2AMu8Ij2bqwiiri2lH5rHtYPZjj4STkNcgcmiQqlOjiYGg==", + "version": "3.5.33", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.33.tgz", + "integrity": "sha512-5vR2QIlmaLG77Ygd4pMP6+SGQ5yox9VhtnbDWTy9DzMzdmeLxZ1QqxrywEZ9sa1AVubfIJyaCG3ytyWU81ufcQ==", "license": "MIT" }, "node_modules/@vue/tsconfig": { @@ -5351,9 +5351,9 @@ } }, "node_modules/postcss": { - "version": "8.5.8", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.8.tgz", - "integrity": "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==", + "version": "8.5.10", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.10.tgz", + "integrity": "sha512-pMMHxBOZKFU6HgAZ4eyGnwXF/EvPGGqUr0MnZ5+99485wwW41kW91A4LOGxSHhgugZmSChL5AlElNdwlNgcnLQ==", "funding": [ { "type": "opencollective", @@ -6801,16 +6801,16 @@ "license": "MIT" }, "node_modules/vue": { - "version": "3.5.32", - "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.32.tgz", - "integrity": "sha512-vM4z4Q9tTafVfMAK7IVzmxg34rSzTFMyIe0UUEijUCkn9+23lj0WRfA83dg7eQZIUlgOSGrkViIaCfqSAUXsMw==", + "version": "3.5.33", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.33.tgz", + "integrity": "sha512-1AgChhx5w3ALgT4oK3acm2Es/7jyZhWSVUfs3rOBlGQC0rjEDkS7G4lWlJJGGNQD+BV3reCwbQrOe1mPNwKHBQ==", "license": "MIT", "dependencies": { - "@vue/compiler-dom": "3.5.32", - "@vue/compiler-sfc": "3.5.32", - "@vue/runtime-dom": "3.5.32", - "@vue/server-renderer": "3.5.32", - "@vue/shared": "3.5.32" + "@vue/compiler-dom": "3.5.33", + "@vue/compiler-sfc": "3.5.33", + "@vue/runtime-dom": "3.5.33", + "@vue/server-renderer": "3.5.33", + "@vue/shared": "3.5.33" }, "peerDependencies": { "typescript": "*" diff --git a/webui/package.json b/webui/package.json index c6fdf6a8d..12e334c7c 100644 --- a/webui/package.json +++ b/webui/package.json @@ -41,7 +41,7 @@ "mime-types": "^3.0.2", "ncp": "^2.0.0", "nodemailer": "^8.0.5", - "vue": "^3.5.32", + "vue": "^3.5.33", "vue-router": "^5.0.6", "vue3-ace-editor": "^2.2.4", "whatwg-mimetype": "^5.0.0", From e83d90cded1022f982cf09c438cd26cb49bbc1de Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 24 Apr 2026 08:07:42 +0000 Subject: [PATCH 05/49] build(deps-dev): bump vue-tsc from 3.2.6 to 3.2.7 in /webui Bumps [vue-tsc](https://github.com/vuejs/language-tools/tree/HEAD/packages/tsc) from 3.2.6 to 3.2.7. - [Release notes](https://github.com/vuejs/language-tools/releases) - [Changelog](https://github.com/vuejs/language-tools/blob/master/CHANGELOG.md) - [Commits](https://github.com/vuejs/language-tools/commits/v3.2.7/packages/tsc) --- updated-dependencies: - dependency-name: vue-tsc dependency-version: 3.2.7 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- webui/package-lock.json | 26 +++++++++++++------------- webui/package.json | 2 +- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/webui/package-lock.json b/webui/package-lock.json index 644296fba..35b7b4164 100644 --- a/webui/package-lock.json +++ b/webui/package-lock.json @@ -54,7 +54,7 @@ "prettier": "^3.8.3", "typescript": "~6.0.3", "vite": "^8.0.8", - "vue-tsc": "^3.2.6", + "vue-tsc": "^3.2.7", "xml2js": "^0.6.2" } }, @@ -1302,25 +1302,25 @@ } }, "node_modules/@vue/language-core": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-3.2.6.tgz", - "integrity": "sha512-xYYYX3/aVup576tP/23sEUpgiEnujrENaoNRbaozC1/MA9I6EGFQRJb4xrt/MmUCAGlxTKL2RmT8JLTPqagCkg==", + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-3.2.7.tgz", + "integrity": "sha512-Gn4q/tRxbpVGLEuARQ43p3YELlNAFgRUVCgW9U5Cr+5q4vfD2bWDWpl3ABbJMXUt5xlE1dF8dkigg2aUq7JYYw==", "dev": true, "license": "MIT", "dependencies": { "@volar/language-core": "2.4.28", "@vue/compiler-dom": "^3.5.0", "@vue/shared": "^3.5.0", - "alien-signals": "^3.0.0", + "alien-signals": "^3.1.2", "muggle-string": "^0.4.1", "path-browserify": "^1.0.1", - "picomatch": "^4.0.2" + "picomatch": "^4.0.4" } }, "node_modules/@vue/language-core/node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", "dev": true, "license": "MIT", "engines": { @@ -6916,14 +6916,14 @@ } }, "node_modules/vue-tsc": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/vue-tsc/-/vue-tsc-3.2.6.tgz", - "integrity": "sha512-gYW/kWI0XrwGzd0PKc7tVB/qpdeAkIZLNZb10/InizkQjHjnT8weZ/vBarZoj4kHKbUTZT/bAVgoOr8x4NsQ/Q==", + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/vue-tsc/-/vue-tsc-3.2.7.tgz", + "integrity": "sha512-zc1tL3HoQni1zGTGrwBVRQb7rGP5SWdu/m4rGB6JcnAC5MT5LFZIxF7Y+EJEnt4hGF23d60rXH7gRjHGb5KQQQ==", "dev": true, "license": "MIT", "dependencies": { "@volar/typescript": "2.4.28", - "@vue/language-core": "3.2.6" + "@vue/language-core": "3.2.7" }, "bin": { "vue-tsc": "bin/vue-tsc.js" diff --git a/webui/package.json b/webui/package.json index 12e334c7c..058258f4b 100644 --- a/webui/package.json +++ b/webui/package.json @@ -63,7 +63,7 @@ "prettier": "^3.8.3", "typescript": "~6.0.3", "vite": "^8.0.8", - "vue-tsc": "^3.2.6", + "vue-tsc": "^3.2.7", "xml2js": "^0.6.2" } } From 2f386ecd442b10481720bc9f65a545d41bd50f62 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 24 Apr 2026 08:15:41 +0000 Subject: [PATCH 06/49] build(deps-dev): bump vite from 8.0.8 to 8.0.10 in /webui Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 8.0.8 to 8.0.10. - [Release notes](https://github.com/vitejs/vite/releases) - [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md) - [Commits](https://github.com/vitejs/vite/commits/v8.0.10/packages/vite) --- updated-dependencies: - dependency-name: vite dependency-version: 8.0.10 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- webui/package-lock.json | 196 ++++++++++++++++++++-------------------- webui/package.json | 2 +- 2 files changed, 99 insertions(+), 99 deletions(-) diff --git a/webui/package-lock.json b/webui/package-lock.json index 35b7b4164..ab59e5cc9 100644 --- a/webui/package-lock.json +++ b/webui/package-lock.json @@ -53,7 +53,7 @@ "npm-run-all": "^4.1.5", "prettier": "^3.8.3", "typescript": "~6.0.3", - "vite": "^8.0.8", + "vite": "^8.0.10", "vue-tsc": "^3.2.7", "xml2js": "^0.6.2" } @@ -121,9 +121,9 @@ } }, "node_modules/@emnapi/core": { - "version": "1.9.2", - "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.9.2.tgz", - "integrity": "sha512-UC+ZhH3XtczQYfOlu3lNEkdW/p4dsJ1r/bP7H8+rhao3TTTMO1ATq/4DdIi23XuGoFY+Cz0JmCbdVl0hz9jZcA==", + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz", + "integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==", "dev": true, "license": "MIT", "optional": true, @@ -133,9 +133,9 @@ } }, "node_modules/@emnapi/runtime": { - "version": "1.9.2", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.9.2.tgz", - "integrity": "sha512-3U4+MIWHImeyu1wnmVygh5WlgfYDtyf0k8AbLhMFxOipihf6nrWC4syIm/SwEeec0mNSafiiNnMJwbza/Is6Lw==", + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz", + "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==", "dev": true, "license": "MIT", "optional": true, @@ -346,9 +346,9 @@ } }, "node_modules/@napi-rs/wasm-runtime": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.3.tgz", - "integrity": "sha512-xK9sGVbJWYb08+mTJt3/YV24WxvxpXcXtP6B172paPZ+Ts69Re9dAr7lKwJoeIx8OoeuimEiRZ7umkiUVClmmQ==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.4.tgz", + "integrity": "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==", "dev": true, "license": "MIT", "optional": true, @@ -400,9 +400,9 @@ } }, "node_modules/@oxc-project/types": { - "version": "0.124.0", - "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.124.0.tgz", - "integrity": "sha512-VBFWMTBvHxS11Z5Lvlr3IWgrwhMTXV+Md+EQF0Xf60+wAdsGFTBx7X7K/hP4pi8N7dcm1RvcHwDxZ16Qx8keUg==", + "version": "0.127.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.127.0.tgz", + "integrity": "sha512-aIYXQBo4lCbO4z0R3FHeucQHpF46l2LbMdxRvqvuRuW2OxdnSkcng5B8+K12spgLDj93rtN3+J2Vac/TIO+ciQ==", "dev": true, "license": "MIT", "funding": { @@ -449,9 +449,9 @@ } }, "node_modules/@rolldown/binding-android-arm64": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.15.tgz", - "integrity": "sha512-YYe6aWruPZDtHNpwu7+qAHEMbQ/yRl6atqb/AhznLTnD3UY99Q1jE7ihLSahNWkF4EqRPVC4SiR4O0UkLK02tA==", + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.17.tgz", + "integrity": "sha512-s70pVGhw4zqGeFnXWvAzJDlvxhlRollagdCCKRgOsgUOH3N1l0LIxf83AtGzmb5SiVM4Hjl5HyarMRfdfj3DaQ==", "cpu": [ "arm64" ], @@ -466,9 +466,9 @@ } }, "node_modules/@rolldown/binding-darwin-arm64": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-rc.15.tgz", - "integrity": "sha512-oArR/ig8wNTPYsXL+Mzhs0oxhxfuHRfG7Ikw7jXsw8mYOtk71W0OkF2VEVh699pdmzjPQsTjlD1JIOoHkLP1Fg==", + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-rc.17.tgz", + "integrity": "sha512-4ksWc9n0mhlZpZ9PMZgTGjeOPRu8MB1Z3Tz0Mo02eWfWCHMW1zN82Qz/pL/rC+yQa+8ZnutMF0JjJe7PjwasYw==", "cpu": [ "arm64" ], @@ -483,9 +483,9 @@ } }, "node_modules/@rolldown/binding-darwin-x64": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-rc.15.tgz", - "integrity": "sha512-YzeVqOqjPYvUbJSWJ4EDL8ahbmsIXQpgL3JVipmN+MX0XnXMeWomLN3Fb+nwCmP/jfyqte5I3XRSm7OfQrbyxw==", + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-rc.17.tgz", + "integrity": "sha512-SUSDOI6WwUVNcWxd02QEBjLdY1VPHvlEkw6T/8nYG322iYWCTxRb1vzk4E+mWWYehTp7ERibq54LSJGjmouOsw==", "cpu": [ "x64" ], @@ -500,9 +500,9 @@ } }, "node_modules/@rolldown/binding-freebsd-x64": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-rc.15.tgz", - "integrity": "sha512-9Erhx956jeQ0nNTyif1+QWAXDRD38ZNjr//bSHrt6wDwB+QkAfl2q6Mn1k6OBPerznjRmbM10lgRb1Pli4xZPw==", + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-rc.17.tgz", + "integrity": "sha512-hwnz3nw9dbJ05EDO/PvcjaaewqqDy7Y1rn1UO81l8iIK1GjenME75dl16ajbvSSMfv66WXSRCYKIqfgq2KCfxw==", "cpu": [ "x64" ], @@ -517,9 +517,9 @@ } }, "node_modules/@rolldown/binding-linux-arm-gnueabihf": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-rc.15.tgz", - "integrity": "sha512-cVwk0w8QbZJGTnP/AHQBs5yNwmpgGYStL88t4UIaqcvYJWBfS0s3oqVLZPwsPU6M0zlW4GqjP0Zq5MnAGwFeGA==", + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-rc.17.tgz", + "integrity": "sha512-IS+W7epTcwANmFSQFrS1SivEXHtl1JtuQA9wlxrZTcNi6mx+FDOYrakGevvvTwgj2JvWiK8B29/qD9BELZPyXQ==", "cpu": [ "arm" ], @@ -534,9 +534,9 @@ } }, "node_modules/@rolldown/binding-linux-arm64-gnu": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-rc.15.tgz", - "integrity": "sha512-eBZ/u8iAK9SoHGanqe/jrPnY0JvBN6iXbVOsbO38mbz+ZJsaobExAm1Iu+rxa4S1l2FjG0qEZn4Rc6X8n+9M+w==", + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-rc.17.tgz", + "integrity": "sha512-e6usGaHKW5BMNZOymS1UcEYGowQMWcgZ71Z17Sl/h2+ZziNJ1a9n3Zvcz6LdRyIW5572wBCTH/Z+bKuZouGk9Q==", "cpu": [ "arm64" ], @@ -551,9 +551,9 @@ } }, "node_modules/@rolldown/binding-linux-arm64-musl": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-rc.15.tgz", - "integrity": "sha512-ZvRYMGrAklV9PEkgt4LQM6MjQX2P58HPAuecwYObY2DhS2t35R0I810bKi0wmaYORt6m/2Sm+Z+nFgb0WhXNcQ==", + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-rc.17.tgz", + "integrity": "sha512-b/CgbwAJpmrRLp02RPfhbudf5tZnN9nsPWK82znefso832etkem8H7FSZwxrOI9djcdTP7U6YfNhbRnh7djErg==", "cpu": [ "arm64" ], @@ -568,9 +568,9 @@ } }, "node_modules/@rolldown/binding-linux-ppc64-gnu": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.0-rc.15.tgz", - "integrity": "sha512-VDpgGBzgfg5hLg+uBpCLoFG5kVvEyafmfxGUV0UHLcL5irxAK7PKNeC2MwClgk6ZAiNhmo9FLhRYgvMmedLtnQ==", + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.0-rc.17.tgz", + "integrity": "sha512-4EII1iNGRUN5WwGbF/kOh/EIkoDN9HsupgLQoXfY+D1oyJm7/F4t5PYU5n8SWZgG0FEwakyM8pGgwcBYruGTlA==", "cpu": [ "ppc64" ], @@ -585,9 +585,9 @@ } }, "node_modules/@rolldown/binding-linux-s390x-gnu": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.0-rc.15.tgz", - "integrity": "sha512-y1uXY3qQWCzcPgRJATPSOUP4tCemh4uBdY7e3EZbVwCJTY3gLJWnQABgeUetvED+bt1FQ01OeZwvhLS2bpNrAQ==", + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.0-rc.17.tgz", + "integrity": "sha512-AH8oq3XqQo4IibpVXvPeLDI5pzkpYn0WiZAfT05kFzoJ6tQNzwRdDYQ45M8I/gslbodRZwW8uxLhbSBbkv96rA==", "cpu": [ "s390x" ], @@ -602,9 +602,9 @@ } }, "node_modules/@rolldown/binding-linux-x64-gnu": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-rc.15.tgz", - "integrity": "sha512-023bTPBod7J3Y/4fzAN6QtpkSABR0rigtrwaP+qSEabUh5zf6ELr9Nc7GujaROuPY3uwdSIXWrvhn1KxOvurWA==", + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-rc.17.tgz", + "integrity": "sha512-cLnjV3xfo7KslbU41Z7z8BH/E1y5mzUYzAqih1d1MDaIGZRCMqTijqLv76/P7fyHuvUcfGsIpqCdddbxLLK9rA==", "cpu": [ "x64" ], @@ -619,9 +619,9 @@ } }, "node_modules/@rolldown/binding-linux-x64-musl": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-rc.15.tgz", - "integrity": "sha512-witB2O0/hU4CgfOOKUoeFgQ4GktPi1eEbAhaLAIpgD6+ZnhcPkUtPsoKKHRzmOoWPZue46IThdSgdo4XneOLYw==", + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-rc.17.tgz", + "integrity": "sha512-0phclDw1spsL7dUB37sIARuis2tAgomCJXAHZlpt8PXZ4Ba0dRP1e+66lsRqrfhISeN9bEGNjQs+T/Fbd7oYGw==", "cpu": [ "x64" ], @@ -636,9 +636,9 @@ } }, "node_modules/@rolldown/binding-openharmony-arm64": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-rc.15.tgz", - "integrity": "sha512-UCL68NJ0Ud5zRipXZE9dF5PmirzJE4E4BCIOOssEnM7wLDsxjc6Qb0sGDxTNRTP53I6MZpygyCpY8Aa8sPfKPg==", + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-rc.17.tgz", + "integrity": "sha512-0ag/hEgXOwgw4t8QyQvUCxvEg+V0KBcA6YuOx9g0r02MprutRF5dyljgm3EmR02O292UX7UeS6HzWHAl6KgyhA==", "cpu": [ "arm64" ], @@ -653,9 +653,9 @@ } }, "node_modules/@rolldown/binding-wasm32-wasi": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-rc.15.tgz", - "integrity": "sha512-ApLruZq/ig+nhaE7OJm4lDjayUnOHVUa77zGeqnqZ9pn0ovdVbbNPerVibLXDmWeUZXjIYIT8V3xkT58Rm9u5Q==", + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-rc.17.tgz", + "integrity": "sha512-LEXei6vo0E5wTGwpkJ4KoT3OZJRnglwldt5ziLzOlc6qqb55z4tWNq2A+PFqCJuvWWdP53CVhG1Z9NtToDPJrA==", "cpu": [ "wasm32" ], @@ -663,18 +663,18 @@ "license": "MIT", "optional": true, "dependencies": { - "@emnapi/core": "1.9.2", - "@emnapi/runtime": "1.9.2", - "@napi-rs/wasm-runtime": "^1.1.3" + "@emnapi/core": "1.10.0", + "@emnapi/runtime": "1.10.0", + "@napi-rs/wasm-runtime": "^1.1.4" }, "engines": { - "node": ">=14.0.0" + "node": "^20.19.0 || >=22.12.0" } }, "node_modules/@rolldown/binding-win32-arm64-msvc": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-rc.15.tgz", - "integrity": "sha512-KmoUoU7HnN+Si5YWJigfTws1jz1bKBYDQKdbLspz0UaqjjFkddHsqorgiW1mxcAj88lYUE6NC/zJNwT+SloqtA==", + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-rc.17.tgz", + "integrity": "sha512-gUmyzBl3SPMa6hrqFUth9sVfcLBlYsbMzBx5PlexMroZStgzGqlZ26pYG89rBb45Mnia+oil6YAIFeEWGWhoZA==", "cpu": [ "arm64" ], @@ -689,9 +689,9 @@ } }, "node_modules/@rolldown/binding-win32-x64-msvc": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-rc.15.tgz", - "integrity": "sha512-3P2A8L+x75qavWLe/Dll3EYBJLQmtkJN8rfh+U/eR3MqMgL/h98PhYI+JFfXuDPgPeCB7iZAKiqii5vqOvnA0g==", + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-rc.17.tgz", + "integrity": "sha512-3hkiolcUAvPB9FLb3UZdfjVVNWherN1f/skkGWJP/fgSQhYUZpSIRr0/I8ZK9TkF3F7kxvJAk0+IcKvPHk9qQg==", "cpu": [ "x64" ], @@ -5701,14 +5701,14 @@ "license": "Unlicense" }, "node_modules/rolldown": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-rc.15.tgz", - "integrity": "sha512-Ff31guA5zT6WjnGp0SXw76X6hzGRk/OQq2hE+1lcDe+lJdHSgnSX6nK3erbONHyCbpSj9a9E+uX/OvytZoWp2g==", + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-rc.17.tgz", + "integrity": "sha512-ZrT53oAKrtA4+YtBWPQbtPOxIbVDbxT0orcYERKd63VJTF13zPcgXTvD4843L8pcsI7M6MErt8QtON6lrB9tyA==", "dev": true, "license": "MIT", "dependencies": { - "@oxc-project/types": "=0.124.0", - "@rolldown/pluginutils": "1.0.0-rc.15" + "@oxc-project/types": "=0.127.0", + "@rolldown/pluginutils": "1.0.0-rc.17" }, "bin": { "rolldown": "bin/cli.mjs" @@ -5717,27 +5717,27 @@ "node": "^20.19.0 || >=22.12.0" }, "optionalDependencies": { - "@rolldown/binding-android-arm64": "1.0.0-rc.15", - "@rolldown/binding-darwin-arm64": "1.0.0-rc.15", - "@rolldown/binding-darwin-x64": "1.0.0-rc.15", - "@rolldown/binding-freebsd-x64": "1.0.0-rc.15", - "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.15", - "@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.15", - "@rolldown/binding-linux-arm64-musl": "1.0.0-rc.15", - "@rolldown/binding-linux-ppc64-gnu": "1.0.0-rc.15", - "@rolldown/binding-linux-s390x-gnu": "1.0.0-rc.15", - "@rolldown/binding-linux-x64-gnu": "1.0.0-rc.15", - "@rolldown/binding-linux-x64-musl": "1.0.0-rc.15", - "@rolldown/binding-openharmony-arm64": "1.0.0-rc.15", - "@rolldown/binding-wasm32-wasi": "1.0.0-rc.15", - "@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.15", - "@rolldown/binding-win32-x64-msvc": "1.0.0-rc.15" + "@rolldown/binding-android-arm64": "1.0.0-rc.17", + "@rolldown/binding-darwin-arm64": "1.0.0-rc.17", + "@rolldown/binding-darwin-x64": "1.0.0-rc.17", + "@rolldown/binding-freebsd-x64": "1.0.0-rc.17", + "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.17", + "@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.17", + "@rolldown/binding-linux-arm64-musl": "1.0.0-rc.17", + "@rolldown/binding-linux-ppc64-gnu": "1.0.0-rc.17", + "@rolldown/binding-linux-s390x-gnu": "1.0.0-rc.17", + "@rolldown/binding-linux-x64-gnu": "1.0.0-rc.17", + "@rolldown/binding-linux-x64-musl": "1.0.0-rc.17", + "@rolldown/binding-openharmony-arm64": "1.0.0-rc.17", + "@rolldown/binding-wasm32-wasi": "1.0.0-rc.17", + "@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.17", + "@rolldown/binding-win32-x64-msvc": "1.0.0-rc.17" } }, "node_modules/rolldown/node_modules/@rolldown/pluginutils": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.15.tgz", - "integrity": "sha512-UromN0peaE53IaBRe9W7CjrZgXl90fqGpK+mIZbA3qSTeYqg3pqpROBdIPvOG3F5ereDHNwoHBI2e50n1BDr1g==", + "version": "1.0.0-rc.17", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.17.tgz", + "integrity": "sha512-n8iosDOt6Ig1UhJ2AYqoIhHWh/isz0xpicHTzpKBeotdVsTEcxsSA/i3EVM7gQAj0rU27OLAxCjzlj15IWY7bg==", "dev": true, "license": "MIT" }, @@ -6309,13 +6309,13 @@ } }, "node_modules/tinyglobby": { - "version": "0.2.15", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", - "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "version": "0.2.16", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.16.tgz", + "integrity": "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==", "license": "MIT", "dependencies": { "fdir": "^6.5.0", - "picomatch": "^4.0.3" + "picomatch": "^4.0.4" }, "engines": { "node": ">=12.0.0" @@ -6342,9 +6342,9 @@ } }, "node_modules/tinyglobby/node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", "license": "MIT", "engines": { "node": ">=12" @@ -6688,17 +6688,17 @@ } }, "node_modules/vite": { - "version": "8.0.8", - "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.8.tgz", - "integrity": "sha512-dbU7/iLVa8KZALJyLOBOQ88nOXtNG8vxKuOT4I2mD+Ya70KPceF4IAmDsmU0h1Qsn5bPrvsY9HJstCRh3hG6Uw==", + "version": "8.0.10", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.10.tgz", + "integrity": "sha512-rZuUu9j6J5uotLDs+cAA4O5H4K1SfPliUlQwqa6YEwSrWDZzP4rhm00oJR5snMewjxF5V/K3D4kctsUTsIU9Mw==", "dev": true, "license": "MIT", "dependencies": { "lightningcss": "^1.32.0", "picomatch": "^4.0.4", - "postcss": "^8.5.8", - "rolldown": "1.0.0-rc.15", - "tinyglobby": "^0.2.15" + "postcss": "^8.5.10", + "rolldown": "1.0.0-rc.17", + "tinyglobby": "^0.2.16" }, "bin": { "vite": "bin/vite.js" diff --git a/webui/package.json b/webui/package.json index 058258f4b..b1bfeef1e 100644 --- a/webui/package.json +++ b/webui/package.json @@ -62,7 +62,7 @@ "npm-run-all": "^4.1.5", "prettier": "^3.8.3", "typescript": "~6.0.3", - "vite": "^8.0.8", + "vite": "^8.0.10", "vue-tsc": "^3.2.7", "xml2js": "^0.6.2" } From 3552ed25145f11e3ce14da3721e58f21de2f0833 Mon Sep 17 00:00:00 2001 From: marle3003 Date: Sun, 26 Apr 2026 14:05:39 +0200 Subject: [PATCH 07/49] feat(search): improve search feature and displaying results in dashboard feat(mcp): add search feature --- acceptance/petstore_test.go | 2 +- engine/common/host.go | 11 + engine/host.go | 3 +- mcp/data/automation-core.md | 57 +++++ mcp/data/automation.md | 30 ++- mcp/run.go | 47 +++++ mcp/run_events.go | 12 ++ mcp/run_events_test.go | 40 +++- mcp/run_test.go | 208 +++++++++++++++++++ providers/asyncapi3/asyncapi3test/channel.go | 12 ++ providers/asyncapi3/kafka/store/log.go | 29 +++ providers/directory/log.go | 53 ++++- providers/directory/search_test.go | 31 +-- providers/mail/log.go | 4 + providers/openapi/log.go | 10 + runtime/events/events.go | 1 + runtime/events/eventstest/event.go | 11 +- runtime/events/index.go | 57 +++-- runtime/events/index_test.go | 6 +- runtime/index.go | 51 ++++- runtime/index_test.go | 6 +- runtime/runtime_http_search.go | 124 ++++++++--- runtime/runtime_http_search_test.go | 7 +- runtime/runtime_kafka_search.go | 19 +- runtime/runtime_kafka_search_test.go | 53 ++++- runtime/runtime_ldap_search.go | 27 ++- runtime/runtime_ldap_search_test.go | 2 + runtime/runtime_search_test.go | 27 +++ webui/e2e/mocks/http_handler.js | 66 ++++-- webui/src/components/dashboard/Search.vue | 116 +++++++---- webui/src/composables/usePrettyText.ts | 33 ++- 31 files changed, 988 insertions(+), 167 deletions(-) diff --git a/acceptance/petstore_test.go b/acceptance/petstore_test.go index 82f95c753..a309e0d46 100644 --- a/acceptance/petstore_test.go +++ b/acceptance/petstore_test.go @@ -389,7 +389,7 @@ func (suite *PetStoreSuite) TestSearch_Paging() { assert.Len(t, items, 10) evt := items[0].(map[string]interface{}) assert.Equal(t, "HTTP", evt["type"]) - assert.Equal(t, "GET /pet/{petId}", evt["title"]) + assert.Equal(t, "/pet/{petId}", evt["title"]) assert.Equal(t, "Swagger Petstore", evt["domain"]) }), ) diff --git a/engine/common/host.go b/engine/common/host.go index ef67cf24b..e9ad29b78 100644 --- a/engine/common/host.go +++ b/engine/common/host.go @@ -176,9 +176,20 @@ func (e *JobExecution) AppendLog(level, message string) { } func (e *JobExecution) Title() string { + if e.Error != nil { + return fmt.Sprintf("Error in: %v", e.Tags["name"]) + } return e.Tags["name"] } +func (e *JobExecution) Metadata() map[string]string { + return nil +} + +func (e *JobExecution) Domain() string { + return "Job Execution" +} + type FakerNode interface { Name() string Fake(r *generator.Request) (interface{}, error) diff --git a/engine/host.go b/engine/host.go index 0690843ba..269115f39 100644 --- a/engine/host.go +++ b/engine/host.go @@ -102,8 +102,9 @@ func (sh *scriptHost) Cron(expr string, handler func(), opt common.JobOptions) ( } func (sh *scriptHost) newJobFunc(handler func(), opt common.JobOptions, schedule string, id int) func() { + name := filepath.Base(sh.name) tags := map[string]string{ - "name": sh.name, + "name": name, "file": sh.name, "fileKey": sh.file.Info.Key(), } diff --git a/mcp/data/automation-core.md b/mcp/data/automation-core.md index 7e35fc17c..55b15d81b 100644 --- a/mcp/data/automation-core.md +++ b/mcp/data/automation-core.md @@ -44,6 +44,35 @@ interface Mokapi { * getEvents({ apiType: 'http', name: 'Swagger Petstore', path: '/pets' }) */ getEvents(traits: HttpTraits | KafkaTraits, limit?: number): Event[]; + + /** + * Returns a specific event from Mokapi based on the id + * @param id The id of the event + * @example + * getEvent('6cbca4f8-ea25-4f66-861c-44d8b15321b1') + */ + getEvent(id: string): Event[]; + + /** + * Advanced Search across all APIs, Topics, and Documentation. + * By default, multiple terms are combined with OR (results contain at least one term). Use prefixes to enforce stricter matches. + * + * QUERY SYNTAX: + * - Simple: `petstore` (Search in all fields) + * Type: `type:kafka` (Search only Kafka) + * - Exact: `"Swagger Petstore"` (Use quotes for phrases) + * - Exclude: `petstore -kafka` (Exclude terms with '-') + * - Wildcard: `pet*` (Matches "pet", "pets", "petstore") + * - Fuzy: `pet~` (Matches "pets", "pest" or slight typos) + * - Fields: `name:petstore`, `path:/pets`, `description:dog` + * - Boosting: `path:/pets^2` (Make path matches more important) + * - Numeric Ranges: `statusCode:>=200 + * + * @param queryText The search term or complex query string. + * @param index Page index for pagination (starts at 0). + * @param limit Number of results (default 10). + */ + search(queryText: string, index?: number, limit?: number): SearchResult } type ApiType = 'http' | 'kafka' | 'ldap' | 'mail' @@ -53,6 +82,33 @@ interface ApiSummary { type: ApiType; } +interface SearchResult { + items: SearchResultItem[] + total: number +} + +interface SearchResultItem { + /** The type of the resource (e.g., 'http', 'kafka', 'event') */ + type: string + /** The name of the API */ + domain: string + /** A human-readable title or summary */ + title: string + /** + * Relevant text snippets showing where the match was found. + * Useful to see context like 'GET /pets' or 'Topic: orders'. + */ + fragments: string[] + /** + * Additional context specific to the result type. + * - HTTP: includes 'method', 'path', 'service' + * - Kafka: includes 'topic', 'service' + */ + metadata: Record + + time?: string +} + /** * JSON Schema defines a JSON-based format for describing the structure of JSON data * @example @@ -201,4 +257,5 @@ interface Schema { } type SchemaType = "object" | "array" | "number" | "integer" | "string" | "boolean" | "null"; + ``` \ No newline at end of file diff --git a/mcp/data/automation.md b/mcp/data/automation.md index 9be899ad3..8c87d6ea5 100644 --- a/mcp/data/automation.md +++ b/mcp/data/automation.md @@ -39,4 +39,32 @@ mokapi.getEvents() Get latest HTTP events for a specific API ```typescript mokapi.getEvents({ type: 'http', name: 'Petstore' }) -``` \ No newline at end of file +``` + +Search for all POST endpoints related to "payments". +```typescript +// 1. Search for a specific capability +const searchResponse = mokapi.search("method:POST AND path:*payments*"); +let op = null +if (searchResponse.items.length > 0) { + const match = searchResponse.items[0]; + + // 2. Use metadata to load the full API specification + const api = mokapi.getApi(match.metadata.service); + + // 3. Find the specific operation to see allowed status codes/schemas + // Tip: Use the path from metadata to identify the correct operation + const opSummary = api.getOperations().find(x => x.path === match.metadata.path && x.method === match.metadata.method); + + if (opSummary) { + op = api.getOperation(opSummary.id); + } +} +op +``` + +Search for errors (404 or 500) related to the Petstore +```typescript +const errors = mokapi.search('+api:"Petstore" +event.data.response.statusCode:>=400 +type:event') +errors.items.map(x => mokapi.getEvent(x.metadata.id)) +``` diff --git a/mcp/run.go b/mcp/run.go index 3479b7847..9e13a6bfd 100644 --- a/mcp/run.go +++ b/mcp/run.go @@ -9,6 +9,7 @@ import ( "mokapi/js/faker" "mokapi/providers/openapi" "mokapi/runtime" + "mokapi/runtime/search" "mokapi/schema/json/generator" "reflect" "slices" @@ -136,6 +137,8 @@ func (m *mokapi) init(obj *goja.Object) { _ = obj.Set("getApi", m.getApi) _ = obj.Set("fake", m.fake) _ = obj.Set("getEvents", m.getEvents) + _ = obj.Set("getEvent", m.getEvent) + _ = obj.Set("search", m.search) } func (m *mokapi) getApis() []ApiSummary { @@ -184,6 +187,50 @@ func (m *mokapi) fake(v goja.Value) (any, error) { return generator.New(&generator.Request{Schema: js}) } +type SearchResult struct { + Items []SearchResultItem `json:"items"` + Total uint64 `json:"total"` +} + +type SearchResultItem struct { + Type string `json:"type"` + Domain string `json:"domain,omitempty"` + Title string `json:"title"` + Fragments []string `json:"fragments,omitempty"` + Metadata map[string]string `json:"metadata"` + Time string `json:"time,omitempty"` +} + +func (m *mokapi) search(queryText string, index int, limit int) (SearchResult, error) { + if limit == 0 { + limit = 10 + } + r := search.Request{ + QueryText: queryText, + Index: index, + Limit: limit, + } + + sr, err := m.app.Search(r) + if err != nil { + return SearchResult{}, err + } + result := SearchResult{ + Total: sr.Total, + } + for _, item := range sr.Results { + result.Items = append(result.Items, SearchResultItem{ + Type: item.Type, + Domain: item.Domain, + Title: item.Title, + Fragments: item.Fragments, + Metadata: item.Params, + Time: item.Time, + }) + } + return result, nil +} + type customFieldNameMapper struct { } diff --git a/mcp/run_events.go b/mcp/run_events.go index f926f4b23..9ed110f72 100644 --- a/mcp/run_events.go +++ b/mcp/run_events.go @@ -32,6 +32,18 @@ func (m *mokapi) getEvents(vTraits goja.Value, vLimit goja.Value) ([]events.Even } } +func (m *mokapi) getEvent(id string) (events.Event, error) { + if id == "" { + return events.Event{}, fmt.Errorf("expected id parameter in GUID format, got '%v'", id) + } + + e := m.app.Events.GetEvent(id) + if e.Id == "" { + return e, fmt.Errorf("event %s not found. Use `mokapi.search('type:event ...')` to search for existing events", id) + } + return e, nil +} + func parseTraits(v goja.Value, vm *goja.Runtime) (events.Traits, error) { traits := events.Traits{} diff --git a/mcp/run_events_test.go b/mcp/run_events_test.go index c1f222439..92e1ad520 100644 --- a/mcp/run_events_test.go +++ b/mcp/run_events_test.go @@ -19,12 +19,14 @@ func (t *testEvent) Title() string { return t.Name } +func (t *testEvent) Metadata() map[string]string { return nil } + func TestEvents(t *testing.T) { testcases := []struct { name string app *runtime.App code string - test func(t *testing.T, evts []events.Event, err error) + test func(t *testing.T, result any, err error) }{ { name: "without params should not error", @@ -32,8 +34,10 @@ func TestEvents(t *testing.T) { app: runtimetest.NewApp( runtimetest.WithEvent(events.NewTraits().WithNamespace("http"), &testEvent{Name: "test-1"}), ), - test: func(t *testing.T, evts []events.Event, err error) { + test: func(t *testing.T, result any, err error) { require.NoError(t, err) + require.IsType(t, []events.Event{}, result) + evts := result.([]events.Event) require.Len(t, evts, 1) require.Equal(t, &testEvent{Name: "test-1"}, evts[0].Data) }, @@ -45,8 +49,10 @@ func TestEvents(t *testing.T) { runtimetest.WithEvent(events.NewTraits().WithNamespace("kafka"), &testEvent{Name: "test-1"}), runtimetest.WithEvent(events.NewTraits().WithNamespace("http"), &testEvent{Name: "test-2"}), ), - test: func(t *testing.T, evts []events.Event, err error) { + test: func(t *testing.T, result any, err error) { require.NoError(t, err) + require.IsType(t, []events.Event{}, result) + evts := result.([]events.Event) require.Len(t, evts, 1) require.Equal(t, &testEvent{Name: "test-2"}, evts[0].Data) }, @@ -58,8 +64,10 @@ func TestEvents(t *testing.T) { runtimetest.WithEvent(events.NewTraits().WithNamespace("http").WithName("foo"), &testEvent{Name: "test-1"}), runtimetest.WithEvent(events.NewTraits().WithNamespace("http").WithName("bar"), &testEvent{Name: "test-2"}), ), - test: func(t *testing.T, evts []events.Event, err error) { + test: func(t *testing.T, result any, err error) { require.NoError(t, err) + require.IsType(t, []events.Event{}, result) + evts := result.([]events.Event) require.Len(t, evts, 1) require.Equal(t, &testEvent{Name: "test-2"}, evts[0].Data) }, @@ -71,8 +79,10 @@ func TestEvents(t *testing.T) { runtimetest.WithEvent(events.NewTraits().WithNamespace("http").With("path", "/users"), &testEvent{Name: "test-1"}), runtimetest.WithEvent(events.NewTraits().WithNamespace("http").With("path", "/pets"), &testEvent{Name: "test-2"}), ), - test: func(t *testing.T, evts []events.Event, err error) { + test: func(t *testing.T, result any, err error) { require.NoError(t, err) + require.IsType(t, []events.Event{}, result) + evts := result.([]events.Event) require.Len(t, evts, 1) require.Equal(t, &testEvent{Name: "test-2"}, evts[0].Data) }, @@ -84,12 +94,27 @@ func TestEvents(t *testing.T) { runtimetest.WithEvent(events.NewTraits().WithNamespace("http").With("method", "GET"), &testEvent{Name: "test-1"}), runtimetest.WithEvent(events.NewTraits().WithNamespace("http").With("method", "POST"), &testEvent{Name: "test-2"}), ), - test: func(t *testing.T, evts []events.Event, err error) { + test: func(t *testing.T, result any, err error) { require.NoError(t, err) + require.IsType(t, []events.Event{}, result) + evts := result.([]events.Event) require.Len(t, evts, 1) require.Equal(t, &testEvent{Name: "test-2"}, evts[0].Data) }, }, + { + name: "get specific event", + code: "mokapi.getEvent(mokapi.getEvents({ method: 'GET' })[0].id)", + app: runtimetest.NewApp( + runtimetest.WithEvent(events.NewTraits().WithNamespace("http").With("method", "GET"), &testEvent{Name: "test-1"}), + ), + test: func(t *testing.T, result any, err error) { + require.NoError(t, err) + require.IsType(t, events.Event{}, result) + evt := result.(events.Event) + require.Equal(t, &testEvent{Name: "test-1"}, evt.Data) + }, + }, } for _, tc := range testcases { @@ -100,9 +125,8 @@ func TestEvents(t *testing.T) { context.Background(), mcp.RunInput{Code: tc.code}, ) - require.IsType(t, []events.Event{}, r.Result) - tc.test(t, r.Result.([]events.Event), err) + tc.test(t, r.Result, err) }) } } diff --git a/mcp/run_test.go b/mcp/run_test.go index 2a84478eb..9108d6dcf 100644 --- a/mcp/run_test.go +++ b/mcp/run_test.go @@ -2,12 +2,21 @@ package mcp_test import ( "context" + "mokapi/config/dynamic" + "mokapi/config/dynamic/dynamictest" + "mokapi/config/static" "mokapi/mcp" + "mokapi/providers/openapi" "mokapi/providers/openapi/openapitest" "mokapi/runtime" + "mokapi/runtime/events" "mokapi/runtime/runtimetest" + "mokapi/runtime/search" + "mokapi/safe" "mokapi/schema/json/generator" + "net/http" "testing" + "time" "github.com/stretchr/testify/require" ) @@ -92,3 +101,202 @@ To ensure you are using the correct global variables and methods: }) } } + +func TestService_Run_Search(t *testing.T) { + testcases := []struct { + name string + app *runtime.App + test func(t *testing.T, s *mcp.Service, app *runtime.App) + }{ + { + name: "search", + app: func() *runtime.App { + app := runtime.New( + &static.Config{ + Api: static.Api{ + Search: static.Search{ + Enabled: true, + InMemory: true, + }, + }, + }, &dynamictest.Reader{}) + app.AddHttp(&dynamic.Config{ + Info: dynamictest.NewConfigInfo(), + Data: openapitest.NewConfig("3.1.0", + openapitest.WithInfo("foo", "", ""), + openapitest.WithPath("/foo/payment/bar", + openapitest.WithOperation(http.MethodPost, + openapitest.WithOperationSummary("Payment summary"), + ), + ), + ), + }) + return app + }(), + test: func(t *testing.T, s *mcp.Service, app *runtime.App) { + pool := safe.NewPool(context.Background()) + app.Start(pool) + defer pool.Stop() + waitSearchIndex(t, func() bool { + r, err := app.Search(search.Request{QueryText: "foo", Limit: 10}) + require.NoError(t, err) + return len(r.Results) > 0 + }) + r, err := s.GetRunResponse( + context.Background(), + mcp.RunInput{ + Code: `mokapi.search("method:POST AND path:*payments*")`, + }, + ) + require.NoError(t, err) + require.Equal(t, mcp.SearchResult{Items: []mcp.SearchResultItem{ + { + Type: "HTTP", + Domain: "foo", + Title: "/foo/payment/bar", + Fragments: []string{"POST"}, + Metadata: map[string]string{"method": "POST", "path": "/foo/payment/bar", "service": "foo", "type": "http"}, + Time: "", + }}, Total: 1}, r.Result) + + r, err = s.GetRunResponse( + context.Background(), + mcp.RunInput{Code: `const searchResponse = mokapi.search("method:POST AND path:*payments*"); +let op = null +if (searchResponse.items.length > 0) { + const match = searchResponse.items[0]; + const api = mokapi.getApi(match.metadata.service); + const opSummary = api.getOperations().find(x => x.path === match.metadata.path && x.method === match.metadata.method); + if (opSummary) { + op = api.getOperation(opSummary.id); + } +} +op`}, + ) + require.NoError(t, err) + require.IsType(t, &mcp.Operation{}, r.Result) + op := r.Result.(*mcp.Operation) + require.Equal(t, "/foo/payment/bar", op.Path) + }, + }, + { + name: "search for event", + app: func() *runtime.App { + app := runtime.New( + &static.Config{ + Api: static.Api{ + Search: static.Search{ + Enabled: true, + InMemory: true, + }, + }, + }, &dynamictest.Reader{}) + app.AddHttp(&dynamic.Config{ + Info: dynamictest.NewConfigInfo(), + Data: openapitest.NewConfig("3.1.0", + openapitest.WithInfo("Petstore", "", ""), + openapitest.WithPath("/pets", + openapitest.WithOperation(http.MethodPost, + openapitest.WithOperationSummary("Payment summary"), + ), + ), + ), + }) + err := app.Events.Push(&openapi.HttpLog{ + Request: &openapi.HttpRequestLog{ + Method: http.MethodPost, + Url: "/pets", + }, + Response: &openapi.HttpResponseLog{ + StatusCode: http.StatusNotFound, + }, + }, events.NewTraits().WithNamespace("http").WithName("Petstore")) + require.NoError(t, err) + err = app.Events.Push(&openapi.HttpLog{ + Request: &openapi.HttpRequestLog{ + Method: http.MethodDelete, + Url: "/pets", + }, + Response: &openapi.HttpResponseLog{ + StatusCode: http.StatusInternalServerError, + }, + }, events.NewTraits().WithNamespace("http").WithName("Petstore")) + require.NoError(t, err) + err = app.Events.Push(&openapi.HttpLog{ + Request: &openapi.HttpRequestLog{ + Method: http.MethodGet, + Url: "/pets", + }, + Response: &openapi.HttpResponseLog{ + StatusCode: http.StatusOK, + }, + }, events.NewTraits().WithNamespace("http").WithName("Petstore")) + require.NoError(t, err) + return app + }(), + test: func(t *testing.T, s *mcp.Service, app *runtime.App) { + pool := safe.NewPool(context.Background()) + app.Start(pool) + defer pool.Stop() + waitSearchIndex(t, func() bool { + r, err := app.Search(search.Request{QueryText: "Petstore", Limit: 10}) + require.NoError(t, err) + return len(r.Results) > 0 + }) + r, err := s.GetRunResponse( + context.Background(), + mcp.RunInput{ + Code: `const errors = mokapi.search('+api:"Petstore" +event.data.response.statusCode:>=400 +type:event') +errors.items.map(x => mokapi.getEvent(x.metadata.id))`, + }, + ) + require.NoError(t, err) + require.IsType(t, []any{}, r.Result) + evts := r.Result.([]any) + require.Len(t, evts, 2) + evt := evts[0] + require.IsType(t, events.Event{}, evt) + d1 := evts[0].(events.Event).Data.(*openapi.HttpLog) + d2 := evts[1].(events.Event).Data.(*openapi.HttpLog) + var evt404 *openapi.HttpLog + var evt500 *openapi.HttpLog + if d1.Response.StatusCode == http.StatusNotFound { + evt404 = d1 + evt500 = d2 + } else if d2.Response.StatusCode == http.StatusNotFound { + evt404 = d2 + evt500 = d1 + } + + require.NotNil(t, evt404) + require.NotNil(t, evt500) + + require.Equal(t, http.MethodPost, evt404.Request.Method) + require.Equal(t, http.MethodDelete, evt500.Request.Method) + }, + }, + } + + for _, tc := range testcases { + t.Run(tc.name, func(t *testing.T) { + generator.Seed(123456) + + s := mcp.NewService(tc.app) + tc.test(t, s, tc.app) + }) + } +} + +func waitSearchIndex(t *testing.T, check func() bool) { + deadline := time.Now().Add(2 * time.Second) + + for { + if check() { + break + } + if time.Now().After(deadline) { + t.Fatal("wait search index reached deadline") + } + time.Sleep(20 * time.Millisecond) + } +} diff --git a/providers/asyncapi3/asyncapi3test/channel.go b/providers/asyncapi3/asyncapi3test/channel.go index 194f46e3b..640b4595a 100644 --- a/providers/asyncapi3/asyncapi3test/channel.go +++ b/providers/asyncapi3/asyncapi3test/channel.go @@ -43,6 +43,18 @@ func WithKafkaChannelBinding(bindings asyncapi3.TopicBindings) ChannelOptions { } } +func WithChannelAddress(address string) ChannelOptions { + return func(c *asyncapi3.Channel) { + c.Address = address + } +} + +func WithChannelName(name string) ChannelOptions { + return func(c *asyncapi3.Channel) { + c.Name = name + } +} + func WithChannelTitle(title string) ChannelOptions { return func(c *asyncapi3.Channel) { c.Title = title diff --git a/providers/asyncapi3/kafka/store/log.go b/providers/asyncapi3/kafka/store/log.go index cca696fab..3dbdda1a9 100644 --- a/providers/asyncapi3/kafka/store/log.go +++ b/providers/asyncapi3/kafka/store/log.go @@ -39,6 +39,10 @@ func (l *KafkaMessageLog) Title() string { } } +func (l *KafkaMessageLog) Metadata() map[string]string { + return nil +} + func newKafkaLog(record *kafka.Record) *KafkaMessageLog { return &KafkaMessageLog{ Key: LogValue{Binary: kafka.Read(record.Key)}, @@ -79,8 +83,13 @@ func (l *KafkaRequestLogEvent) Title() string { return l.Request.Title() } +func (l *KafkaRequestLogEvent) Metadata() map[string]string { + return nil +} + type KafkaRequest interface { Title() string + Metadata() map[string]string } type KafkaRequestHeader struct { @@ -111,6 +120,10 @@ func (r *KafkaJoinGroupRequest) Title() string { return fmt.Sprintf("JoinGroup %s", r.GroupName) } +func (l *KafkaJoinGroupRequest) Metadata() map[string]string { + return nil +} + type KafkaJoinGroupResponse struct { KafkaResponseError GenerationId int32 `json:"generationId"` @@ -138,6 +151,10 @@ func (r *KafkaSyncGroupRequest) Title() string { return fmt.Sprintf("SyncGroup %s", r.GroupName) } +func (r *KafkaSyncGroupRequest) Metadata() map[string]string { + return nil +} + type KafkaSyncGroupResponse struct { KafkaResponseError ProtocolType string `json:"protocolType"` @@ -153,6 +170,10 @@ func (r *KafkaListOffsetsRequest) Title() string { return "ListOffsets" } +func (r *KafkaListOffsetsRequest) Metadata() map[string]string { + return nil +} + type KafkaListOffsetsRequestPartition struct { Partition int `json:"partition"` Timestamp int64 `json:"timestamp"` @@ -183,6 +204,10 @@ func (r *KafkaFindCoordinatorRequest) Title() string { return "FindCoordinator" } +func (r *KafkaFindCoordinatorRequest) Metadata() map[string]string { + return nil +} + type KafkaFindCoordinatorResponse struct { KafkaResponseError Host string `json:"host"` @@ -201,6 +226,10 @@ func (r *KafkaInitProducerIdRequest) Title() string { return "InitProducerId" } +func (r *KafkaInitProducerIdRequest) Metadata() map[string]string { + return nil +} + type KafkaInitProducerIdResponse struct { KafkaResponseError ProducerId int64 `json:"producerId"` diff --git a/providers/directory/log.go b/providers/directory/log.go index fb8476699..5645d4385 100644 --- a/providers/directory/log.go +++ b/providers/directory/log.go @@ -44,7 +44,7 @@ func NewSearchLogEvent(r *ldap.SearchRequest, eh events.Handler, traits events.T Duration: 0, Actions: nil, } - _ = eh.Push(event, traits.WithNamespace("ldap")) + _ = eh.Push(event, traits.WithNamespace("ldap").With("operation", "search")) return event } @@ -127,13 +127,13 @@ func NewBindLogEvent(req *ldap.BindRequest, res *ldap.BindResponse, eh events.Ha Duration: 0, Actions: nil, } - _ = eh.Push(l, traits.WithNamespace("ldap")) + _ = eh.Push(l, traits.WithNamespace("ldap").With("operation", "bind")) return l } func NewUnbindEvent(eh events.Handler, traits events.Traits) *UnbindLog { l := &UnbindLog{Request: &UnbindRequest{Operation: "Unbind"}} - _ = eh.Push(l, traits.WithNamespace("ldap")) + _ = eh.Push(l, traits.WithNamespace("ldap").With("operation", "unbind")) return l } @@ -160,7 +160,7 @@ func NewAddLogEvent(req *ldap.AddRequest, res *ldap.AddResponse, eh events.Handl Duration: 0, Actions: nil, } - _ = eh.Push(l, traits.WithNamespace("ldap")) + _ = eh.Push(l, traits.WithNamespace("ldap").With("operation", "add")) return l } @@ -209,7 +209,7 @@ func NewModifyLogEvent(req *ldap.ModifyRequest, res *ldap.ModifyResponse, eh eve Duration: 0, Actions: nil, } - _ = eh.Push(l, traits.WithNamespace("ldap")) + _ = eh.Push(l, traits.WithNamespace("ldap").With("operation", "modify")) return l } @@ -240,7 +240,7 @@ func NewDeleteLogEvent(req *ldap.DeleteRequest, res *ldap.DeleteResponse, eh eve Duration: 0, Actions: nil, } - _ = eh.Push(l, traits.WithNamespace("ldap")) + _ = eh.Push(l, traits.WithNamespace("ldap").With("operation", "delete")) return l } @@ -277,7 +277,7 @@ func NewModifyDNLogEvent(req *ldap.ModifyDNRequest, res *ldap.ModifyDNResponse, Duration: 0, Actions: nil, } - _ = eh.Push(l, traits.WithNamespace("ldap")) + _ = eh.Push(l, traits.WithNamespace("ldap").With("operation", "modifydn")) return l } @@ -311,7 +311,7 @@ func NewCompareLogEvent(req *ldap.CompareRequest, res *ldap.CompareResponse, eh Duration: 0, Actions: nil, } - _ = eh.Push(l, traits.WithNamespace("ldap")) + _ = eh.Push(l, traits.WithNamespace("ldap").With("operation", "compare")) return l } @@ -320,30 +320,67 @@ func (l *BindLog) Title() string { return fmt.Sprintf("%s %s %s", l.Request.Auth, l.Request.Name, l.Request.Password) } +func (l *BindLog) Metadata() map[string]string { + return nil +} + func (l *UnbindLog) Title() string { return "" } +func (l *UnbindLog) Metadata() map[string]string { + return nil +} + func (l *SearchLog) Title() string { return l.Request.Filter } +func (l *SearchLog) Metadata() map[string]string { + if l.Request.BaseDN != "" { + return map[string]string{ + "baseDn": l.Request.BaseDN, + } + } + return nil +} + func (l *CompareLog) Title() string { return fmt.Sprintf("%s %s", l.Request.Operation, l.Request.Value) } +func (l *CompareLog) Metadata() map[string]string { + return nil +} + func (l *ModifyLog) Title() string { return fmt.Sprintf("%s %s", l.Request.Operation, l.Request.Dn) } +func (l *ModifyLog) Metadata() map[string]string { + return nil +} + func (l *ModifyDNLog) Title() string { return fmt.Sprintf("%s %s", l.Request.Operation, l.Request.Dn) } +func (l *ModifyDNLog) Metadata() map[string]string { + return nil +} + func (l *DeleteLog) Title() string { return fmt.Sprintf("%s %s", l.Request.Operation, l.Request.Dn) } +func (l *DeleteLog) Metadata() map[string]string { + return nil +} + func (l *AddLog) Title() string { return fmt.Sprintf("%s %s", l.Request.Operation, l.Request.Dn) } + +func (l *AddLog) Metadata() map[string]string { + return nil +} diff --git a/providers/directory/search_test.go b/providers/directory/search_test.go index 807fd4881..069515c82 100644 --- a/providers/directory/search_test.go +++ b/providers/directory/search_test.go @@ -10,6 +10,7 @@ import ( "mokapi/ldap" "mokapi/ldap/ldaptest" "mokapi/providers/directory" + "mokapi/runtime/events" "mokapi/runtime/events/eventstest" "mokapi/try" "strings" @@ -481,7 +482,7 @@ func TestSearch(t *testing.T) { name string input string reader dynamic.Reader - test func(t *testing.T, h ldap.Handler, err error) + test func(t *testing.T, h ldap.Handler, eh events.Handler, err error) }{ { name: "presence", @@ -489,7 +490,7 @@ func TestSearch(t *testing.T) { reader: &dynamictest.Reader{Data: map[string]*dynamic.Config{ "file:/users.ldif": {Raw: []byte("dn: cn=user\nmail: user@foo.com")}, }}, - test: func(t *testing.T, h ldap.Handler, err error) { + test: func(t *testing.T, h ldap.Handler, eh events.Handler, err error) { require.NoError(t, err) rr := ldaptest.NewRecorder() @@ -500,6 +501,10 @@ func TestSearch(t *testing.T) { res := rr.Message.(*ldap.SearchResponse) require.Len(t, res.Results, 1) + + evts := eh.GetEvents(events.NewTraits()) + require.Len(t, evts, 1) + require.Equal(t, "search", evts[0].Traits.Get("operation")) }, }, { @@ -508,7 +513,7 @@ func TestSearch(t *testing.T) { reader: &dynamictest.Reader{Data: map[string]*dynamic.Config{ "file:/users.ldif": {Raw: []byte("dn: cn=user\ncn: Smith")}, }}, - test: func(t *testing.T, h ldap.Handler, err error) { + test: func(t *testing.T, h ldap.Handler, eh events.Handler, err error) { require.NoError(t, err) rr := ldaptest.NewRecorder() @@ -527,7 +532,7 @@ func TestSearch(t *testing.T) { reader: &dynamictest.Reader{Data: map[string]*dynamic.Config{ "file:/users.ldif": {Raw: []byte("dn: cn=user\ndescription: Software Developers")}, }}, - test: func(t *testing.T, h ldap.Handler, err error) { + test: func(t *testing.T, h ldap.Handler, eh events.Handler, err error) { require.NoError(t, err) rr := ldaptest.NewRecorder() @@ -546,7 +551,7 @@ func TestSearch(t *testing.T) { reader: &dynamictest.Reader{Data: map[string]*dynamic.Config{ "file:/users.ldif": {Raw: []byte("dn: cn=user\ndescription: Software Developers")}, }}, - test: func(t *testing.T, h ldap.Handler, err error) { + test: func(t *testing.T, h ldap.Handler, eh events.Handler, err error) { require.NoError(t, err) rr := ldaptest.NewRecorder() @@ -565,7 +570,7 @@ func TestSearch(t *testing.T) { reader: &dynamictest.Reader{Data: map[string]*dynamic.Config{ "file:/users.ldif": {Raw: []byte("dn: cn=user\nuserAccountControl: 512")}, }}, - test: func(t *testing.T, h ldap.Handler, err error) { + test: func(t *testing.T, h ldap.Handler, eh events.Handler, err error) { require.NoError(t, err) rr := ldaptest.NewRecorder() @@ -584,7 +589,7 @@ func TestSearch(t *testing.T) { reader: &dynamictest.Reader{Data: map[string]*dynamic.Config{ "file:/users.ldif": {Raw: []byte("dn: cn=user\n\ndn: cn=group\nmember: cn=user")}, }}, - test: func(t *testing.T, h ldap.Handler, err error) { + test: func(t *testing.T, h ldap.Handler, eh events.Handler, err error) { require.NoError(t, err) rr := ldaptest.NewRecorder() @@ -603,7 +608,7 @@ func TestSearch(t *testing.T) { reader: &dynamictest.Reader{Data: map[string]*dynamic.Config{ "file:/users.ldif": {Raw: []byte("dn: cn=uSEr\n\ndn: cn=group\nmember: cn=UseR")}, }}, - test: func(t *testing.T, h ldap.Handler, err error) { + test: func(t *testing.T, h ldap.Handler, eh events.Handler, err error) { require.NoError(t, err) rr := ldaptest.NewRecorder() @@ -622,7 +627,7 @@ func TestSearch(t *testing.T) { reader: &dynamictest.Reader{Data: map[string]*dynamic.Config{ "file:/users.ldif": {Raw: []byte("dn: uid=ff, cn=user\n\ndn: uid=cc,cn=group\nmember: uid=ff,cn=user")}, }}, - test: func(t *testing.T, h ldap.Handler, err error) { + test: func(t *testing.T, h ldap.Handler, eh events.Handler, err error) { require.NoError(t, err) rr := ldaptest.NewRecorder() @@ -652,7 +657,7 @@ dn: id=user3,ou=Accounting,dc=example,dc=com foo: bar `)}, }}, - test: func(t *testing.T, h ldap.Handler, err error) { + test: func(t *testing.T, h ldap.Handler, eh events.Handler, err error) { require.NoError(t, err) rr := ldaptest.NewRecorder() @@ -677,10 +682,12 @@ foo: bar var c *directory.Config err := json.Unmarshal([]byte(tc.input), &c) if err != nil { - tc.test(t, nil, err) + tc.test(t, nil, nil, err) } else { err = c.Parse(&dynamic.Config{Data: c, Info: dynamic.ConfigInfo{Url: try.MustUrl("file:/foo.yml")}}, tc.reader) - tc.test(t, directory.NewHandler(c, enginetest.NewEngine(), &eventstest.Handler{}), err) + eh := &eventstest.Handler{} + h := directory.NewHandler(c, enginetest.NewEngine(), eh) + tc.test(t, h, eh, err) } }) } diff --git a/providers/mail/log.go b/providers/mail/log.go index df25b6e2f..334308fff 100644 --- a/providers/mail/log.go +++ b/providers/mail/log.go @@ -45,3 +45,7 @@ func NewLogEvent(msg *smtp.Message, ctx *smtp.ClientContext, eh events.Handler, func (l *Log) Title() string { return fmt.Sprintf("%s", l.Subject) } + +func (l *Log) Metadata() map[string]string { + return nil +} diff --git a/providers/openapi/log.go b/providers/openapi/log.go index febfb5d04..42a57a740 100644 --- a/providers/openapi/log.go +++ b/providers/openapi/log.go @@ -10,6 +10,7 @@ import ( "net" "net/http" "net/textproto" + "strconv" "strings" ) @@ -115,6 +116,15 @@ func (l *HttpLog) Title() string { return fmt.Sprintf("%s %s", l.Request.Method, l.Request.Url) } +func (l *HttpLog) Metadata() map[string]string { + if l != nil && l.Response != nil { + return map[string]string{ + "statusCode": strconv.Itoa(l.Response.StatusCode), + } + } + return nil +} + func (l *HttpRequestLog) setParams(name string, params map[string]RequestParameterValue) { for k, v := range params { value, _ := json.Marshal(v.Value) diff --git a/runtime/events/events.go b/runtime/events/events.go index 60a293067..cd05d2702 100644 --- a/runtime/events/events.go +++ b/runtime/events/events.go @@ -18,6 +18,7 @@ type Handler interface { type EventData interface { Title() string + Metadata() map[string]string } type StoreManager struct { diff --git a/runtime/events/eventstest/event.go b/runtime/events/eventstest/event.go index 7b6563265..3f888d0ed 100644 --- a/runtime/events/eventstest/event.go +++ b/runtime/events/eventstest/event.go @@ -3,14 +3,19 @@ package eventstest import "mokapi/runtime/events" type Event struct { - Name string - Api string `json:"api"` + Name string + Api string `json:"api"` + MetadataField map[string]string `json:"-"` } func (e *Event) Title() string { return e.Name } +func (e *Event) Metadata() map[string]string { + return e.MetadataField +} + type Handler struct { Events []events.Event } @@ -23,7 +28,7 @@ func (h *Handler) Push(data events.EventData, traits events.Traits) error { func (h *Handler) GetEvents(traits events.Traits) []events.Event { var result []events.Event for _, e := range h.Events { - if e.Traits.Match(traits) { + if traits.Match(e.Traits) { result = append(result, e) } } diff --git a/runtime/events/index.go b/runtime/events/index.go index 13de8e724..bad28d0eb 100644 --- a/runtime/events/index.go +++ b/runtime/events/index.go @@ -4,16 +4,19 @@ import ( "fmt" "mokapi/runtime/search" "reflect" + "strings" "time" ) type eventIndex struct { - Type string `json:"type"` - Discriminator string `json:"discriminator"` - Api string `json:"api"` - Title string `json:"_title" index:"false" store:"true"` - Event *Event `json:"event"` - Time string `json:"_time"` + Api string `json:"api"` + Type string `json:"type"` + Discriminator string `json:"discriminator"` + Domain string `json:"domain"` + Title string `json:"_title" index:"false" store:"true"` + Event *Event `json:"event"` + Metadata map[string]string `json:"metadata"` + Time string `json:"_time"` } func (m *StoreManager) addToIndex(event *Event) { @@ -22,14 +25,22 @@ func (m *StoreManager) addToIndex(event *Event) { } data := eventIndex{ + Api: event.Traits.GetName(), Type: "event", Discriminator: fmt.Sprintf("event_%s", event.Traits.String()), - Api: getApiFromEvent(event), + Domain: getDomainFromEvent(event), Event: event, Time: event.Time.Format(time.RFC3339), } if event.Data != nil { data.Title = event.Data.Title() + + for k, v := range event.Data.Metadata() { + if data.Metadata == nil { + data.Metadata = make(map[string]string) + } + data.Metadata[k] = v + } } m.index.Add(event.Id, data) @@ -39,25 +50,41 @@ func GetSearchResult(fields map[string]string, _ []string) (search.ResultItem, e result := search.ResultItem{ Type: "Event", Title: fields["_title"], - Domain: fields["event.data.api"], + Domain: fields["domain"], Time: fields["_time"], } - if fields["event.traits.namespace"] == "kafka" { - result.Domain = fmt.Sprintf("%s - %s", fields["event.data.api"], fields["event.traits.topic"]) - } result.Params = map[string]string{ - "namespace": fields["event.traits.namespace"], - "id": fields["event.id"], + "id": fields["event.id"], + } + for k, v := range fields { + if strings.HasPrefix(k, "event.traits.") { + k = strings.Replace(k, "event.", "", 1) + result.Params[k] = v + } else if strings.HasPrefix(k, "metadata.") { + k = strings.Replace(k, "metadata.", "", 1) + result.Params[k] = v + } } return result, nil } -func getApiFromEvent(event *Event) string { +func getDomainFromEvent(event *Event) string { + if d, ok := event.Data.(DomainData); ok { + return d.Domain() + } + return getDataField(event, "Api") +} + +type DomainData interface { + Domain() string +} + +func getDataField(event *Event, field string) string { if event.Data == nil { return "" } - f := reflect.ValueOf(event.Data).Elem().FieldByName("Api") + f := reflect.ValueOf(event.Data).Elem().FieldByName(field) if f.IsValid() { return f.String() } diff --git a/runtime/events/index_test.go b/runtime/events/index_test.go index df46cc77d..6bb4adc1c 100644 --- a/runtime/events/index_test.go +++ b/runtime/events/index_test.go @@ -45,7 +45,7 @@ func TestIndex_Http(t *testing.T) { require.Equal(t, "My API", r.Results[0].Domain) require.Equal(t, "foo", r.Results[0].Title) require.Equal(t, []string{"foo"}, r.Results[0].Fragments) - require.Equal(t, "test", r.Results[0].Params["namespace"]) + require.Equal(t, "test", r.Results[0].Params["traits.namespace"]) require.NotEmpty(t, r.Results[0].Params["id"]) }, }, @@ -73,7 +73,7 @@ func TestIndex_Http(t *testing.T) { require.Equal(t, "My API", r.Results[0].Domain) require.Equal(t, "foo", r.Results[0].Title) require.Equal(t, []string{"event"}, r.Results[0].Fragments) - require.Equal(t, "test", r.Results[0].Params["namespace"]) + require.Equal(t, "test", r.Results[0].Params["traits.namespace"]) require.NotEmpty(t, r.Results[0].Params["id"]) }, }, @@ -125,7 +125,7 @@ func TestIndex_Http(t *testing.T) { require.Equal(t, "My API", r.Results[0].Domain) require.Equal(t, "bar", r.Results[0].Title) require.Equal(t, []string{"event"}, r.Results[0].Fragments) - require.Equal(t, "test", r.Results[0].Params["namespace"]) + require.Equal(t, "test", r.Results[0].Params["traits.namespace"]) require.NotEmpty(t, r.Results[0].Params["id"]) }, }, diff --git a/runtime/index.go b/runtime/index.go index d7188ed00..8a92bf444 100644 --- a/runtime/index.go +++ b/runtime/index.go @@ -2,6 +2,7 @@ package runtime import ( "context" + "fmt" "mokapi/config/static" "mokapi/runtime/events" "mokapi/runtime/search" @@ -62,6 +63,11 @@ func (s *SearchIndex) start(pool *safe.Pool) { docMapping.AddFieldMappingsAt("_title", disableIndex) docMapping.AddFieldMappingsAt("_time", disableIndex) docMapping.AddFieldMappingsAt("discriminator", disableIndex) + docMapping.AddFieldMappingsAt("statusCode", bleve.NewNumericFieldMapping()) + + metaMapping := bleve.NewDocumentMapping() + metaMapping.AddFieldMappingsAt("*", disableIndex) + docMapping.AddSubDocumentMapping("meta", metaMapping) apiField := bleve.NewTextFieldMapping() apiField.Analyzer = "mokapi_analyzer" @@ -193,10 +199,19 @@ func (s *SearchIndex) Search(r search.Request) (search.Result, error) { clauses = append(clauses, q) } - for k, v := range params { - term := bleve.NewMatchPhraseQuery(v) - term.SetField(k) - clauses = append(clauses, term) + for _, p := range params { + term := bleve.NewMatchPhraseQuery(p.value) + term.SetField(p.key) + bq := bleve.NewBooleanQuery() + switch p.operator { + case "+": + bq.AddMust(term) + case "-": + bq.AddMustNot(term) + default: + bq.AddShould(term) + } + clauses = append(clauses, bq) } qFacetsValues := make([]query.Query, len(clauses)) @@ -284,25 +299,39 @@ func (s *SearchIndex) Search(r search.Request) (search.Result, error) { func getSearchFields(doc index.Document) map[string]string { m := make(map[string]string) doc.VisitFields(func(field index.Field) { - m[field.Name()] = string(field.Value()) + var value string + switch f := field.(type) { + case index.NumericField: + v, _ := f.Number() + value = fmt.Sprintf("%v", v) + default: + value = string(field.Value()) + } + m[field.Name()] = value }) return m } -func parseQuery(query string) (string, map[string]string) { - re := regexp.MustCompile(`([\w.]+):("[^"]+"|\S+)`) +type param struct { + key string + value string + operator string +} + +func parseQuery(query string) (string, []param) { + re := regexp.MustCompile(`([+-]?)([\w.]+):("[^"]+"|\S+)`) - params := make(map[string]string) matches := re.FindAllStringSubmatch(query, -1) + var params []param s := query for _, m := range matches { - key := m[1] + key := m[2] if !slices.Contains(fieldsNotIncludedInAll, key) { continue } - value := strings.Trim(m[2], `"`) - params[key] = value + value := strings.Trim(m[3], `"`) + params = append(params, param{key: key, value: value, operator: m[1]}) s = strings.Replace(s, m[0], "", 1) } diff --git a/runtime/index_test.go b/runtime/index_test.go index eadffe8d2..081fe847d 100644 --- a/runtime/index_test.go +++ b/runtime/index_test.go @@ -26,7 +26,7 @@ func TestIndex(t *testing.T) { app.Start(pool) defer pool.Stop() - trait := events.NewTraits().WithNamespace("test") + trait := events.NewTraits().WithNamespace("test").WithName("Swagger Petstore") app.Events.SetStore(10, trait) err := app.Events.Push(&eventstest.Event{ Name: "foo", @@ -34,7 +34,7 @@ func TestIndex(t *testing.T) { }, trait) require.NoError(t, err) - petstore := openapitest.NewConfig("3.0", openapitest.WithInfo("Swagger Petstore", "1.0", "This is a sample server Petstore server. You can find out more about Swagger at https://swagger.io"), + petStore := openapitest.NewConfig("3.0", openapitest.WithInfo("Swagger Petstore", "1.0", "This is a sample server Petstore server. You can find out more about Swagger at https://swagger.io"), openapitest.WithPath("/pet", openapitest.WithOperation("put", openapitest.WithOperationInfo("Update an existing pet.", "Update an existing pet by Id.", "updatePet", false), @@ -43,7 +43,7 @@ func TestIndex(t *testing.T) { ) app.AddHttp(&dynamic.Config{ Info: dynamic.ConfigInfo{Url: try.MustUrl("petstore.yaml"), Provider: "NPM"}, - Data: petstore, + Data: petStore, }) result, err := app.Search(search.Request{ diff --git a/runtime/runtime_http_search.go b/runtime/runtime_http_search.go index e6a551da1..273fa5792 100644 --- a/runtime/runtime_http_search.go +++ b/runtime/runtime_http_search.go @@ -2,10 +2,13 @@ package runtime import ( "fmt" + "maps" "mokapi/providers/openapi" openApiSchema "mokapi/providers/openapi/schema" "mokapi/runtime/search" "mokapi/schema/json/schema" + "slices" + "strconv" "strings" ) @@ -28,6 +31,7 @@ type httpPathSearchIndexData struct { Summary string `json:"summary"` Description string `json:"description"` Parameters []httpParameterSearchIndexData `json:"parameters"` + Meta map[string]string `json:"meta"` } type httpParameterSearchIndexData struct { @@ -38,22 +42,31 @@ type httpParameterSearchIndexData struct { } type httpOperationSearchIndexData struct { - Type string `json:"type"` - Discriminator string `json:"discriminator"` - Api string `json:"api"` - Path string `json:"path"` - Method string `json:"method"` - Summary string `json:"summary"` - Description string `json:"description"` - OperationId string `json:"operationId"` - Tags []string `json:"tags"` - Parameters []httpParameterSearchIndexData `json:"parameters"` - RequestBody string `json:"request_body"` - Responses []httpResponseSearchIndexData `json:"responses"` + Type string `json:"type"` + Discriminator string `json:"discriminator"` + Api string `json:"api"` + Path string `json:"path"` + Method string `json:"method"` + Summary string `json:"summary"` + Description string `json:"description"` + OperationId string `json:"operationId"` + Tags []string `json:"tags"` + Parameters []httpParameterSearchIndexData `json:"parameters"` + StatusCode int `json:"statusCode"` + StatusCodeText string `json:"statusCodeText"` + RequestBodies []httpRequestBodySearchIndexData `json:"requestBodies"` + Responses []httpResponseSearchIndexData `json:"responses"` +} + +type httpRequestBodySearchIndexData struct { + Description string `json:"description"` + ContentType string `json:"contentType"` + Schema *schema.IndexData `json:"schema"` } type httpResponseSearchIndexData struct { Description string `json:"description"` + ContentType string `json:"contentType"` Schema *schema.IndexData `json:"schema"` } @@ -86,6 +99,7 @@ func (s *HttpStore) addToIndex(cfg *openapi.Config) { Path: path, Summary: p.Summary, Description: p.Description, + Meta: map[string]string{}, } if pathData.Summary == "" { pathData.Summary = p.Value.Summary @@ -103,28 +117,19 @@ func (s *HttpStore) addToIndex(cfg *openapi.Config) { Schema: schema.NewIndexData(ps), }) } + methods := slices.Collect(maps.Keys(p.Value.Operations())) + pathData.Meta["methods"] = strings.Join(methods, ",") s.index.Add(fmt.Sprintf("http_%s_%s", cfg.Info.Name, path), pathData) for method, op := range p.Value.Operations() { id := fmt.Sprintf("http_%s_%s_%s", cfg.Info.Name, path, method) - opData := httpOperationSearchIndexData{ - Type: "http", - Discriminator: "http_operation", - Api: cfg.Info.Name, - Path: path, - Method: method, - Summary: op.Summary, - Description: op.Description, - OperationId: op.OperationId, - Tags: op.Tags, - Parameters: pathData.Parameters, - } + params := pathData.Parameters for _, param := range op.Parameters { ps := openApiSchema.ConvertToJsonSchema(param.Value.Schema) - opData.Parameters = append(opData.Parameters, httpParameterSearchIndexData{ + params = append(params, httpParameterSearchIndexData{ Name: param.Value.Name, Description: param.Value.Description, Location: param.Value.Type.String(), @@ -132,25 +137,75 @@ func (s *HttpStore) addToIndex(cfg *openapi.Config) { }) } - if op.Responses != nil { + var requestBodies []httpRequestBodySearchIndexData + if op.RequestBody != nil && op.RequestBody.Value != nil { + v := op.RequestBody.Value + for ct, mt := range v.Content { + rs := openApiSchema.ConvertToJsonSchema(mt.Schema) + requestBodies = append(requestBodies, httpRequestBodySearchIndexData{ + Description: v.Description, + ContentType: ct, + Schema: schema.NewIndexData(rs), + }) + } + } + + if op.Responses != nil && op.Responses.Len() > 0 { for it := op.Responses.Iter(); it.Next(); { v := it.Value().Value if v == nil { continue } - for _, mt := range v.Content { - rs := openApiSchema.ConvertToJsonSchema(mt.Schema) + statusCode := 0 + if i, err := strconv.Atoi(it.Key()); err == nil { + statusCode = i + } - opData.Responses = append(opData.Responses, httpResponseSearchIndexData{ + var responses []httpResponseSearchIndexData + for ct, mt := range v.Content { + rs := openApiSchema.ConvertToJsonSchema(mt.Schema) + responses = append(responses, httpResponseSearchIndexData{ Description: v.Description, + ContentType: ct, Schema: schema.NewIndexData(rs), }) } + opData := httpOperationSearchIndexData{ + Type: "http", + Discriminator: "http_operation", + Api: cfg.Info.Name, + Path: path, + Method: method, + Summary: op.Summary, + Description: op.Description, + OperationId: op.OperationId, + Tags: op.Tags, + Parameters: params, + StatusCode: statusCode, + StatusCodeText: it.Key(), + RequestBodies: requestBodies, + Responses: responses, + } + + s.index.Add(id, opData) + } + } else { + opData := httpOperationSearchIndexData{ + Type: "http", + Discriminator: "http_operation", + Api: cfg.Info.Name, + Path: path, + Method: method, + Summary: op.Summary, + Description: op.Description, + OperationId: op.OperationId, + Tags: op.Tags, + Parameters: params, + RequestBodies: requestBodies, } + s.index.Add(id, opData) } - - s.index.Add(id, opData) } } } @@ -180,12 +235,15 @@ func getHttpSearchResult(fields map[string]string, discriminator []string) (sear } case "operation": result.Domain = fields["api"] - result.Title = fmt.Sprintf("%s %s", fields["method"], fields["path"]) + result.Title = fields["path"] result.Params = map[string]string{ "type": strings.ToLower(result.Type), "service": result.Domain, "path": fields["path"], - "method": strings.ToLower(fields["method"]), + "method": strings.ToUpper(fields["method"]), + } + if s, ok := fields["statusCode"]; ok && s != "0" { + result.Params["statusCode"] = s } default: return result, fmt.Errorf("unsupported search result: %s", strings.Join(discriminator, "_")) diff --git a/runtime/runtime_http_search_test.go b/runtime/runtime_http_search_test.go index 71cfc150b..8c86fec1b 100644 --- a/runtime/runtime_http_search_test.go +++ b/runtime/runtime_http_search_test.go @@ -10,6 +10,7 @@ import ( "mokapi/runtime" "mokapi/runtime/search" "mokapi/safe" + "net/http" "testing" "time" @@ -224,7 +225,7 @@ func TestIndex_Http(t *testing.T) { openapitest.WithInfo("foo", "1.0", "a description"), openapitest.WithPath("/pets", openapitest.WithPathInfo("", "a description"), - openapitest.WithOperation("get", + openapitest.WithOperation(http.MethodGet, openapitest.WithHeaderParam("foo", true, openapitest.WithParamInfo("parameter description")), ), ), @@ -243,13 +244,13 @@ func TestIndex_Http(t *testing.T) { search.ResultItem{ Type: "HTTP", Domain: "foo", - Title: "GET /pets", + Title: "/pets", Fragments: []string{"parameter description"}, Params: map[string]string{ "type": "http", "service": "foo", "path": "/pets", - "method": "get", + "method": "GET", }, }, r.Results[0]) diff --git a/runtime/runtime_kafka_search.go b/runtime/runtime_kafka_search.go index 03a960b64..543779aaa 100644 --- a/runtime/runtime_kafka_search.go +++ b/runtime/runtime_kafka_search.go @@ -19,6 +19,7 @@ type kafkaSearchIndexData struct { Description string `json:"description"` Contact *asyncapi3.Contact `json:"contact"` Servers []kafkaServerSearchData `json:"servers"` + Meta map[string]string `json:"meta"` } type kafkaServerSearchData struct { @@ -65,6 +66,9 @@ func (s *KafkaStore) addToIndex(cfg *asyncapi3.Config) { Version: cfg.Info.Version, Description: cfg.Info.Description, Contact: cfg.Info.Contact, + Meta: map[string]string{ + "topics": fmt.Sprintf("%d", len(cfg.Channels)), + }, } for it := cfg.Servers.Iter(); it.Next(); { name := it.Key() @@ -87,13 +91,20 @@ func (s *KafkaStore) addToIndex(cfg *asyncapi3.Config) { if topic == nil || topic.Value == nil { continue } + topicName := name + if topic.Value.Name != "" { + topicName = topic.Value.Name + } + if topic.Value.Address != "" { + topicName = topic.Value.Address + } t := kafkaTopicSearchIndexData{ Type: "kafka", Discriminator: "kafka_topic", Api: cfg.Info.Name, ChannelId: name, - Name: topic.Value.Name, + Name: topicName, Title: topic.Value.Title, Address: topic.Value.Address, Summary: topic.Value.Summary, @@ -139,6 +150,12 @@ func getKafkaSearchResult(fields map[string]string, discriminator []string) (sea "type": strings.ToLower(result.Type), "service": result.Title, } + for k, v := range fields { + if strings.HasPrefix(k, "meta.") { + k = strings.Replace(k, "meta.", "", 1) + result.Params[k] = v + } + } return result, nil } diff --git a/runtime/runtime_kafka_search_test.go b/runtime/runtime_kafka_search_test.go index 4b24bd866..28957d0e3 100644 --- a/runtime/runtime_kafka_search_test.go +++ b/runtime/runtime_kafka_search_test.go @@ -51,6 +51,7 @@ func TestIndex_Kafka(t *testing.T) { Params: map[string]string{ "type": "kafka", "service": "Kafka Test server", + "topics": "0", }, }, r.Results[0]) @@ -86,15 +87,27 @@ func TestIndex_Kafka(t *testing.T) { cfg := asyncapi3test.NewConfig( asyncapi3test.WithInfo("Kafka Test server", "", ""), asyncapi3test.WithChannel("foo", - asyncapi3test.WithChannelDescription("description"), + asyncapi3test.WithChannelDescription("first"), ), ) + + second := asyncapi3test.NewChannel( + asyncapi3test.WithChannelDescription("second"), + asyncapi3test.WithChannelAddress("address-name"), + ) + cfg.Channels["bar"] = &asyncapi3.ChannelRef{Value: second} + + third := asyncapi3test.NewChannel( + asyncapi3test.WithChannelDescription("third"), + ) + cfg.Channels["yuh"] = &asyncapi3.ChannelRef{Value: third} + _, err := app.Kafka.Add(toConfig(cfg), enginetest.NewEngine()) require.NoError(t, err) var r search.Result waitSearchIndex(t, func() bool { - r, err = app.Search(search.Request{QueryText: "description", Limit: 10}) + r, err = app.Search(search.Request{QueryText: "first", Limit: 10}) require.NoError(t, err) return len(r.Results) == 1 }) @@ -104,7 +117,7 @@ func TestIndex_Kafka(t *testing.T) { Type: "Kafka", Domain: "Kafka Test server", Title: "Topic foo", - Fragments: []string{"description"}, + Fragments: []string{"first"}, Params: map[string]string{ "type": "kafka", "service": "Kafka Test server", @@ -112,6 +125,40 @@ func TestIndex_Kafka(t *testing.T) { }, }, r.Results[0]) + + r, err = app.Search(search.Request{QueryText: "second", Limit: 10}) + require.NoError(t, err) + require.Len(t, r.Results, 1) + require.Equal(t, + search.ResultItem{ + Type: "Kafka", + Domain: "Kafka Test server", + Title: "Topic address-name", + Fragments: []string{"second"}, + Params: map[string]string{ + "type": "kafka", + "service": "Kafka Test server", + "topic": "address-name", + }, + }, + r.Results[0]) + + r, err = app.Search(search.Request{QueryText: "third", Limit: 10}) + require.NoError(t, err) + require.Len(t, r.Results, 1) + require.Equal(t, + search.ResultItem{ + Type: "Kafka", + Domain: "Kafka Test server", + Title: "Topic yuh", + Fragments: []string{"third"}, + Params: map[string]string{ + "type": "kafka", + "service": "Kafka Test server", + "topic": "yuh", + }, + }, + r.Results[0]) }, }, } diff --git a/runtime/runtime_ldap_search.go b/runtime/runtime_ldap_search.go index af43a7496..510d5ef94 100644 --- a/runtime/runtime_ldap_search.go +++ b/runtime/runtime_ldap_search.go @@ -8,13 +8,14 @@ import ( ) type ldapSearchIndexData struct { - Type string `json:"type"` - Discriminator string `json:"discriminator"` - Api string `json:"api"` - Name string `json:"name"` - Version string `json:"version"` - Server string `json:"server"` - Description string `json:"description"` + Type string `json:"type"` + Discriminator string `json:"discriminator"` + Api string `json:"api"` + Name string `json:"name"` + Version string `json:"version"` + Server string `json:"server"` + Description string `json:"description"` + Meta map[string]string `json:"meta"` } type ldapSearchIndexEntry struct { @@ -44,6 +45,9 @@ func (s *LdapStore) addToIndex(cfg *directory.Config) { Version: cfg.Info.Version, Description: cfg.Info.Description, Server: cfg.Address, + Meta: map[string]string{ + "entries": fmt.Sprintf("%d", cfg.Entries.Len()), + }, } s.index.Add(fmt.Sprintf("ldap_%s", cfg.Info.Name), c) @@ -63,7 +67,7 @@ func (s *LdapStore) addToIndex(cfg *directory.Config) { Values: values, }) } - s.index.Add(fmt.Sprintf("mail_%s_%s", cfg.Info.Name, e.Dn), se) + s.index.Add(fmt.Sprintf("ldap_%s_%s", cfg.Info.Name, e.Dn), se) } } } @@ -79,6 +83,12 @@ func getLdapSearchResult(fields map[string]string, discriminator []string) (sear "type": strings.ToLower(result.Type), "service": result.Title, } + for k, v := range fields { + if strings.HasPrefix(k, "meta.") { + k = strings.Replace(k, "meta.", "", 1) + result.Params[k] = v + } + } return result, nil } @@ -89,6 +99,7 @@ func getLdapSearchResult(fields map[string]string, discriminator []string) (sear result.Params = map[string]string{ "type": strings.ToLower(result.Type), "service": result.Domain, + "entry": fields["dn"], } default: return result, fmt.Errorf("unsupported search result: %s", strings.Join(discriminator, "_")) diff --git a/runtime/runtime_ldap_search_test.go b/runtime/runtime_ldap_search_test.go index b42d6265c..10db656a5 100644 --- a/runtime/runtime_ldap_search_test.go +++ b/runtime/runtime_ldap_search_test.go @@ -52,6 +52,7 @@ func TestIndex_Ldap(t *testing.T) { Params: map[string]string{ "type": "ldap", "service": "foo", + "entries": "0", }, }, r.Results[0]) @@ -113,6 +114,7 @@ func TestIndex_Ldap(t *testing.T) { Params: map[string]string{ "type": "ldap", "service": "foo", + "entry": "cn=alice,dc=foo,dc=com", }, }, r.Results[0]) diff --git a/runtime/runtime_search_test.go b/runtime/runtime_search_test.go index fbe7608b2..b55dda4cf 100644 --- a/runtime/runtime_search_test.go +++ b/runtime/runtime_search_test.go @@ -85,6 +85,33 @@ func TestIndex_Config(t *testing.T) { require.Len(t, r.Results, 2) }, }, + { + name: "api:foo with operator", + test: func(t *testing.T, app *runtime.App) { + h := openapitest.NewConfig("3.0", openapitest.WithInfo("foo", "", "")) + app.AddHttp(toConfig(h)) + h = openapitest.NewConfig("3.0", openapitest.WithInfo("bar", "", "")) + app.AddHttp(toConfig(h)) + k := asyncapi3test.NewConfig(asyncapi3test.WithInfo("foo", "", "")) + _, err := app.Kafka.Add(toConfig(k), enginetest.NewEngine()) + require.NoError(t, err) + + var r search.Result + waitSearchIndex(t, func() bool { + r, err = app.Search(search.Request{QueryText: "+api:foo", Limit: 10}) + require.NoError(t, err) + return len(r.Results) == 2 + }) + require.Len(t, r.Results, 2) + require.Equal(t, "foo", r.Results[0].Title) + require.Equal(t, "foo", r.Results[1].Title) + + r, err = app.Search(search.Request{QueryText: "-api:foo", Limit: 10}) + require.NoError(t, err) + require.Len(t, r.Results, 1) + require.Equal(t, "bar", r.Results[0].Title) + }, + }, } t.Parallel() diff --git a/webui/e2e/mocks/http_handler.js b/webui/e2e/mocks/http_handler.js index 8ba8008f9..2799824dd 100644 --- a/webui/e2e/mocks/http_handler.js +++ b/webui/e2e/mocks/http_handler.js @@ -548,28 +548,59 @@ function getSearchResults() { type: 'http', service: 'Swagger Petstore', path: '/pet', + methods: 'get,post' } }, { type: 'HTTP', domain: 'Swagger Petstore', - title: "POST /pet", + title: "/pet", fragments: ['Everything', 'store'], params: { type: 'http', service: 'Swagger Petstore', path: '/pet', - method: 'post' + method: 'post', + statusCode: '200' + } + }, + { + type: 'HTTP', + domain: 'Swagger Petstore', + title: "/foo/longTextPathEndpoint/bar/pets", + fragments: ['Everything', 'store'], + params: { + type: 'http', + service: 'Swagger Petstore', + path: '/foo/bar/pets', + method: 'put', + statusCode: '200' + } + }, + { + type: 'HTTP', + domain: 'Swagger Petstore', + title: "/customer/foo/bar/test/correspondenceAddress", + fragments: ['Everything', 'store'], + params: { + type: 'http', + service: 'Swagger Petstore', + path: '/customer/foo/bar/test/correspondenceAddress', + method: 'post', + statusCode: '200' } }, { type: 'Event', domain: 'Swagger Petstore', - title: "POST http://127.0.0.1:18080/pet", + title: "http://127.0.0.1:18080/pet", fragments: [], + time: '2025-05-23T08:49:25.482366+01:00', params: { type: 'event', - namespace: 'http', + 'traits.namespace': 'http', + 'traits.name': 'Swagger Petstore', + 'traits.method': 'get', id: '4242' } }, @@ -589,7 +620,8 @@ function getSearchResults() { fragments: ['To ours significant why upon tomorrow'], params: { type: 'kafka', - service: 'Kafka World' + service: 'Kafka World', + topics: '3' } }, { @@ -605,12 +637,16 @@ function getSearchResults() { }, { type: 'Event', - domain: 'Kafka World - mokapi.shop.products', + domain: 'Kafka World', title: "GGOEWXXX0827", fragments: null, + time: '2025-05-01T08:49:25.482366+01:00', params: { type: 'event', - namespace: 'kafka', + 'traits.namespace': 'kafka', + 'traits.name': 'Kafka World', + 'traits.topic': 'mokapi.shop.products', + 'traits.partition': '0', id: '123456' } }, @@ -631,35 +667,39 @@ function getSearchResults() { fragments: ['message from Alice'], params: { type: 'event', - namespace: 'mail', + 'traits.namespace': 'mail', + 'traits.name': 'Mail Testserver', id: '8832' } }, { type: 'LDAP', - domain: 'LDAP Testserver', title: "LDAP Testserver", fragments: ['This is a sample LDAP server'], params: { type: 'ldap', service: 'LDAP Testserver', + entries: '12' } }, { type: 'Event', domain: 'LDAP Testserver', - title: "Search (objectClass=user)", + title: "(objectClass=user)", fragments: ['(objectClass=user)'], params: { type: 'event', - namespace: 'ldap', - id: 'dkads-23124' + 'traits.namespace': 'ldap', + 'traits.name': 'LDAP Testserver', + 'traits.operation': 'search', + id: 'dkads-23124', + baseDn: 'dc=example,dc=org', } } ], facets: { type: [{value: 'HTTP', count: 3}, {value: 'Kafka', count: 2}, {value: 'Mail', count: 1}, {value: 'Event', count: 2}, {value: 'Config', count: 1}] }, - total: 8 + total: 15 } } \ No newline at end of file diff --git a/webui/src/components/dashboard/Search.vue b/webui/src/components/dashboard/Search.vue index a9d5496de..f487434ff 100644 --- a/webui/src/components/dashboard/Search.vue +++ b/webui/src/components/dashboard/Search.vue @@ -2,8 +2,14 @@ import { usePrettyDates } from '@/composables/usePrettyDate'; import router from '@/router'; import { computed, onMounted, ref, watch } from 'vue'; -import { useRoute, type RouteLocationRaw } from 'vue-router'; +import { useRoute } from 'vue-router'; import { transformPath } from '@/composables/fetch'; +import { useProgressiveLoading } from '@/composables/useProgressiveLoading'; +import Http from './search/Http.vue'; +import Kafka from './search/Kafka.vue'; +import Event from './search/Event.vue'; +import Ldap from './search/Ldap.vue'; +import Mail from './search/Mail.vue'; const route = useRoute() const { format } = usePrettyDates() @@ -14,6 +20,7 @@ const searchResult = ref(); const maxVisiblePages = 10 // max pages in pagination const showTips = ref(false) const facets = ref<{ [name: string]: string | undefined}>({}) +const loading = useProgressiveLoading() const pageNumber = computed(() => { if (!searchResult.value) { @@ -46,7 +53,7 @@ watch(queryText, async () => { } // debounced clearTimeout(timeout) - timeout = setTimeout(async () => { await search() }, 500) + timeout = setTimeout(async () => { await search() }, 1000) }) async function navigateToSearchResult(result: any) { @@ -113,7 +120,7 @@ function title(result: SearchItem) { onMounted(async () => { for (const param in route.query) { - if (param === 'q') { + if (param === 'q' || param === 'index') { continue } if (route.query[param]) { @@ -145,34 +152,34 @@ function getIndex(): number { return Number.isNaN(parsed) ? 0 : parsed } -function search_clicked() { - let q: string | undefined = queryText.value - if (q === '') { - q = undefined // remove parameter - } - let index: number | undefined = pageIndex.value - if (index === 0) { - index = undefined - } +async function search_clicked() { + const newQuery = { ...route.query } - const to: RouteLocationRaw = { - query: { - ...route.query, - q: q, - index: index - } + if (queryText.value) { + newQuery.q = queryText.value + } else { + delete newQuery.q + } + + if (pageIndex.value) { + newQuery.index = pageIndex.value.toString() + } else { + delete newQuery.index } for (const name in facets.value) { - if (facets.value[name] === '') { - to.query![name] = undefined + if (!facets.value[name]) { + delete newQuery[name] } else { - to.query![name] = facets.value[name] + newQuery[name] = facets.value[name] } } - - router.replace(to) + const r = await router.replace({ query: newQuery }) + if (r) { + // navigation was redundant, so search manually + search() + } } function search_keypressed(event: KeyboardEvent) { @@ -187,6 +194,8 @@ function pageIndex_click(index: number) { } async function search() { + loading.start() + let path = `/api/search/query?q=${queryText.value}` if (pageIndex.value !== 0) { path += `&index=${pageIndex.value}` @@ -209,6 +218,7 @@ async function search() { return res.json() }) .then(res => { + loading.stop() return res }) .catch((s) => { @@ -255,24 +265,31 @@ function facetTitle(s: string) { {{ showTips ? 'Search Tips ▲' : 'Search Tips ▼' }} -
-
    -
  • name:petstore – Find "petstore" in the name field
  • -
  • type:event – Find events like HTTP requests, Kafka messages, mails, etc
  • -
  • +petstore -kafka – Must include "petstore", exclude "kafka"
  • -
  • "Swagger Petstore" – Match exact phrase
  • -
  • pet* – Wildcard (matches "pet", "pets", "petstore")
  • -
  • pet~ – Fuzzy match (e.g., "pets", "pest")
  • -
  • path:/pets^2 description:dog – Boost matches in path field
  • -
  • (get OR post) AND pets – Combine multiple terms logically
  • +
    + By default, multiple terms are combined with OR (results contain at least one term). Use prefixes to enforce stricter matches. +
    Refine Your Results
    +
      +
    • +petstore -kafka - Must include "petstore", Must Not include "kafka".
    • +
    • petstore kafka - Returns results containing "petstore" OR "kafka" (default).
    • +
    • "Swagger Petstore" - Matches the exact phrase.
    • +
    +
    Fields & Logic
    +
      +
    • name:petstore - Search for "petstore" specifically in the name field.
    • +
    • +method:GET 404 500 - Must be GET and must contain either 404 or 500.
    • +
    • +statusCode:>=300 - Must be response with status code greater than or equal to 300.
    • +
    • path:/pets^2 - Boost matches in the path field (scores them higher).
    • +
    +
    Wildcards & Fuzzy
    +
      +
    • pet* - Wildcard (matches "pet", "pets", "petstore").
    • +
    • pet~ - Fuzzy match (matches "pets", "pest" or slight typos).
    -
    - Learn more about Mokapi's search here -
+
{{ loading.statusText }}

Showing {{ searchResult.total }} {{ searchResult.total === 1 ? "result" : "results" }}

@@ -281,7 +298,7 @@ function facetTitle(s: string) {
-
+