Compare commits
67 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
d65c18bd38 | ||
![]() |
a5b0acda06 | ||
![]() |
e251626374 | ||
![]() |
ed0ec0ac1f | ||
![]() |
1945f23419 | ||
![]() |
d10f4ca0cc | ||
![]() |
a5073dd3d4 | ||
![]() |
ddcc49cb42 | ||
![]() |
ae63538baf | ||
![]() |
d9f819d143 | ||
![]() |
3c8b316b76 | ||
![]() |
6b2b6a5dd2 | ||
![]() |
4e00073ec2 | ||
![]() |
8f179f00a2 | ||
![]() |
fe6e853c57 | ||
![]() |
f664e786ac | ||
![]() |
b6f57aa54e | ||
![]() |
afb70a371b | ||
![]() |
c35bdce399 | ||
![]() |
5419a69700 | ||
![]() |
065337c344 | ||
![]() |
21fe455fd6 | ||
![]() |
88dbee311c | ||
![]() |
9001a96128 | ||
![]() |
e4b2203cf6 | ||
![]() |
54c236bacf | ||
![]() |
f001290658 | ||
![]() |
13b2693f29 | ||
![]() |
731d652a7d | ||
![]() |
7f6e4d09c0 | ||
![]() |
12cd279c90 | ||
![]() |
62eb054ff5 | ||
![]() |
e0bbe99b6c | ||
![]() |
03f321b62a | ||
![]() |
460b24f42c | ||
![]() |
fd2c7ca716 | ||
![]() |
8bc6761468 | ||
![]() |
8746d3c985 | ||
![]() |
c18058765a | ||
![]() |
b9e0eadecb | ||
![]() |
680f1263a5 | ||
![]() |
0e0b4e1ff1 | ||
![]() |
2faeecebcc | ||
![]() |
e25bf9ee8b | ||
![]() |
d0ebdefcee | ||
![]() |
7342036646 | ||
![]() |
8e58f000a0 | ||
![]() |
931cea4c4c | ||
![]() |
ccb4d78f6b | ||
![]() |
860af150f7 | ||
![]() |
7d24e065e9 | ||
![]() |
7aef327d2e | ||
![]() |
f76500bb6e | ||
![]() |
63e01540dc | ||
![]() |
a46b91d1cf | ||
![]() |
5061b19cf7 | ||
![]() |
f809123b4f | ||
![]() |
306508856b | ||
![]() |
867af6924d | ||
![]() |
4ec99fc868 | ||
![]() |
b5c135b811 | ||
![]() |
300ec27ec4 | ||
![]() |
c5d80d96fb | ||
![]() |
001fa25a3b | ||
![]() |
0d82507a87 | ||
![]() |
591484b11c | ||
![]() |
b2ab93926d |
13
README.md
@@ -34,14 +34,15 @@ npm install
|
|||||||
npm run dev
|
npm run dev
|
||||||
```
|
```
|
||||||
|
|
||||||
The default UI address is `http://localhost:8080`.
|
The default UI address is `http://localhost:3000`.
|
||||||
|
|
||||||
# Contact Us
|
# Contact Us
|
||||||
* Mail list: **dev@skywalking.apache.org**. Mail to `dev-subscribe@skywalking.apache.org`, follow the reply to subscribe to the mail list.
|
|
||||||
* Send `Request to join SkyWalking slack` mail to the mail list(`dev@skywalking.apache.org`), we will invite you in.
|
- Mail list: **dev@skywalking.apache.org**. Mail to `dev-subscribe@skywalking.apache.org`, follow the reply to subscribe to the mail list.
|
||||||
* For Chinese speaker, send `[CN] Request to join SkyWalking slack` mail to the mail list(`dev@skywalking.apache.org`), we will invite you in.
|
- Send `Request to join SkyWalking slack` mail to the mail list(`dev@skywalking.apache.org`), we will invite you in.
|
||||||
* Twitter, [ASFSkyWalking](https://twitter.com/AsfSkyWalking)
|
- For Chinese speaker, send `[CN] Request to join SkyWalking slack` mail to the mail list(`dev@skywalking.apache.org`), we will invite you in.
|
||||||
* [bilibili B站 视频](https://space.bilibili.com/390683219)
|
- Twitter, [ASFSkyWalking](https://twitter.com/AsfSkyWalking)
|
||||||
|
- [bilibili B 站 视频](https://space.bilibili.com/390683219)
|
||||||
|
|
||||||
# License
|
# License
|
||||||
|
|
||||||
|
@@ -17,35 +17,10 @@
|
|||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
ignores: [(commit) => commit.includes("init")],
|
ignores: [(commit) => commit.includes("init")],
|
||||||
extends: ["@commitlint/config-conventional"],
|
|
||||||
rules: {
|
rules: {
|
||||||
"body-leading-blank": [2, "always"],
|
"body-leading-blank": [2, "always"],
|
||||||
"footer-leading-blank": [1, "always"],
|
"footer-leading-blank": [1, "always"],
|
||||||
"header-max-length": [2, "always", 108],
|
"header-max-length": [2, "always", 108],
|
||||||
"subject-empty": [2, "never"],
|
|
||||||
"type-empty": [2, "never"],
|
|
||||||
"subject-case": [0],
|
"subject-case": [0],
|
||||||
"type-enum": [
|
|
||||||
2,
|
|
||||||
"always",
|
|
||||||
[
|
|
||||||
"feat",
|
|
||||||
"fix",
|
|
||||||
"perf",
|
|
||||||
"style",
|
|
||||||
"docs",
|
|
||||||
"test",
|
|
||||||
"refactor",
|
|
||||||
"build",
|
|
||||||
"ci",
|
|
||||||
"chore",
|
|
||||||
"revert",
|
|
||||||
"wip",
|
|
||||||
"workflow",
|
|
||||||
"types",
|
|
||||||
"release",
|
|
||||||
"merge",
|
|
||||||
],
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
3864
package-lock.json
generated
17
package.json
@@ -18,7 +18,7 @@
|
|||||||
"check-components-types": "if (! git diff --quiet -U0 ./src/types); then echo 'type files are not updated correctly'; git diff -U0 ./src/types; exit 1; fi"
|
"check-components-types": "if (! git diff --quiet -U0 ./src/types); then echo 'type files are not updated correctly'; git diff -U0 ./src/types; exit 1; fi"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"axios": "^1.6.0",
|
"axios": "^1.7.5",
|
||||||
"d3": "^7.3.0",
|
"d3": "^7.3.0",
|
||||||
"d3-flame-graph": "^4.1.3",
|
"d3-flame-graph": "^4.1.3",
|
||||||
"d3-tip": "^0.9.1",
|
"d3-tip": "^0.9.1",
|
||||||
@@ -65,20 +65,20 @@
|
|||||||
"postcss-scss": "^4.0.2",
|
"postcss-scss": "^4.0.2",
|
||||||
"prettier": "^2.7.1",
|
"prettier": "^2.7.1",
|
||||||
"sass": "^1.56.1",
|
"sass": "^1.56.1",
|
||||||
"start-server-and-test": "^1.15.2",
|
"start-server-and-test": "^2.0.5",
|
||||||
"stylelint": "15.9.0",
|
"stylelint": "15.9.0",
|
||||||
"stylelint-config-html": "^1.0.0",
|
"stylelint-config-html": "^1.0.0",
|
||||||
"stylelint-config-prettier": "9.0.4",
|
"stylelint-config-prettier": "9.0.4",
|
||||||
"stylelint-config-standard": "^33.0.0",
|
"stylelint-config-standard": "^33.0.0",
|
||||||
"stylelint-order": "^6.0.3",
|
"stylelint-order": "^6.0.3",
|
||||||
"typescript": "~4.7.4",
|
"typescript": "~4.7.4",
|
||||||
"unplugin-auto-import": "^0.7.0",
|
"unplugin-auto-import": "^0.18.2",
|
||||||
"unplugin-vue-components": "^0.19.2",
|
"unplugin-vue-components": "^0.27.3",
|
||||||
"vite": "^4.0.5",
|
"vite": "^4.5.3",
|
||||||
"vite-plugin-monaco-editor": "^1.1.0",
|
"vite-plugin-monaco-editor": "^1.1.0",
|
||||||
"vite-plugin-svg-icons": "^2.0.1",
|
"vite-plugin-svg-icons": "^2.0.1",
|
||||||
"vitest": "^0.25.6",
|
"vitest": "^0.25.6",
|
||||||
"vue-tsc": "^1.0.12"
|
"vue-tsc": "^1.8.27"
|
||||||
},
|
},
|
||||||
"browserslist": [
|
"browserslist": [
|
||||||
"> 1%",
|
"> 1%",
|
||||||
@@ -98,10 +98,7 @@
|
|||||||
"{!(package)*.json,*.code-snippets,.!(browserslist)*rc}": [
|
"{!(package)*.json,*.code-snippets,.!(browserslist)*rc}": [
|
||||||
"prettier --write"
|
"prettier --write"
|
||||||
],
|
],
|
||||||
"package.json": [
|
"package.json, *.md": [
|
||||||
"prettier --write"
|
|
||||||
],
|
|
||||||
"*.md": [
|
|
||||||
"prettier --write"
|
"prettier --write"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@@ -12,4 +12,4 @@ distributed under the License is distributed on an "AS IS" BASIS,
|
|||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
See the License for the specific language governing permissions and
|
See the License for the specific language governing permissions and
|
||||||
limitations under the License. -->
|
limitations under the License. -->
|
||||||
<svg class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" width="32" height="32"><path d="M856.32 428.064a32 32 0 0 0-32 32v163.328H372.48c-0.896 0-1.664 0.448-2.56 0.512v-177.696h244.48a32 32 0 1 0 0-64H130.56c-0.896 0-1.664 0.448-2.56 0.512V231.68h488.16a32 32 0 1 0 0-64H96a32 32 0 0 0-32 32v701.824a32 32 0 0 0 32 32h760.32a32 32 0 0 0 32-32V460.064a32 32 0 0 0-32-32zM128 445.728c0.896 0.064 1.664 0.512 2.56 0.512h175.36v423.264H128V445.728z m241.92 423.776v-182.624c0.896 0.064 1.664 0.512 2.56 0.512h451.84v182.08h-454.4zM960 174.656h-61.376V113.28a32 32 0 1 0-64 0v61.344H752.64a32 32 0 1 0 0 64h81.984v81.984a32 32 0 1 0 64 0V238.656H960a32 32 0 1 0 0-64z" fill="#2c2c2c"></path></svg>
|
<svg class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" width="32" height="32"><path d="M856.32 428.064a32 32 0 0 0-32 32v163.328H372.48c-0.896 0-1.664 0.448-2.56 0.512v-177.696h244.48a32 32 0 1 0 0-64H130.56c-0.896 0-1.664 0.448-2.56 0.512V231.68h488.16a32 32 0 1 0 0-64H96a32 32 0 0 0-32 32v701.824a32 32 0 0 0 32 32h760.32a32 32 0 0 0 32-32V460.064a32 32 0 0 0-32-32zM128 445.728c0.896 0.064 1.664 0.512 2.56 0.512h175.36v423.264H128V445.728z m241.92 423.776v-182.624c0.896 0.064 1.664 0.512 2.56 0.512h451.84v182.08h-454.4zM960 174.656h-61.376V113.28a32 32 0 1 0-64 0v61.344H752.64a32 32 0 1 0 0 64h81.984v81.984a32 32 0 1 0 64 0V238.656H960a32 32 0 1 0 0-64z"></path></svg>
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.4 KiB |
16
src/assets/icons/cilium.svg
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
<!-- Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
contributor license agreements. See the NOTICE file distributed with
|
||||||
|
this work for additional information regarding copyright ownership.
|
||||||
|
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
(the "License"); you may not use this file except in compliance with
|
||||||
|
the License. You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License. -->
|
||||||
|
|
||||||
|
<svg width="16" height="16" viewBox="20 0 70 72" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="m49.72 45.923-5.505-9.69 5.505-9.69h10.974l5.506 9.69-5.506 9.69H49.72ZM49.72 69.367l-5.505-9.69 5.505-9.689h10.974l5.506 9.69-5.506 9.69H49.72ZM49.72 22.477l-5.505-9.689 5.505-9.69h10.974l5.506 9.69-5.506 9.69H49.72ZM70.06 57.644l-5.506-9.69 5.506-9.69h10.974l5.506 9.69-5.506 9.69H70.06ZM70.06 34.2l-5.506-9.69 5.506-9.69h10.974l5.506 9.69-5.506 9.69H70.06ZM29.357 57.644l-5.506-9.69 5.506-9.69h10.974l5.506 9.69-5.506 9.69H29.357ZM29.357 34.2l-5.506-9.69 5.506-9.69h10.974l5.506 9.69-5.506 9.69H29.357Z" stroke="#141A1F" stroke-width="2.771"/><path d="M10.784 95.947c1.026.007 " fill="#141A1F"/></svg>
|
After Width: | Height: | Size: 1.4 KiB |
@@ -13,4 +13,4 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|||||||
See the License for the specific language governing permissions and
|
See the License for the specific language governing permissions and
|
||||||
limitations under the License. -->
|
limitations under the License. -->
|
||||||
|
|
||||||
<svg t="1654161407133" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1721" width="16" height="16"><path d="M804.224 86.144c0-19.264-15.616-34.944-34.944-34.944l-734.336 0c-19.264 0-34.944 15.68-34.944 34.944l0 82.048 804.224 0 0-82.048zM738.88 602.432c0 47.072-38.176 85.248-85.248 85.248s-85.248-38.176-85.248-85.248c0-47.072 38.176-85.248 85.248-85.248s85.248 38.176 85.248 85.248zM804.992 264.64l0-62.976-804.224 0 0 665.408c0 18.56 14.656 33.472 32.96 34.56l402.24 0c61.12 44.544 136.192 71.168 217.664 71.168 204.544 0 370.368-165.824 370.368-370.368 0-150.592-89.984-279.936-219.008-337.792zM412.096 298.24l30.528 0c-10.624 7.36-20.8 15.36-30.528 23.744l0-23.744zM63.04 298.24l153.024 0 0 153.024-153.024 0 0-153.024zM216.064 805.056l-153.024 0 0-153.024 153.024 0 0 153.024zM219.136 631.232l-153.024 0 0-153.024 153.024 0 0 153.024zM237.568 805.056l0-153.024 49.408 0c7.488 55.936 27.264 107.904 56.832 153.024l-106.24 0zM284.672 631.232l-44.032 0 0-153.024 64.384 0c-13.824 38.848-21.824 80.576-21.824 124.224 0 9.728 0.768 19.264 1.472 28.8zM390.592 341.76c-31.168 31.424-56.512 68.544-74.88 109.44l-78.144 0 0-152.96 153.024 0 0 43.52zM899.136 638.4l-63.36 12.864c-4.288 16.064-10.688 31.296-18.816 45.376l35.712 53.888-50.944 50.944-53.888-35.712c-14.08 8.128-29.312 14.528-45.376 18.816l-12.864 63.36-72 0-12.864-63.36c-16.064-4.288-31.296-10.688-45.376-18.816l-53.888 35.712-50.944-50.944 35.712-53.888c-8.128-14.08-14.528-29.312-18.816-45.376l-63.36-12.864 0-72 63.36-12.864c4.352-16.064 10.688-31.296 18.816-45.312l-35.712-53.952 50.944-50.944 53.888 35.776c14.08-8.128 29.312-14.464 45.376-18.816l12.864-63.36 72 0 12.864 63.36c16.064 4.288 31.296 10.688 45.376 18.816l53.888-35.712 50.944 50.944-35.712 53.824c8.128 14.08 14.528 29.312 18.816 45.376l63.36 12.864 0 72z" p-id="1722" fill="#707070"></path></svg>
|
<svg t="1654161407133" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1721" width="16" height="16"><path d="M804.224 86.144c0-19.264-15.616-34.944-34.944-34.944l-734.336 0c-19.264 0-34.944 15.68-34.944 34.944l0 82.048 804.224 0 0-82.048zM738.88 602.432c0 47.072-38.176 85.248-85.248 85.248s-85.248-38.176-85.248-85.248c0-47.072 38.176-85.248 85.248-85.248s85.248 38.176 85.248 85.248zM804.992 264.64l0-62.976-804.224 0 0 665.408c0 18.56 14.656 33.472 32.96 34.56l402.24 0c61.12 44.544 136.192 71.168 217.664 71.168 204.544 0 370.368-165.824 370.368-370.368 0-150.592-89.984-279.936-219.008-337.792zM412.096 298.24l30.528 0c-10.624 7.36-20.8 15.36-30.528 23.744l0-23.744zM63.04 298.24l153.024 0 0 153.024-153.024 0 0-153.024zM216.064 805.056l-153.024 0 0-153.024 153.024 0 0 153.024zM219.136 631.232l-153.024 0 0-153.024 153.024 0 0 153.024zM237.568 805.056l0-153.024 49.408 0c7.488 55.936 27.264 107.904 56.832 153.024l-106.24 0zM284.672 631.232l-44.032 0 0-153.024 64.384 0c-13.824 38.848-21.824 80.576-21.824 124.224 0 9.728 0.768 19.264 1.472 28.8zM390.592 341.76c-31.168 31.424-56.512 68.544-74.88 109.44l-78.144 0 0-152.96 153.024 0 0 43.52zM899.136 638.4l-63.36 12.864c-4.288 16.064-10.688 31.296-18.816 45.376l35.712 53.888-50.944 50.944-53.888-35.712c-14.08 8.128-29.312 14.528-45.376 18.816l-12.864 63.36-72 0-12.864-63.36c-16.064-4.288-31.296-10.688-45.376-18.816l-53.888 35.712-50.944-50.944 35.712-53.888c-8.128-14.08-14.528-29.312-18.816-45.376l-63.36-12.864 0-72 63.36-12.864c4.352-16.064 10.688-31.296 18.816-45.312l-35.712-53.952 50.944-50.944 53.888 35.776c14.08-8.128 29.312-14.464 45.376-18.816l12.864-63.36 72 0 12.864 63.36c16.064 4.288 31.296 10.688 45.376 18.816l53.888-35.712 50.944 50.944-35.712 53.824c8.128 14.08 14.528 29.312 18.816 45.376l63.36 12.864 0 72z" p-id="1722"></path></svg>
|
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.6 KiB |
@@ -12,4 +12,4 @@ distributed under the License is distributed on an "AS IS" BASIS,
|
|||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
See the License for the specific language governing permissions and
|
See the License for the specific language governing permissions and
|
||||||
limitations under the License. -->
|
limitations under the License. -->
|
||||||
<svg t="1655695739627" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2218" width="48" height="48"><path d="M173.292308 177.230769C86.646154 265.846154 39.384615 382.030769 39.384615 504.123077 39.384615 531.692308 61.046154 551.384615 86.646154 551.384615s47.261538-21.661538 47.261538-47.261538c-1.969231-96.492308 37.415385-189.046154 106.338462-257.969231s163.446154-106.338462 257.969231-106.338461c27.569231 0 47.261538-21.661538 47.261538-47.261539 0-27.569231-21.661538-47.261538-47.261538-47.261538C378.092308 43.323077 259.938462 90.584615 173.292308 177.230769z m57.107692 326.892308c0 27.569231 19.692308 47.261538 47.261538 47.261538s47.261538-21.661538 47.261539-47.261538c0-45.292308 17.723077-90.584615 51.2-122.092308 33.476923-33.476923 76.8-49.230769 122.092308-51.2 27.569231 0 47.261538-21.661538 47.261538-47.261538 0-27.569231-19.692308-47.261538-47.261538-47.261539-70.892308 0-139.815385 27.569231-191.015385 76.8-7.876923 9.846154-80.738462 82.707692-76.8 191.015385z m665.6-204.8c-17.723077-23.630769-41.353846-51.2-45.292308-55.138462-5.907692-3.938462-13.784615-7.876923-21.661538-7.876923-7.876923 0-15.753846 1.969231-19.692308 7.876923L610.461538 441.107692c-47.261538-39.384615-118.153846-37.415385-163.446153 7.876923-45.292308 45.292308-47.261538 116.184615-7.876923 163.446154l-191.015385 191.015385c-5.907692 5.907692-9.846154 13.784615-9.846154 21.661538 0 9.846154 3.938462 19.692308 11.815385 25.6l53.16923 39.384616c72.861538 57.107692 163.446154 88.615385 259.938462 88.615384 232.369231 0 421.415385-189.046154 421.415385-421.415384 0-94.523077-33.476923-185.107692-88.615385-257.969231z" p-id="2219" fill="#707070"></path></svg>
|
<svg t="1655695739627" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2218" width="48" height="48"><path d="M173.292308 177.230769C86.646154 265.846154 39.384615 382.030769 39.384615 504.123077 39.384615 531.692308 61.046154 551.384615 86.646154 551.384615s47.261538-21.661538 47.261538-47.261538c-1.969231-96.492308 37.415385-189.046154 106.338462-257.969231s163.446154-106.338462 257.969231-106.338461c27.569231 0 47.261538-21.661538 47.261538-47.261539 0-27.569231-21.661538-47.261538-47.261538-47.261538C378.092308 43.323077 259.938462 90.584615 173.292308 177.230769z m57.107692 326.892308c0 27.569231 19.692308 47.261538 47.261538 47.261538s47.261538-21.661538 47.261539-47.261538c0-45.292308 17.723077-90.584615 51.2-122.092308 33.476923-33.476923 76.8-49.230769 122.092308-51.2 27.569231 0 47.261538-21.661538 47.261538-47.261538 0-27.569231-19.692308-47.261538-47.261538-47.261539-70.892308 0-139.815385 27.569231-191.015385 76.8-7.876923 9.846154-80.738462 82.707692-76.8 191.015385z m665.6-204.8c-17.723077-23.630769-41.353846-51.2-45.292308-55.138462-5.907692-3.938462-13.784615-7.876923-21.661538-7.876923-7.876923 0-15.753846 1.969231-19.692308 7.876923L610.461538 441.107692c-47.261538-39.384615-118.153846-37.415385-163.446153 7.876923-45.292308 45.292308-47.261538 116.184615-7.876923 163.446154l-191.015385 191.015385c-5.907692 5.907692-9.846154 13.784615-9.846154 21.661538 0 9.846154 3.938462 19.692308 11.815385 25.6l53.16923 39.384616c72.861538 57.107692 163.446154 88.615385 259.938462 88.615384 232.369231 0 421.415385-189.046154 421.415385-421.415384 0-94.523077-33.476923-185.107692-88.615385-257.969231z" p-id="2219"></path></svg>
|
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 2.4 KiB |
18
src/assets/icons/hierarchy_topology.svg
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
<!-- Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
contributor license agreements. See the NOTICE file distributed with
|
||||||
|
this work for additional information regarding copyright ownership.
|
||||||
|
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
(the "License"); you may not use this file except in compliance with
|
||||||
|
the License. You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License. -->
|
||||||
|
|
||||||
|
<svg t="1704964118567" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5167">
|
||||||
|
<path d="M900.032 646.016h-56.064V502.976a16 16 0 0 0-16-16H544v-96h62.976c22.144 0 40-17.92 40-40V161.024a40 40 0 0 0-40-40H417.024a40 40 0 0 0-40 40v189.952c0 22.144 17.92 40 40 40H480v96H195.968a16 16 0 0 0-16 16v143.04h-55.936a38.016 38.016 0 0 0-38.016 38.016v176c0 20.928 17.024 37.952 37.952 37.952h176a38.016 38.016 0 0 0 38.016-38.016v-176a38.016 38.016 0 0 0-37.952-37.952h-56V550.976H480v95.04h-56a38.016 38.016 0 0 0-38.016 38.016v176c0 20.928 17.024 37.952 38.016 37.952h176a38.016 38.016 0 0 0 38.016-38.016v-176a38.016 38.016 0 0 0-38.016-37.952H544V550.976h236.032v95.04h-56.064a38.016 38.016 0 0 0-37.952 38.016v176c0 20.928 17.024 37.952 38.016 37.952h176a38.016 38.016 0 0 0 37.952-38.016v-176a38.016 38.016 0 0 0-38.016-37.952zM440.96 184.96h141.952v141.952H441.024V185.024zM278.016 838.016H145.92V705.92h132.032v132.032z m299.968 0H446.08V705.92H577.92v132.032z m300.032 0h-132.032V705.92h132.032v132.032z" p-id="5168"></path>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.8 KiB |
138
src/assets/icons/logo-light.svg
Normal file
@@ -0,0 +1,138 @@
|
|||||||
|
<!-- Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
contributor license agreements. See the NOTICE file distributed with
|
||||||
|
this work for additional information regarding copyright ownership.
|
||||||
|
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
(the "License"); you may not use this file except in compliance with
|
||||||
|
the License. You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License. -->
|
||||||
|
<svg version="1.0" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400.000000 400.000000"
|
||||||
|
preserveAspectRatio="xMidYMid meet">
|
||||||
|
|
||||||
|
<g transform="translate(0.000000,400.000000) scale(0.100000,-0.100000)"
|
||||||
|
fill="#000000" stroke="none">
|
||||||
|
<path d="M1737 3725 c-379 -61 -696 -224 -968 -495 -249 -248 -403 -533 -481
|
||||||
|
-890 -20 -93 -22 -133 -22 -340 0 -207 2 -247 22 -339 48 -217 123 -407 231
|
||||||
|
-581 253 -406 658 -688 1141 -791 91 -20 135 -23 330 -24 172 0 246 4 315 17
|
||||||
|
361 69 669 231 926 487 271 272 438 604 494 983 23 154 16 448 -15 593 -147
|
||||||
|
694 -668 1214 -1366 1365 -130 29 -472 37 -607 15z m461 -131 c24 -3 52 -14
|
||||||
|
63 -25 23 -23 25 -76 3 -100 -15 -17 -15 -19 0 -34 25 -26 20 -82 -10 -112
|
||||||
|
-25 -25 -28 -25 -112 -19 -48 4 -88 8 -89 10 -1 1 4 60 12 131 8 72 15 137 15
|
||||||
|
145 0 17 14 17 118 4z m-359 -30 c30 -22 61 -89 61 -137 0 -48 -22 -102 -48
|
||||||
|
-116 -23 -12 -163 -43 -169 -38 -7 7 -53 280 -48 285 8 9 78 20 130 21 32 1
|
||||||
|
59 -5 74 -15z m564 -8 c7 -8 22 -44 31 -80 l18 -66 62 48 c48 38 66 47 85 43
|
||||||
|
23 -6 18 -12 -58 -71 -76 -61 -83 -69 -98 -122 -12 -43 -21 -58 -34 -58 -28 0
|
||||||
|
-30 14 -10 73 l19 56 -29 93 c-16 51 -29 94 -29 96 0 8 31 0 43 -12z m-858
|
||||||
|
-45 c0 -8 -30 -27 -69 -43 -38 -15 -71 -30 -74 -32 -4 -4 17 -76 22 -76 1 0
|
||||||
|
31 11 66 25 76 30 90 31 90 7 0 -13 -19 -24 -70 -42 -61 -21 -69 -27 -64 -45
|
||||||
|
15 -46 24 -65 32 -65 5 0 42 14 82 30 57 23 75 27 82 18 4 -7 8 -16 8 -19 0
|
||||||
|
-7 -180 -79 -197 -79 -6 0 -28 44 -49 98 -20 53 -43 112 -51 131 -7 19 -11 36
|
||||||
|
-9 38 10 11 173 71 186 70 8 -1 15 -9 15 -16z m-257 -157 c26 -29 28 -61 6
|
||||||
|
-92 -12 -17 -12 -22 -2 -22 7 0 42 -13 77 -29 62 -28 63 -29 41 -44 -21 -15
|
||||||
|
-26 -14 -59 2 -20 10 -53 24 -73 30 -37 12 -37 13 -96 -25 -2 -1 13 -27 32
|
||||||
|
-58 34 -52 35 -56 17 -65 -17 -10 -27 2 -92 101 -39 62 -74 119 -76 128 -2 9
|
||||||
|
14 26 44 44 119 73 138 76 181 30z m-292 -145 c3 -6 -19 -37 -52 -70 l-58 -59
|
||||||
|
29 -30 29 -30 56 55 c48 47 59 54 69 42 10 -12 2 -24 -44 -68 l-56 -52 32 -33
|
||||||
|
32 -33 64 59 c52 47 68 57 78 47 11 -10 -1 -27 -66 -92 l-80 -80 -99 105 c-55
|
||||||
|
58 -100 108 -100 111 0 10 139 139 150 139 5 0 12 -5 16 -11z m1197 -44 c494
|
||||||
|
-74 896 -467 982 -959 19 -113 19 -299 0 -410 -73 -416 -377 -773 -776 -910
|
||||||
|
-142 -48 -213 -59 -384 -59 -175 -1 -241 10 -400 65 -383 131 -680 481 -761
|
||||||
|
893 -22 115 -20 335 5 450 79 372 314 669 656 831 214 102 441 135 678 99z
|
||||||
|
m-1319 -258 c81 -91 95 -110 86 -126 -9 -18 -14 -18 -122 16 -62 19 -117 38
|
||||||
|
-123 41 -10 6 17 -27 109 -133 41 -46 48 -60 39 -73 -13 -20 0 -23 -160 28
|
||||||
|
-89 28 -133 47 -133 56 0 28 27 25 134 -15 73 -26 103 -34 94 -23 -7 9 -43 50
|
||||||
|
-80 91 -55 61 -65 78 -57 93 13 25 30 23 147 -15 l103 -33 -82 82 c-67 67 -80
|
||||||
|
85 -74 103 4 12 10 21 14 19 4 -2 51 -51 105 -111z m2502 -151 c38 -38 44 -77
|
||||||
|
19 -126 -19 -37 -43 -50 -95 -50 -61 0 -100 41 -100 105 0 40 5 52 31 76 46
|
||||||
|
42 99 41 145 -5z m-2677 -171 c16 -8 41 -29 56 -47 24 -29 27 -38 23 -91 -4
|
||||||
|
-54 -8 -63 -41 -93 -32 -30 -44 -34 -90 -34 -126 0 -200 102 -150 207 9 20 30
|
||||||
|
44 47 54 38 23 115 25 155 4z m-145 -306 c35 -16 50 -59 42 -124 l-6 -54 32
|
||||||
|
-5 c18 -3 44 -7 58 -8 19 -2 24 -8 22 -23 -2 -11 -5 -21 -6 -22 -5 -6 -272 30
|
||||||
|
-280 37 -5 5 -4 42 3 87 9 63 16 82 37 101 28 24 60 28 98 11z m2717 -590 c14
|
||||||
|
-7 18 -16 14 -27 -4 -9 -20 -52 -36 -95 l-29 -78 33 -13 c77 -32 72 -34 105
|
||||||
|
51 29 75 55 102 67 70 3 -7 -7 -48 -24 -90 l-29 -76 55 -21 c30 -11 58 -18 62
|
||||||
|
-15 5 2 23 45 41 95 31 87 41 99 68 82 10 -7 2 -36 -32 -126 -25 -65 -47 -120
|
||||||
|
-49 -123 -3 -2 -82 26 -177 62 -95 36 -175 65 -177 65 -9 0 1 33 39 137 24 62
|
||||||
|
44 113 46 113 2 0 12 -5 23 -11z m34 -411 c80 -57 145 -106 145 -109 0 -3 -6
|
||||||
|
-14 -14 -24 -13 -18 -17 -16 -79 28 -36 26 -69 47 -74 47 -10 0 -113 -145
|
||||||
|
-113 -158 0 -7 61 -53 122 -93 14 -9 -11 -52 -26 -46 -10 4 -288 198 -304 212
|
||||||
|
-6 5 18 45 26 45 5 0 36 -21 71 -46 34 -25 64 -44 65 -42 1 2 25 35 52 73 28
|
||||||
|
39 53 75 57 81 4 7 -18 29 -58 55 -35 24 -65 49 -65 55 0 16 23 35 38 29 7 -2
|
||||||
|
78 -51 157 -107z m-2350 -142 c35 -15 65 -59 65 -96 0 -54 -57 -110 -112 -110
|
||||||
|
-13 0 -37 9 -55 20 -69 41 -63 154 9 185 42 18 51 18 93 1z m2003 -75 c8 -5
|
||||||
|
12 -17 10 -27 -3 -14 -11 -18 -33 -17 -82 7 -145 -48 -145 -126 0 -89 73 -161
|
||||||
|
162 -161 43 0 54 4 84 34 27 27 34 42 34 74 0 32 4 41 22 45 29 8 38 1 38 -31
|
||||||
|
-1 -38 -32 -102 -66 -133 -75 -69 -196 -57 -276 28 -27 28 -58 99 -58 132 0
|
||||||
|
65 56 152 115 177 34 15 94 18 113 5z m-247 -340 c79 -74 145 -138 147 -142 2
|
||||||
|
-4 -7 -13 -19 -19 -19 -11 -26 -7 -65 31 l-43 42 -68 -31 -68 -32 -3 -64 c-2
|
||||||
|
-55 -6 -66 -23 -71 -11 -4 -23 -5 -25 -2 -3 2 -9 94 -14 203 -8 180 -7 200 8
|
||||||
|
212 9 7 19 11 23 10 4 -2 71 -63 150 -137z m-321 34 c58 -30 78 -120 40 -182
|
||||||
|
-19 -31 -48 -44 -151 -67 l-26 -6 14 -60 c15 -68 12 -80 -20 -80 -20 0 -24 12
|
||||||
|
-56 173 -19 94 -36 179 -38 188 -4 12 11 19 64 31 90 20 138 21 173 3z m-334
|
||||||
|
-207 c38 -105 71 -195 72 -200 2 -4 -10 -8 -26 -8 -28 0 -32 5 -49 58 l-20 57
|
||||||
|
-79 3 -79 3 -27 -54 c-24 -49 -29 -54 -53 -50 -14 3 -25 9 -23 13 2 3 41 88
|
||||||
|
87 188 112 243 106 244 197 -10z"/>
|
||||||
|
<path d="M2120 3537 c0 -14 -2 -32 -6 -40 -4 -11 6 -16 43 -20 54 -6 83 5 83
|
||||||
|
32 0 27 -24 43 -75 49 -43 4 -45 3 -45 -21z"/>
|
||||||
|
<path d="M2105 3399 c-4 -22 -5 -42 -2 -45 9 -10 77 -16 101 -10 52 13 44 70
|
||||||
|
-12 86 -68 19 -79 14 -87 -31z"/>
|
||||||
|
<path d="M1697 3533 c-13 -3 -17 -11 -14 -26 3 -12 11 -58 18 -102 7 -44 14
|
||||||
|
-81 15 -83 7 -10 96 13 113 29 39 36 21 165 -24 183 -18 7 -80 6 -108 -1z"/>
|
||||||
|
<path d="M1156 3310 l-47 -30 22 -33 c12 -17 24 -34 25 -36 6 -7 94 50 103 67
|
||||||
|
5 10 5 27 0 40 -12 31 -45 28 -103 -8z"/>
|
||||||
|
<path d="M1060 2137 c-20 -10 -25 -20 -25 -52 0 -37 4 -42 53 -75 79 -52 68
|
||||||
|
-97 -21 -88 -23 2 -32 -1 -32 -12 0 -11 14 -16 57 -18 48 -2 60 0 77 19 40 43
|
||||||
|
27 78 -46 125 -71 45 -70 68 5 72 35 2 52 7 52 16 0 26 -78 34 -120 13z"/>
|
||||||
|
<path d="M1230 2020 c0 -123 1 -130 20 -130 17 0 20 7 20 43 l1 42 20 -25 c12
|
||||||
|
-14 27 -33 34 -43 8 -11 22 -17 35 -15 21 3 20 4 -9 43 -38 50 -38 61 0 105
|
||||||
|
29 34 29 35 8 38 -12 2 -26 -4 -34 -15 -7 -10 -22 -29 -34 -43 l-20 -25 -1 78
|
||||||
|
c0 70 -2 77 -20 77 -19 0 -20 -7 -20 -130z"/>
|
||||||
|
<path d="M2030 1976 c0 -130 1 -136 20 -136 20 0 20 5 18 132 -3 117 -5 133
|
||||||
|
-20 136 -16 3 -18 -8 -18 -132z"/>
|
||||||
|
<path d="M2133 2103 c-10 -3 -13 -40 -13 -134 0 -121 1 -129 19 -129 16 0 20
|
||||||
|
8 23 43 l3 42 30 -42 c20 -28 38 -42 53 -43 12 0 22 3 22 6 0 3 -16 26 -35 51
|
||||||
|
l-35 46 35 43 c40 48 42 54 18 54 -10 0 -35 -19 -55 -42 l-37 -43 -1 78 c0 75
|
||||||
|
-2 81 -27 70z"/>
|
||||||
|
<path d="M2310 2090 c0 -13 7 -20 20 -20 13 0 20 7 20 20 0 13 -7 20 -20 20
|
||||||
|
-13 0 -20 -7 -20 -20z"/>
|
||||||
|
<path d="M1410 2073 c0 -5 7 -30 15 -58 9 -27 20 -67 26 -87 5 -22 16 -38 24
|
||||||
|
-38 8 0 15 -4 15 -8 0 -17 -25 -32 -52 -32 -18 0 -28 -5 -28 -15 0 -22 72 -20
|
||||||
|
92 3 9 9 28 60 42 112 15 52 29 103 32 113 5 15 1 18 -17 15 -17 -2 -25 -12
|
||||||
|
-32 -38 -23 -94 -29 -110 -36 -106 -5 3 -11 20 -15 38 -17 85 -27 108 -46 108
|
||||||
|
-11 0 -20 -3 -20 -7z"/>
|
||||||
|
<path d="M1766 2031 c-3 -4 -8 -35 -12 -67 -8 -75 -19 -96 -28 -58 -25 105
|
||||||
|
-26 105 -53 102 -23 -3 -29 -10 -41 -58 -15 -63 -32 -88 -32 -48 0 14 -3 40
|
||||||
|
-7 59 -5 28 -7 30 -14 14 -13 -35 -10 -112 6 -125 29 -24 49 -7 67 55 9 33 17
|
||||||
|
62 18 65 1 3 11 -24 23 -60 19 -57 25 -65 47 -65 22 0 27 7 37 50 7 28 16 71
|
||||||
|
19 98 5 39 4 47 -9 47 -9 0 -18 -4 -21 -9z"/>
|
||||||
|
<path d="M1853 2033 c-7 -2 -13 -12 -13 -20 0 -12 7 -14 31 -9 34 7 69 -8 69
|
||||||
|
-28 0 -8 -17 -16 -42 -20 -53 -9 -68 -21 -68 -57 0 -43 21 -57 90 -56 l60 0 0
|
||||||
|
68 c0 103 -19 130 -90 128 -14 0 -31 -3 -37 -6z m87 -128 c0 -18 -7 -26 -24
|
||||||
|
-31 -30 -7 -46 1 -46 25 0 24 9 31 42 31 23 0 28 -4 28 -25z"/>
|
||||||
|
<path d="M2317 2033 c-4 -3 -7 -48 -7 -100 0 -86 1 -93 20 -93 19 0 20 7 20
|
||||||
|
100 0 77 -3 100 -13 100 -8 0 -17 -3 -20 -7z"/>
|
||||||
|
<path d="M2400 1938 c0 -91 1 -98 20 -98 17 0 19 8 22 78 l3 77 35 0 35 0 3
|
||||||
|
-77 c3 -70 5 -78 22 -78 18 0 20 7 20 78 0 106 -9 117 -94 118 l-66 1 0 -99z"/>
|
||||||
|
<path d="M2642 2025 l-33 -14 4 -73 c2 -40 -1 -84 -7 -97 -9 -20 -6 -27 17
|
||||||
|
-47 51 -43 147 -23 147 30 0 31 -16 43 -78 57 -64 15 -67 29 -7 29 58 0 90 28
|
||||||
|
81 71 -3 15 -1 31 4 34 39 24 -74 32 -128 10z m74 -29 c27 -20 7 -51 -32 -51
|
||||||
|
-23 0 -30 5 -32 24 -6 38 29 52 64 27z m-8 -151 c14 -4 22 -13 20 -23 -4 -22
|
||||||
|
-60 -28 -77 -9 -15 19 -3 49 18 43 9 -2 26 -7 39 -11z"/>
|
||||||
|
<path d="M549 2531 c-50 -50 -35 -120 33 -151 52 -24 80 -25 117 -5 72 37 56
|
||||||
|
137 -26 171 -52 22 -91 18 -124 -15z"/>
|
||||||
|
<path d="M471 2222 c-10 -19 -18 -99 -11 -105 3 -2 24 -7 47 -10 l42 -5 7 54
|
||||||
|
c4 37 2 59 -6 69 -17 21 -67 19 -79 -3z"/>
|
||||||
|
<path d="M2571 750 c0 -25 4 -66 7 -91 l7 -46 57 27 57 27 -65 64 -64 63 1
|
||||||
|
-44z"/>
|
||||||
|
<path d="M2247 708 c-25 -7 -36 -15 -33 -23 2 -7 10 -41 17 -74 l12 -62 31 6
|
||||||
|
c84 17 103 26 114 50 17 37 15 59 -9 89 -23 29 -61 33 -132 14z"/>
|
||||||
|
<path d="M1927 590 l-36 -75 60 -9 c33 -5 62 -7 64 -4 4 4 -4 28 -47 148 -4 9
|
||||||
|
-19 -14 -41 -60z"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 8.9 KiB |
17
src/assets/icons/workflow_scheduler.svg
Executable file
@@ -0,0 +1,17 @@
|
|||||||
|
<!-- Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
contributor license agreements. See the NOTICE file distributed with
|
||||||
|
this work for additional information regarding copyright ownership.
|
||||||
|
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
(the "License"); you may not use this file except in compliance with
|
||||||
|
the License. You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License. -->
|
||||||
|
<svg t="1712402256302" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1578">
|
||||||
|
<path d="M640 885.589333a39.424 39.424 0 0 1-32.938667 46.634667A483.413333 483.413333 0 0 1 512 938.666667a295.68 295.68 0 0 1-92.117333-16.768 32.085333 32.085333 0 1 1 13.568-62.72 415.658667 415.658667 0 0 0 78.549333 15.36 295.722667 295.722667 0 0 0 75.434667-4.266667c20.181333-9.514667 47.317333-9.216 52.565333 15.36z m-397.824-307.968a160.597333 160.597333 0 0 1 156.842667 164.096 198.314667 198.314667 0 0 1-6.954667 48.426667 154.325333 154.325333 0 0 1-149.930667 115.712 164.266667 164.266667 0 0 1 0-328.192z m539.605333 0a164.266667 164.266667 0 1 1-156.842666 164.096 160.597333 160.597333 0 0 1 156.885333-164.096z m-30.122666-262.058666A344.917333 344.917333 0 0 1 853.333333 497.024c1.109333 16.768-1.749333 38.826667-30.08 41.258667a32.554667 32.554667 0 0 1-33.493333-26.325334 334.848 334.848 0 0 0-80.341333-146.304 34.517333 34.517333 0 0 1-4.992-54.613333 33.408 33.408 0 0 1 47.232 4.693333z m-417.706667-4.48c13.269333 16.64 4.821333 28.501333-8.789333 48.512A422.4 422.4 0 0 0 256 517.802667a33.152 33.152 0 0 1-36.821333 26.709333 31.573333 31.573333 0 0 1-27.52-32.512 89.6 89.6 0 0 1 3.797333-29.226667 402.773333 402.773333 0 0 1 93.312-177.536 30.592 30.592 0 0 1 45.184 5.845334zM512 85.333333a164.266667 164.266667 0 1 1-156.842667 164.096A160.597333 160.597333 0 0 1 512 85.333333z" p-id="1579"></path>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 2.2 KiB |
BIN
src/assets/img/technologies/ACTIVEMQ.png
Executable file → Normal file
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 8.5 KiB |
BIN
src/assets/img/technologies/SOLONMVC.png
Normal file
After Width: | Height: | Size: 3.1 KiB |
BIN
src/assets/img/tools/BROWSER.png
Normal file
After Width: | Height: | Size: 314 B |
BIN
src/assets/img/tools/CILIUM_SERVICE.png
Normal file
After Width: | Height: | Size: 2.9 KiB |
BIN
src/assets/img/tools/DATABASE.png
Normal file
After Width: | Height: | Size: 150 B |
BIN
src/assets/img/tools/ELASTICSEARCH.png
Normal file
After Width: | Height: | Size: 150 B |
BIN
src/assets/img/tools/GENERAL.png
Normal file
After Width: | Height: | Size: 211 B |
BIN
src/assets/img/tools/K8S.png
Normal file
After Width: | Height: | Size: 471 B |
BIN
src/assets/img/tools/K8S_SERVICE.png
Normal file
After Width: | Height: | Size: 471 B |
BIN
src/assets/img/tools/MESH.png
Normal file
After Width: | Height: | Size: 262 B |
BIN
src/assets/img/tools/MESH_CP.png
Normal file
After Width: | Height: | Size: 262 B |
BIN
src/assets/img/tools/MESH_DP.png
Normal file
After Width: | Height: | Size: 262 B |
BIN
src/assets/img/tools/MONGODB.png
Normal file
After Width: | Height: | Size: 150 B |
BIN
src/assets/img/tools/MQ.png
Normal file
After Width: | Height: | Size: 16 KiB |
BIN
src/assets/img/tools/NGINX.png
Normal file
After Width: | Height: | Size: 263 B |
BIN
src/assets/img/tools/OS_LINUX.png
Normal file
After Width: | Height: | Size: 241 B |
BIN
src/assets/img/tools/POSTGRESQL.png
Normal file
After Width: | Height: | Size: 150 B |
BIN
src/assets/img/tools/RABBITMQ.png
Normal file
After Width: | Height: | Size: 16 KiB |
BIN
src/assets/img/tools/VIRTUAL_CACHE.png
Normal file
After Width: | Height: | Size: 211 B |
BIN
src/assets/img/tools/VIRTUAL_DATABASE.png
Normal file
After Width: | Height: | Size: 211 B |
BIN
src/assets/img/tools/VIRTUAL_GATEWAY.png
Normal file
After Width: | Height: | Size: 211 B |
@@ -451,7 +451,7 @@ limitations under the License. -->
|
|||||||
}
|
}
|
||||||
|
|
||||||
.calendar + .calendar {
|
.calendar + .calendar {
|
||||||
border-left: solid 1px #eaeaea;
|
border-left: solid 1px var(--sw-border-color-light);
|
||||||
margin-left: 5px;
|
margin-left: 5px;
|
||||||
padding-left: 5px;
|
padding-left: 5px;
|
||||||
}
|
}
|
||||||
@@ -464,7 +464,7 @@ limitations under the License. -->
|
|||||||
}
|
}
|
||||||
|
|
||||||
.calendar-head a {
|
.calendar-head a {
|
||||||
color: #666;
|
color: var(--sw-topology-color);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
@@ -568,7 +568,7 @@ limitations under the License. -->
|
|||||||
|
|
||||||
.calendar-hour {
|
.calendar-hour {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
border: 1px solid #e6e5e5;
|
border: 1px solid var(--sw-border-color-light);
|
||||||
color: #9e9e9e;
|
color: #9e9e9e;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -53,6 +53,7 @@ limitations under the License. -->
|
|||||||
import { addResizeListener, removeResizeListener } from "@/utils/event";
|
import { addResizeListener, removeResizeListener } from "@/utils/event";
|
||||||
import Trace from "@/views/dashboard/related/trace/Index.vue";
|
import Trace from "@/views/dashboard/related/trace/Index.vue";
|
||||||
import associateProcessor from "@/hooks/useAssociateProcessor";
|
import associateProcessor from "@/hooks/useAssociateProcessor";
|
||||||
|
import { WidgetType } from "@/views/dashboard/data";
|
||||||
|
|
||||||
/*global Nullable, defineProps, defineEmits, Indexable*/
|
/*global Nullable, defineProps, defineEmits, Indexable*/
|
||||||
const emits = defineEmits(["select"]);
|
const emits = defineEmits(["select"]);
|
||||||
@@ -63,7 +64,7 @@ limitations under the License. -->
|
|||||||
const currentParams = ref<Nullable<EventParams>>(null);
|
const currentParams = ref<Nullable<EventParams>>(null);
|
||||||
const showTrace = ref<boolean>(false);
|
const showTrace = ref<boolean>(false);
|
||||||
const traceOptions = ref<{ type: string; filters?: unknown }>({
|
const traceOptions = ref<{ type: string; filters?: unknown }>({
|
||||||
type: "Trace",
|
type: WidgetType.Trace,
|
||||||
});
|
});
|
||||||
const menuPos = reactive<{ x: number; y: number }>({ x: NaN, y: NaN });
|
const menuPos = reactive<{ x: number; y: number }>({ x: NaN, y: NaN });
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
@@ -234,12 +235,10 @@ limitations under the License. -->
|
|||||||
.no-data {
|
.no-data {
|
||||||
font-size: $font-size-smaller;
|
font-size: $font-size-smaller;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
box-sizing: border-box;
|
align-items: center;
|
||||||
display: -webkit-box;
|
justify-content: center;
|
||||||
-webkit-box-orient: horizontal;
|
display: flex;
|
||||||
-webkit-box-pack: center;
|
color: var(--text-color-placeholder);
|
||||||
-webkit-box-align: center;
|
|
||||||
color: #666;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.chart {
|
.chart {
|
||||||
|
@@ -85,7 +85,7 @@ limitations under the License. -->
|
|||||||
.bar-select {
|
.bar-select {
|
||||||
position: relative;
|
position: relative;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
border: 1px solid #ddd;
|
border: 1px solid var(--el-border-color);
|
||||||
background: $theme-background;
|
background: $theme-background;
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
color: $font-color;
|
color: $font-color;
|
||||||
@@ -97,8 +97,8 @@ limitations under the License. -->
|
|||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
margin: 3px;
|
margin: 3px;
|
||||||
color: $active-color;
|
color: $active-color;
|
||||||
background-color: #fafafa;
|
background-color: var(--theme-background);
|
||||||
border: 1px solid #e8e8e8;
|
border: 1px solid var(--el-color-primary);
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -139,7 +139,7 @@ limitations under the License. -->
|
|||||||
left: 0;
|
left: 0;
|
||||||
background-color: $theme-background;
|
background-color: $theme-background;
|
||||||
box-shadow: 0 1px 6px rgb(99 99 99 / 20%);
|
box-shadow: 0 1px 6px rgb(99 99 99 / 20%);
|
||||||
border: 1px solid #ddd;
|
border: 1px solid var(--el-border-color);
|
||||||
width: 100%;
|
width: 100%;
|
||||||
border-radius: 0 0 3px 3px;
|
border-radius: 0 0 3px 3px;
|
||||||
border-right-width: 1px !important;
|
border-right-width: 1px !important;
|
||||||
@@ -169,7 +169,7 @@ limitations under the License. -->
|
|||||||
}
|
}
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: #f5f5f5;
|
background-color: var(--layout-background);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@@ -28,8 +28,8 @@ limitations under the License. -->
|
|||||||
:filterable="filterable"
|
:filterable="filterable"
|
||||||
>
|
>
|
||||||
<el-option
|
<el-option
|
||||||
v-for="item in options"
|
v-for="(item, index) in options"
|
||||||
:key="item.value || ''"
|
:key="`${item.value}${index}`"
|
||||||
:label="item.label || ''"
|
:label="item.label || ''"
|
||||||
:value="item.value || ''"
|
:value="item.value || ''"
|
||||||
:disabled="item.disabled || false"
|
:disabled="item.disabled || false"
|
||||||
|
@@ -31,7 +31,7 @@ limitations under the License. -->
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { nextTick, ref } from "vue";
|
import { nextTick, ref, watch } from "vue";
|
||||||
import type { PropType } from "vue";
|
import type { PropType } from "vue";
|
||||||
import { ElInput } from "element-plus";
|
import { ElInput } from "element-plus";
|
||||||
|
|
||||||
@@ -69,10 +69,17 @@ limitations under the License. -->
|
|||||||
inputValue.value = "";
|
inputValue.value = "";
|
||||||
emits("change", dynamicTags.value);
|
emits("change", dynamicTags.value);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.tags,
|
||||||
|
() => {
|
||||||
|
dynamicTags.value = props.tags || [];
|
||||||
|
},
|
||||||
|
);
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.input-name {
|
.input-name {
|
||||||
width: 300px;
|
width: 250px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.vertical {
|
.vertical {
|
||||||
|
@@ -447,7 +447,7 @@ limitations under the License. -->
|
|||||||
width: 100px;
|
width: 100px;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
border-right: solid 1px #eaeaea;
|
border-right: solid 1px var(--sw-border-color-light);
|
||||||
}
|
}
|
||||||
|
|
||||||
&__shortcut {
|
&__shortcut {
|
||||||
@@ -457,7 +457,7 @@ limitations under the License. -->
|
|||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
line-height: 34px;
|
line-height: 34px;
|
||||||
font-size: $font-size-smaller;
|
font-size: $font-size-smaller;
|
||||||
color: #666;
|
color: var(--sw-topology-color);
|
||||||
text-align: left;
|
text-align: left;
|
||||||
outline: none;
|
outline: none;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
@@ -532,6 +532,6 @@ limitations under the License. -->
|
|||||||
}
|
}
|
||||||
|
|
||||||
.datepicker__buttons .datepicker__button-cancel {
|
.datepicker__buttons .datepicker__button-cancel {
|
||||||
background: #666;
|
background: var(--sw-topology-color);
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@@ -46,3 +46,14 @@ export const Alarm = {
|
|||||||
}
|
}
|
||||||
}`,
|
}`,
|
||||||
};
|
};
|
||||||
|
export const AlarmTagKeys = {
|
||||||
|
variable: "$duration: Duration!",
|
||||||
|
query: `
|
||||||
|
tagKeys: queryAlarmTagAutocompleteKeys(duration: $duration)`,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const AlarmTagValues = {
|
||||||
|
variable: "$tagKey: String!, $duration: Duration!",
|
||||||
|
query: `
|
||||||
|
tagValues: queryAlarmTagAutocompleteValues(tagKey: $tagKey, duration: $duration)`,
|
||||||
|
};
|
||||||
|
@@ -23,6 +23,7 @@ export const ServicesTopology = {
|
|||||||
name
|
name
|
||||||
type
|
type
|
||||||
isReal
|
isReal
|
||||||
|
layers
|
||||||
}
|
}
|
||||||
calls {
|
calls {
|
||||||
id
|
id
|
||||||
@@ -99,3 +100,56 @@ export const ProcessTopology = {
|
|||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
};
|
};
|
||||||
|
export const HierarchyServiceTopology = {
|
||||||
|
variable: "$serviceId: ID!, $layer: String!",
|
||||||
|
query: `
|
||||||
|
hierarchyServiceTopology: getServiceHierarchy(serviceId: $serviceId, layer: $layer) {
|
||||||
|
relations {
|
||||||
|
upperService {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
layer
|
||||||
|
normal
|
||||||
|
}
|
||||||
|
lowerService {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
layer
|
||||||
|
normal
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}`,
|
||||||
|
};
|
||||||
|
export const HierarchyInstanceTopology = {
|
||||||
|
variable: "$instanceId: ID!, $layer: String!",
|
||||||
|
query: `
|
||||||
|
hierarchyInstanceTopology: getInstanceHierarchy(instanceId: $instanceId, layer: $layer) {
|
||||||
|
relations {
|
||||||
|
upperInstance {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
layer
|
||||||
|
normal
|
||||||
|
serviceName
|
||||||
|
serviceId
|
||||||
|
}
|
||||||
|
lowerInstance {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
layer
|
||||||
|
normal
|
||||||
|
serviceName
|
||||||
|
serviceId
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}`,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const ListLayerLevels = {
|
||||||
|
query: `
|
||||||
|
levels: listLayerLevels {
|
||||||
|
layer
|
||||||
|
level
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
};
|
||||||
|
@@ -15,6 +15,8 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Alarm } from "../fragments/alarm";
|
import { Alarm, AlarmTagKeys, AlarmTagValues } from "../fragments/alarm";
|
||||||
|
|
||||||
export const queryAlarms = `query queryAlarms(${Alarm.variable}) {${Alarm.query}}`;
|
export const queryAlarms = `query queryAlarms(${Alarm.variable}) {${Alarm.query}}`;
|
||||||
|
export const queryAlarmTagValues = `query queryTagValues(${AlarmTagValues.variable}) {${AlarmTagValues.query}}`;
|
||||||
|
export const queryAlarmTagKeys = `query queryTagKeys(${AlarmTagKeys.variable}) {${AlarmTagKeys.query}}`;
|
||||||
|
@@ -14,9 +14,20 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
import { InstanceTopology, EndpointTopology, ServicesTopology, ProcessTopology } from "../fragments/topology";
|
import {
|
||||||
|
InstanceTopology,
|
||||||
|
EndpointTopology,
|
||||||
|
ServicesTopology,
|
||||||
|
ProcessTopology,
|
||||||
|
HierarchyServiceTopology,
|
||||||
|
HierarchyInstanceTopology,
|
||||||
|
ListLayerLevels,
|
||||||
|
} from "../fragments/topology";
|
||||||
|
|
||||||
export const getInstanceTopology = `query queryData(${InstanceTopology.variable}) {${InstanceTopology.query}}`;
|
export const getInstanceTopology = `query queryData(${InstanceTopology.variable}) {${InstanceTopology.query}}`;
|
||||||
export const getEndpointTopology = `query queryData(${EndpointTopology.variable}) {${EndpointTopology.query}}`;
|
export const getEndpointTopology = `query queryData(${EndpointTopology.variable}) {${EndpointTopology.query}}`;
|
||||||
export const getServicesTopology = `query queryData(${ServicesTopology.variable}) {${ServicesTopology.query}}`;
|
export const getServicesTopology = `query queryData(${ServicesTopology.variable}) {${ServicesTopology.query}}`;
|
||||||
export const getProcessTopology = `query queryData(${ProcessTopology.variable}) {${ProcessTopology.query}}`;
|
export const getProcessTopology = `query queryData(${ProcessTopology.variable}) {${ProcessTopology.query}}`;
|
||||||
|
export const getHierarchyInstanceTopology = `query queryData(${HierarchyInstanceTopology.variable}) {${HierarchyInstanceTopology.query}}`;
|
||||||
|
export const getHierarchyServiceTopology = `query queryData(${HierarchyServiceTopology.variable}) {${HierarchyServiceTopology.query}}`;
|
||||||
|
export const queryListLayerLevels = `query queryLayerLevels {${ListLayerLevels.query}}`;
|
||||||
|
@@ -14,32 +14,8 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
export enum MetricQueryTypes {
|
export const MaximumEntities = 20;
|
||||||
ReadMetricsValue = "readMetricsValue",
|
|
||||||
ReadMetricsValues = "readMetricsValues",
|
|
||||||
SortMetrics = "sortMetrics",
|
|
||||||
ReadLabeledMetricsValues = "readLabeledMetricsValues",
|
|
||||||
READHEATMAP = "readHeatMap",
|
|
||||||
ReadSampledRecords = "readSampledRecords",
|
|
||||||
ReadRecords = "readRecords",
|
|
||||||
ReadNullableMetricsValue = "readNullableMetricsValue",
|
|
||||||
}
|
|
||||||
|
|
||||||
export enum Calculations {
|
|
||||||
Percentage = "percentage",
|
|
||||||
ByteToKB = "byteToKB",
|
|
||||||
ByteToMB = "byteToMB",
|
|
||||||
ByteToGB = "byteToGB",
|
|
||||||
Apdex = "apdex",
|
|
||||||
ConvertSeconds = "convertSeconds",
|
|
||||||
ConvertMilliseconds = "convertMilliseconds",
|
|
||||||
MsToS = "msTos",
|
|
||||||
Average = "average",
|
|
||||||
PercentageAvg = "percentageAvg",
|
|
||||||
ApdexAvg = "apdexAvg",
|
|
||||||
SecondToDay = "secondToDay",
|
|
||||||
NanosecondToMillisecond = "nanosecondToMillisecond",
|
|
||||||
}
|
|
||||||
export enum sizeEnum {
|
export enum sizeEnum {
|
||||||
XS = "XS",
|
XS = "XS",
|
||||||
SM = "SM",
|
SM = "SM",
|
||||||
@@ -68,50 +44,6 @@ screenMap.set(sizeEnum.XL, screenEnum.XL);
|
|||||||
screenMap.set(sizeEnum.XXL, screenEnum.XXL);
|
screenMap.set(sizeEnum.XXL, screenEnum.XXL);
|
||||||
|
|
||||||
export const RespFields: Indexable = {
|
export const RespFields: Indexable = {
|
||||||
readMetricsValues: `{
|
|
||||||
label
|
|
||||||
values {
|
|
||||||
values {value isEmptyValue}
|
|
||||||
}
|
|
||||||
}`,
|
|
||||||
readMetricsValue: ``,
|
|
||||||
readNullableMetricsValue: `{
|
|
||||||
value
|
|
||||||
isEmptyValue
|
|
||||||
}`,
|
|
||||||
sortMetrics: `{
|
|
||||||
name
|
|
||||||
id
|
|
||||||
value
|
|
||||||
refId
|
|
||||||
}`,
|
|
||||||
readLabeledMetricsValues: `{
|
|
||||||
label
|
|
||||||
values {
|
|
||||||
values {value isEmptyValue}
|
|
||||||
}
|
|
||||||
}`,
|
|
||||||
readHeatMap: `{
|
|
||||||
values {
|
|
||||||
id
|
|
||||||
values
|
|
||||||
}
|
|
||||||
buckets {
|
|
||||||
min
|
|
||||||
max
|
|
||||||
}
|
|
||||||
}`,
|
|
||||||
readSampledRecords: `{
|
|
||||||
name
|
|
||||||
value
|
|
||||||
refId
|
|
||||||
}`,
|
|
||||||
readRecords: `{
|
|
||||||
id
|
|
||||||
name
|
|
||||||
value
|
|
||||||
refId
|
|
||||||
}`,
|
|
||||||
execExpression: `{
|
execExpression: `{
|
||||||
type
|
type
|
||||||
results {
|
results {
|
||||||
|
@@ -17,15 +17,25 @@
|
|||||||
import { ElMessage } from "element-plus";
|
import { ElMessage } from "element-plus";
|
||||||
import { useDashboardStore } from "@/store/modules/dashboard";
|
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||||
import type { LayoutConfig } from "@/types/dashboard";
|
import type { LayoutConfig } from "@/types/dashboard";
|
||||||
|
import { ConfigFieldTypes } from "@/views/dashboard/data";
|
||||||
|
|
||||||
export default function getDashboard(param?: { name: string; layer: string; entity: string }) {
|
export default function getDashboard(param?: { name?: string; layer: string; entity: string }, t?: string) {
|
||||||
|
const type = t || ConfigFieldTypes.NAME; // "NAME" or "ISDEFAULT"
|
||||||
const dashboardStore = useDashboardStore();
|
const dashboardStore = useDashboardStore();
|
||||||
const opt = param || dashboardStore.currentDashboard;
|
const opt = param || dashboardStore.currentDashboard;
|
||||||
const list = JSON.parse(sessionStorage.getItem("dashboards") || "[]");
|
const list = JSON.parse(sessionStorage.getItem("dashboards") || "[]");
|
||||||
const dashboard = list.find(
|
let dashboard: Recordable;
|
||||||
|
if (type === ConfigFieldTypes.NAME) {
|
||||||
|
dashboard = list.find(
|
||||||
(d: { name: string; layer: string; entity: string }) =>
|
(d: { name: string; layer: string; entity: string }) =>
|
||||||
d.name === opt.name && d.entity === opt.entity && d.layer === opt.layer,
|
d.name === opt.name && d.entity === opt.entity && d.layer === opt.layer,
|
||||||
);
|
);
|
||||||
|
} else {
|
||||||
|
dashboard = list.find(
|
||||||
|
(d: { name: string; layer: string; entity: string; isDefault: boolean }) =>
|
||||||
|
d.isDefault && d.entity === opt.entity && d.layer === opt.layer,
|
||||||
|
);
|
||||||
|
}
|
||||||
const all = dashboardStore.layout;
|
const all = dashboardStore.layout;
|
||||||
const widgets: LayoutConfig[] = [];
|
const widgets: LayoutConfig[] = [];
|
||||||
for (const item of all) {
|
for (const item of all) {
|
||||||
@@ -52,6 +62,9 @@ export default function getDashboard(param?: { name: string; layer: string; enti
|
|||||||
filters,
|
filters,
|
||||||
};
|
};
|
||||||
dashboardStore.setWidget(item);
|
dashboardStore.setWidget(item);
|
||||||
|
if (widget.id === sourceId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
const targetTabIndex = (widget.id || "").split("-");
|
const targetTabIndex = (widget.id || "").split("-");
|
||||||
const sourceTabindex = (sourceId || "").split("-") || [];
|
const sourceTabindex = (sourceId || "").split("-") || [];
|
||||||
let container: Nullable<Element>;
|
let container: Nullable<Element>;
|
||||||
|
@@ -14,7 +14,7 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
import { RespFields } from "./data";
|
import { RespFields, MaximumEntities } from "./data";
|
||||||
import { EntityType, ExpressionResultType } from "@/views/dashboard/data";
|
import { EntityType, ExpressionResultType } from "@/views/dashboard/data";
|
||||||
import { ElMessage } from "element-plus";
|
import { ElMessage } from "element-plus";
|
||||||
import { useDashboardStore } from "@/store/modules/dashboard";
|
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||||
@@ -24,31 +24,27 @@ import type { MetricConfigOpt } from "@/types/dashboard";
|
|||||||
import type { Instance, Endpoint, Service } from "@/types/selector";
|
import type { Instance, Endpoint, Service } from "@/types/selector";
|
||||||
import type { Node, Call } from "@/types/topology";
|
import type { Node, Call } from "@/types/topology";
|
||||||
|
|
||||||
export async function useExpressionsQueryProcessor(config: Indexable) {
|
export async function useDashboardQueryProcessor(configList: Indexable[]) {
|
||||||
function expressionsGraphqlPods() {
|
function expressionsGraphql(config: Indexable, idx: number) {
|
||||||
if (!(config.metrics && config.metrics[0])) {
|
if (!(config.metrics && config.metrics[0])) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const appStore = useAppStoreWithOut();
|
|
||||||
const dashboardStore = useDashboardStore();
|
const dashboardStore = useDashboardStore();
|
||||||
const selectorStore = useSelectorStore();
|
const selectorStore = useSelectorStore();
|
||||||
|
|
||||||
if (!selectorStore.currentService && dashboardStore.entity !== "All") {
|
if (!selectorStore.currentService && dashboardStore.entity !== "All") {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const conditions: Recordable = {
|
const conditions: Recordable = {};
|
||||||
duration: appStore.durationTime,
|
const variables: string[] = [];
|
||||||
};
|
|
||||||
const variables: string[] = [`$duration: Duration!`];
|
|
||||||
const isRelation = ["ServiceRelation", "ServiceInstanceRelation", "EndpointRelation", "ProcessRelation"].includes(
|
const isRelation = ["ServiceRelation", "ServiceInstanceRelation", "EndpointRelation", "ProcessRelation"].includes(
|
||||||
dashboardStore.entity,
|
dashboardStore.entity,
|
||||||
);
|
);
|
||||||
if (isRelation && !selectorStore.currentDestService) {
|
if (isRelation && !selectorStore.currentDestService) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const fragment = config.metrics.map((name: string, index: number) => {
|
if (idx === 0) {
|
||||||
variables.push(`$expression${index}: String!`, `$entity${index}: Entity!`);
|
variables.push(`$entity: Entity!`);
|
||||||
conditions[`expression${index}`] = name;
|
|
||||||
const entity = {
|
const entity = {
|
||||||
serviceName: dashboardStore.entity === "All" ? undefined : selectorStore.currentService.value,
|
serviceName: dashboardStore.entity === "All" ? undefined : selectorStore.currentService.value,
|
||||||
normal: dashboardStore.entity === "All" ? undefined : selectorStore.currentService.normal,
|
normal: dashboardStore.entity === "All" ? undefined : selectorStore.currentService.normal,
|
||||||
@@ -76,19 +72,21 @@ export async function useExpressionsQueryProcessor(config: Indexable) {
|
|||||||
? selectorStore.currentDestProcess && selectorStore.currentDestProcess.value
|
? selectorStore.currentDestProcess && selectorStore.currentDestProcess.value
|
||||||
: undefined,
|
: undefined,
|
||||||
};
|
};
|
||||||
conditions[`entity${index}`] = entity;
|
conditions[`entity`] = entity;
|
||||||
|
}
|
||||||
|
const fragment = config.metrics.map((name: string, index: number) => {
|
||||||
|
variables.push(`$expression${idx}${index}: String!`);
|
||||||
|
conditions[`expression${idx}${index}`] = name;
|
||||||
|
|
||||||
return `expression${index}: execExpression(expression: $expression${index}, entity: $entity${index}, duration: $duration)${RespFields.execExpression}`;
|
return `expression${idx}${index}: execExpression(expression: $expression${idx}${index}, entity: $entity, duration: $duration)${RespFields.execExpression}`;
|
||||||
});
|
});
|
||||||
const queryStr = `query queryData(${variables}) {${fragment}}`;
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
queryStr,
|
variables,
|
||||||
|
fragment,
|
||||||
conditions,
|
conditions,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
function expressionsSource(config: Indexable, resp: { errors: string; data: Indexable | any }) {
|
||||||
function expressionsSource(resp: { errors: string; data: Indexable }) {
|
|
||||||
if (resp.errors) {
|
if (resp.errors) {
|
||||||
ElMessage.error(resp.errors);
|
ElMessage.error(resp.errors);
|
||||||
return { source: {}, tips: [], typesOfMQE: [] };
|
return { source: {}, tips: [], typesOfMQE: [] };
|
||||||
@@ -97,6 +95,10 @@ export async function useExpressionsQueryProcessor(config: Indexable) {
|
|||||||
ElMessage.error("The query is wrong");
|
ElMessage.error("The query is wrong");
|
||||||
return { source: {}, tips: [], typesOfMQE: [] };
|
return { source: {}, tips: [], typesOfMQE: [] };
|
||||||
}
|
}
|
||||||
|
if (resp.data.error) {
|
||||||
|
ElMessage.error(resp.data.error);
|
||||||
|
return { source: {}, tips: [], typesOfMQE: [] };
|
||||||
|
}
|
||||||
const tips: string[] = [];
|
const tips: string[] = [];
|
||||||
const source: { [key: string]: unknown } = {};
|
const source: { [key: string]: unknown } = {};
|
||||||
const keys = Object.keys(resp.data);
|
const keys = Object.keys(resp.data);
|
||||||
@@ -112,27 +114,19 @@ export async function useExpressionsQueryProcessor(config: Indexable) {
|
|||||||
tips.push(obj.error);
|
tips.push(obj.error);
|
||||||
typesOfMQE.push(type);
|
typesOfMQE.push(type);
|
||||||
if (!obj.error) {
|
if (!obj.error) {
|
||||||
if (type === ExpressionResultType.TIME_SERIES_VALUES) {
|
if ([ExpressionResultType.SINGLE_VALUE, ExpressionResultType.TIME_SERIES_VALUES].includes(type)) {
|
||||||
if (results.length === 1) {
|
|
||||||
const label = results[0].metric && results[0].metric.labels[0] && results[0].metric.labels[0].value;
|
|
||||||
source[c.label || label || name] = results[0].values.map((d: { value: unknown }) => d.value) || [];
|
|
||||||
} else {
|
|
||||||
const labels = (c.label || "").split(",").map((item: string) => item.replace(/^\s*|\s*$/g, ""));
|
|
||||||
for (const item of results) {
|
for (const item of results) {
|
||||||
|
const label =
|
||||||
|
item.metric &&
|
||||||
|
item.metric.labels.map((d: { key: string; value: string }) => `${d.key}=${d.value}`).join(",");
|
||||||
const values = item.values.map((d: { value: unknown }) => d.value) || [];
|
const values = item.values.map((d: { value: unknown }) => d.value) || [];
|
||||||
const index = item.metric.labels[0].value;
|
if (results.length === 1) {
|
||||||
const indexNum = labels.findIndex((_, i: number) => i === Number(index));
|
source[label || c.label || name] = values;
|
||||||
if (labels[indexNum] && indexNum > -1) {
|
|
||||||
source[labels[indexNum]] = values;
|
|
||||||
} else {
|
} else {
|
||||||
source[index] = values;
|
source[label] = values;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (type === ExpressionResultType.SINGLE_VALUE) {
|
|
||||||
source[c.label || name] = (results[0].values[0] || {}).value;
|
|
||||||
}
|
|
||||||
if (([ExpressionResultType.RECORD_LIST, ExpressionResultType.SORTED_LIST] as string[]).includes(type)) {
|
if (([ExpressionResultType.RECORD_LIST, ExpressionResultType.SORTED_LIST] as string[]).includes(type)) {
|
||||||
source[name] = results[0].values;
|
source[name] = results[0].values;
|
||||||
}
|
}
|
||||||
@@ -141,24 +135,76 @@ export async function useExpressionsQueryProcessor(config: Indexable) {
|
|||||||
|
|
||||||
return { source, tips, typesOfMQE };
|
return { source, tips, typesOfMQE };
|
||||||
}
|
}
|
||||||
const params = await expressionsGraphqlPods();
|
async function fetchMetrics(configArr: any) {
|
||||||
if (!params) {
|
const appStore = useAppStoreWithOut();
|
||||||
return { source: {}, tips: [], typesOfMQE: [] };
|
const variables: string[] = [`$duration: Duration!`];
|
||||||
|
let fragments = "";
|
||||||
|
let conditions: Recordable = {
|
||||||
|
duration: appStore.durationTime,
|
||||||
|
};
|
||||||
|
for (let i = 0; i < configArr.length; i++) {
|
||||||
|
const params = await expressionsGraphql(configArr[i], i);
|
||||||
|
if (params) {
|
||||||
|
fragments += params?.fragment;
|
||||||
|
conditions = { ...conditions, ...params.conditions };
|
||||||
|
variables.push(...params.variables);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if (!fragments) {
|
||||||
|
return { 0: { source: {}, tips: [], typesOfMQE: [] } };
|
||||||
|
}
|
||||||
|
const queryStr = `query queryData(${variables}) {${fragments}}`;
|
||||||
const dashboardStore = useDashboardStore();
|
const dashboardStore = useDashboardStore();
|
||||||
const json = await dashboardStore.fetchMetricValue(params);
|
const json = await dashboardStore.fetchMetricValue({
|
||||||
|
queryStr,
|
||||||
|
conditions,
|
||||||
|
});
|
||||||
if (json.errors) {
|
if (json.errors) {
|
||||||
ElMessage.error(json.errors);
|
ElMessage.error(json.errors);
|
||||||
return { source: {}, tips: [], typesOfMQE: [] };
|
return { 0: { source: {}, tips: [], typesOfMQE: [] } };
|
||||||
}
|
}
|
||||||
const data = expressionsSource(json);
|
try {
|
||||||
|
const pageData: Recordable = {};
|
||||||
|
|
||||||
return data;
|
for (let i = 0; i < configArr.length; i++) {
|
||||||
|
const resp: any = {};
|
||||||
|
for (let m = 0; m < configArr[i].metrics.length; m++) {
|
||||||
|
resp[`expression${i}${m}`] = json.data[`expression${i}${m}`];
|
||||||
|
}
|
||||||
|
const data = expressionsSource(configArr[i], { ...json, data: resp });
|
||||||
|
const id = configArr[i].id;
|
||||||
|
pageData[id] = data;
|
||||||
|
}
|
||||||
|
return pageData;
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
return { 0: { source: {}, tips: [], typesOfMQE: [] } };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function chunkArray(array: any[], chunkSize: number) {
|
||||||
|
const result = [];
|
||||||
|
for (let i = 0; i < array.length; i += chunkSize) {
|
||||||
|
result.push(array.slice(i, i + chunkSize));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
const partArr = chunkArray(configList, 6);
|
||||||
|
const promiseArr = partArr.map((d: Array<Indexable>) => fetchMetrics(d));
|
||||||
|
const responseList = await Promise.all(promiseArr);
|
||||||
|
let resp = {};
|
||||||
|
for (const item of responseList) {
|
||||||
|
resp = {
|
||||||
|
...resp,
|
||||||
|
...item,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function useExpressionsQueryPodsMetrics(
|
export async function useExpressionsQueryPodsMetrics(
|
||||||
pods: Array<(Instance | Endpoint | Service) & Indexable>,
|
allPods: Array<(Instance | Endpoint | Service) & Indexable>,
|
||||||
config: {
|
config: {
|
||||||
expressions: string[];
|
expressions: string[];
|
||||||
subExpressions: string[];
|
subExpressions: string[];
|
||||||
@@ -166,7 +212,7 @@ export async function useExpressionsQueryPodsMetrics(
|
|||||||
},
|
},
|
||||||
scope: string,
|
scope: string,
|
||||||
) {
|
) {
|
||||||
function expressionsGraphqlPods() {
|
function expressionsGraphqlPods(pods: Array<(Instance | Endpoint | Service) & Indexable>) {
|
||||||
const metrics: string[] = [];
|
const metrics: string[] = [];
|
||||||
const subMetrics: string[] = [];
|
const subMetrics: string[] = [];
|
||||||
config.expressions = config.expressions || [];
|
config.expressions = config.expressions || [];
|
||||||
@@ -198,18 +244,22 @@ export async function useExpressionsQueryPodsMetrics(
|
|||||||
variables.push(`$entity${index}: Entity!`);
|
variables.push(`$entity${index}: Entity!`);
|
||||||
conditions[`entity${index}`] = entity;
|
conditions[`entity${index}`] = entity;
|
||||||
const f = metrics.map((name: string, idx: number) => {
|
const f = metrics.map((name: string, idx: number) => {
|
||||||
variables.push(`$expression${index}${idx}: String!`);
|
if (index === 0) {
|
||||||
conditions[`expression${index}${idx}`] = name;
|
variables.push(`$expression${idx}: String!`);
|
||||||
|
conditions[`expression${idx}`] = name;
|
||||||
|
}
|
||||||
let str = "";
|
let str = "";
|
||||||
if (config.subExpressions[idx]) {
|
if (config.subExpressions[idx]) {
|
||||||
variables.push(`$subExpression${index}${idx}: String!`);
|
if (index === 0) {
|
||||||
conditions[`subExpression${index}${idx}`] = config.subExpressions[idx];
|
variables.push(`$subExpression${idx}: String!`);
|
||||||
str = `subexpression${index}${idx}: execExpression(expression: $subExpression${index}${idx}, entity: $entity${index}, duration: $duration)${RespFields.execExpression}`;
|
conditions[`subExpression${idx}`] = config.subExpressions[idx];
|
||||||
|
}
|
||||||
|
str = `subexpression${index}${idx}: execExpression(expression: $subExpression${idx}, entity: $entity${index}, duration: $duration)${RespFields.execExpression}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
str +
|
str +
|
||||||
`expression${index}${idx}: execExpression(expression: $expression${index}${idx}, entity: $entity${index}, duration: $duration)${RespFields.execExpression}`
|
`expression${index}${idx}: execExpression(expression: $expression${idx}, entity: $entity${index}, duration: $duration)${RespFields.execExpression}`
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
return f;
|
return f;
|
||||||
@@ -220,7 +270,10 @@ export async function useExpressionsQueryPodsMetrics(
|
|||||||
return { queryStr, conditions };
|
return { queryStr, conditions };
|
||||||
}
|
}
|
||||||
|
|
||||||
function expressionsPodsSource(resp: { errors: string; data: Indexable }): Indexable {
|
function expressionsPodsSource(
|
||||||
|
resp: { errors: string; data: Indexable },
|
||||||
|
pods: Array<(Instance | Endpoint | Service) & Indexable>,
|
||||||
|
): Indexable {
|
||||||
if (resp.errors) {
|
if (resp.errors) {
|
||||||
ElMessage.error(resp.errors);
|
ElMessage.error(resp.errors);
|
||||||
return {};
|
return {};
|
||||||
@@ -301,19 +354,42 @@ export async function useExpressionsQueryPodsMetrics(
|
|||||||
|
|
||||||
return { data, names, subNames, metricConfigArr, metricTypesArr, expressionsTips, subExpressionsTips };
|
return { data, names, subNames, metricConfigArr, metricTypesArr, expressionsTips, subExpressionsTips };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function fetchPodsExpressionValues(pods: Array<(Instance | Endpoint | Service) & Indexable>) {
|
||||||
const dashboardStore = useDashboardStore();
|
const dashboardStore = useDashboardStore();
|
||||||
const params = await expressionsGraphqlPods();
|
const params = await expressionsGraphqlPods(pods);
|
||||||
|
|
||||||
const json = await dashboardStore.fetchMetricValue(params);
|
const json = await dashboardStore.fetchMetricValue(params);
|
||||||
|
|
||||||
if (json.errors) {
|
if (json.errors) {
|
||||||
ElMessage.error(json.errors);
|
ElMessage.error(json.errors);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
const expressionParams = expressionsPodsSource(json);
|
const expressionParams = expressionsPodsSource(json, pods);
|
||||||
|
|
||||||
return expressionParams;
|
return expressionParams;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const result = [];
|
||||||
|
for (let i = 0; i < allPods.length; i += MaximumEntities) {
|
||||||
|
result.push(allPods.slice(i, i + MaximumEntities));
|
||||||
|
}
|
||||||
|
const promiseArr = result.map((d: Array<(Instance | Endpoint | Service) & Indexable>) =>
|
||||||
|
fetchPodsExpressionValues(d),
|
||||||
|
);
|
||||||
|
const responseList = await Promise.all(promiseArr);
|
||||||
|
let resp: Indexable = { data: [], expressionsTips: [], subExpressionsTips: [] };
|
||||||
|
for (const item of responseList) {
|
||||||
|
resp = {
|
||||||
|
...item,
|
||||||
|
data: [...resp.data, ...item.data],
|
||||||
|
expressionsTips: [...resp.expressionsTips, ...item.expressionsTips],
|
||||||
|
subExpressionsTips: [...resp.subExpressionsTips, ...item.subExpressionsTips],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return resp;
|
||||||
|
}
|
||||||
|
|
||||||
export function useQueryTopologyExpressionsProcessor(metrics: string[], instances: (Call | Node)[]) {
|
export function useQueryTopologyExpressionsProcessor(metrics: string[], instances: (Call | Node)[]) {
|
||||||
const appStore = useAppStoreWithOut();
|
const appStore = useAppStoreWithOut();
|
||||||
const dashboardStore = useDashboardStore();
|
const dashboardStore = useDashboardStore();
|
||||||
@@ -330,10 +406,14 @@ export function useQueryTopologyExpressionsProcessor(metrics: string[], instance
|
|||||||
let serviceInstanceName;
|
let serviceInstanceName;
|
||||||
let destServiceInstanceName;
|
let destServiceInstanceName;
|
||||||
let destEndpointName;
|
let destEndpointName;
|
||||||
|
let normal = false;
|
||||||
|
let destNormal;
|
||||||
if (d.sourceObj && d.targetObj) {
|
if (d.sourceObj && d.targetObj) {
|
||||||
// instances = Calls
|
// instances = Calls
|
||||||
serviceName = d.sourceObj.serviceName || d.sourceObj.name;
|
serviceName = d.sourceObj.serviceName || d.sourceObj.name;
|
||||||
destServiceName = d.targetObj.serviceName || d.targetObj.name;
|
destServiceName = d.targetObj.serviceName || d.targetObj.name;
|
||||||
|
normal = d.sourceObj.normal || d.sourceObj.isReal || false;
|
||||||
|
destNormal = d.targetObj.normal || d.targetObj.isReal || false;
|
||||||
if (EntityType[4].value === dashboardStore.entity) {
|
if (EntityType[4].value === dashboardStore.entity) {
|
||||||
serviceInstanceName = d.sourceObj.name;
|
serviceInstanceName = d.sourceObj.name;
|
||||||
destServiceInstanceName = d.targetObj.name;
|
destServiceInstanceName = d.targetObj.name;
|
||||||
@@ -345,6 +425,10 @@ export function useQueryTopologyExpressionsProcessor(metrics: string[], instance
|
|||||||
} else {
|
} else {
|
||||||
// instances = Nodes
|
// instances = Nodes
|
||||||
serviceName = d.serviceName || d.name;
|
serviceName = d.serviceName || d.name;
|
||||||
|
normal = d.normal || d.isReal || false;
|
||||||
|
if (EntityType[3].value === dashboardStore.entity) {
|
||||||
|
serviceInstanceName = d.name;
|
||||||
|
}
|
||||||
if (EntityType[4].value === dashboardStore.entity) {
|
if (EntityType[4].value === dashboardStore.entity) {
|
||||||
serviceInstanceName = d.name;
|
serviceInstanceName = d.name;
|
||||||
}
|
}
|
||||||
@@ -354,11 +438,11 @@ export function useQueryTopologyExpressionsProcessor(metrics: string[], instance
|
|||||||
}
|
}
|
||||||
const entity = {
|
const entity = {
|
||||||
serviceName,
|
serviceName,
|
||||||
normal: true,
|
normal,
|
||||||
serviceInstanceName,
|
serviceInstanceName,
|
||||||
endpointName,
|
endpointName,
|
||||||
destServiceName,
|
destServiceName,
|
||||||
destNormal: destServiceName ? true : undefined,
|
destNormal: destServiceName ? destNormal : undefined,
|
||||||
destServiceInstanceName,
|
destServiceInstanceName,
|
||||||
destEndpointName,
|
destEndpointName,
|
||||||
};
|
};
|
||||||
|
@@ -1,41 +0,0 @@
|
|||||||
/**
|
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
||||||
* contributor license agreements. See the NOTICE file distributed with
|
|
||||||
* this work for additional information regarding copyright ownership.
|
|
||||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
|
||||||
* (the "License"); you may not use this file except in compliance with
|
|
||||||
* the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
import { MetricQueryTypes, Calculations } from "./data";
|
|
||||||
import { MetricModes } from "@/views/dashboard/data";
|
|
||||||
|
|
||||||
export function useListConfig(config: Indexable, index: number) {
|
|
||||||
if (config.metricModes === MetricModes.Expression) {
|
|
||||||
return {
|
|
||||||
isLinear: false,
|
|
||||||
isAvg: true,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
const i = Number(index);
|
|
||||||
const types = [Calculations.Average, Calculations.ApdexAvg, Calculations.PercentageAvg];
|
|
||||||
const calculation = config.metricConfig && config.metricConfig[i] && config.metricConfig[i].calculation;
|
|
||||||
const isLinear =
|
|
||||||
[MetricQueryTypes.ReadMetricsValues, MetricQueryTypes.ReadLabeledMetricsValues].includes(config.metricTypes[i]) &&
|
|
||||||
!types.includes(calculation);
|
|
||||||
const isAvg =
|
|
||||||
[MetricQueryTypes.ReadMetricsValues, MetricQueryTypes.ReadLabeledMetricsValues].includes(config.metricTypes[i]) &&
|
|
||||||
types.includes(calculation);
|
|
||||||
|
|
||||||
return {
|
|
||||||
isLinear,
|
|
||||||
isAvg,
|
|
||||||
};
|
|
||||||
}
|
|
@@ -1,437 +0,0 @@
|
|||||||
/**
|
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
||||||
* contributor license agreements. See the NOTICE file distributed with
|
|
||||||
* this work for additional information regarding copyright ownership.
|
|
||||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
|
||||||
* (the "License"); you may not use this file except in compliance with
|
|
||||||
* the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
import dayjs from "dayjs";
|
|
||||||
import { RespFields, MetricQueryTypes, Calculations } from "./data";
|
|
||||||
import { ElMessage } from "element-plus";
|
|
||||||
import { useDashboardStore } from "@/store/modules/dashboard";
|
|
||||||
import { useSelectorStore } from "@/store/modules/selectors";
|
|
||||||
import { useAppStoreWithOut } from "@/store/modules/app";
|
|
||||||
import type { Instance, Endpoint, Service } from "@/types/selector";
|
|
||||||
import type { MetricConfigOpt } from "@/types/dashboard";
|
|
||||||
|
|
||||||
export function useQueryProcessor(config: Indexable) {
|
|
||||||
if (!(config.metrics && config.metrics[0])) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!(config.metricTypes && config.metricTypes[0])) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const appStore = useAppStoreWithOut();
|
|
||||||
const dashboardStore = useDashboardStore();
|
|
||||||
const selectorStore = useSelectorStore();
|
|
||||||
|
|
||||||
if (!selectorStore.currentService && dashboardStore.entity !== "All") {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const conditions: Recordable = {
|
|
||||||
duration: appStore.durationTime,
|
|
||||||
};
|
|
||||||
const variables: string[] = [`$duration: Duration!`];
|
|
||||||
const isRelation = ["ServiceRelation", "ServiceInstanceRelation", "EndpointRelation", "ProcessRelation"].includes(
|
|
||||||
dashboardStore.entity,
|
|
||||||
);
|
|
||||||
if (isRelation && !selectorStore.currentDestService) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const fragment = config.metrics.map((name: string, index: number) => {
|
|
||||||
const metricType = config.metricTypes[index] || "";
|
|
||||||
const c = (config.metricConfig && config.metricConfig[index]) || {};
|
|
||||||
if ([MetricQueryTypes.ReadSampledRecords, MetricQueryTypes.SortMetrics].includes(metricType)) {
|
|
||||||
variables.push(`$condition${index}: TopNCondition!`);
|
|
||||||
conditions[`condition${index}`] = {
|
|
||||||
name,
|
|
||||||
parentService: ["All"].includes(dashboardStore.entity) ? null : selectorStore.currentService.value,
|
|
||||||
normal: selectorStore.currentService ? selectorStore.currentService.normal : true,
|
|
||||||
topN: Number(c.topN) || 10,
|
|
||||||
order: c.sortOrder || "DES",
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
const entity = {
|
|
||||||
serviceName: dashboardStore.entity === "All" ? undefined : selectorStore.currentService.value,
|
|
||||||
normal: dashboardStore.entity === "All" ? undefined : selectorStore.currentService.normal,
|
|
||||||
serviceInstanceName: ["ServiceInstance", "ServiceInstanceRelation", "ProcessRelation"].includes(
|
|
||||||
dashboardStore.entity,
|
|
||||||
)
|
|
||||||
? selectorStore.currentPod && selectorStore.currentPod.value
|
|
||||||
: undefined,
|
|
||||||
endpointName: dashboardStore.entity.includes("Endpoint")
|
|
||||||
? selectorStore.currentPod && selectorStore.currentPod.value
|
|
||||||
: undefined,
|
|
||||||
processName: dashboardStore.entity.includes("Process")
|
|
||||||
? selectorStore.currentProcess && selectorStore.currentProcess.value
|
|
||||||
: undefined,
|
|
||||||
destNormal: isRelation ? selectorStore.currentDestService.normal : undefined,
|
|
||||||
destServiceName: isRelation ? selectorStore.currentDestService.value : undefined,
|
|
||||||
destServiceInstanceName: ["ServiceInstanceRelation", "ProcessRelation"].includes(dashboardStore.entity)
|
|
||||||
? selectorStore.currentDestPod && selectorStore.currentDestPod.value
|
|
||||||
: undefined,
|
|
||||||
destEndpointName:
|
|
||||||
dashboardStore.entity === "EndpointRelation"
|
|
||||||
? selectorStore.currentDestPod && selectorStore.currentDestPod.value
|
|
||||||
: undefined,
|
|
||||||
destProcessName: dashboardStore.entity.includes("ProcessRelation")
|
|
||||||
? selectorStore.currentDestProcess && selectorStore.currentDestProcess.value
|
|
||||||
: undefined,
|
|
||||||
};
|
|
||||||
if ([MetricQueryTypes.ReadRecords].includes(metricType)) {
|
|
||||||
variables.push(`$condition${index}: RecordCondition!`);
|
|
||||||
conditions[`condition${index}`] = {
|
|
||||||
name,
|
|
||||||
parentEntity: entity,
|
|
||||||
topN: Number(c.topN) || 10,
|
|
||||||
order: c.sortOrder || "DES",
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
if (metricType === MetricQueryTypes.ReadLabeledMetricsValues) {
|
|
||||||
const labels = (c.labelsIndex || "").split(",").map((item: string) => item.replace(/^\s*|\s*$/g, ""));
|
|
||||||
variables.push(`$labels${index}: [String!]!`);
|
|
||||||
conditions[`labels${index}`] = labels;
|
|
||||||
}
|
|
||||||
variables.push(`$condition${index}: MetricsCondition!`);
|
|
||||||
conditions[`condition${index}`] = {
|
|
||||||
name,
|
|
||||||
entity,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (metricType === MetricQueryTypes.ReadLabeledMetricsValues) {
|
|
||||||
return `${name}${index}: ${metricType}(condition: $condition${index}, labels: $labels${index}, duration: $duration)${RespFields[metricType]}`;
|
|
||||||
}
|
|
||||||
const t = metricType === MetricQueryTypes.ReadMetricsValue ? MetricQueryTypes.ReadNullableMetricsValue : metricType;
|
|
||||||
|
|
||||||
return `${name}${index}: ${t}(condition: $condition${index}, duration: $duration)${RespFields[t]}`;
|
|
||||||
});
|
|
||||||
const queryStr = `query queryData(${variables}) {${fragment}}`;
|
|
||||||
|
|
||||||
return {
|
|
||||||
queryStr,
|
|
||||||
conditions,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
export function useSourceProcessor(
|
|
||||||
resp: { errors: string; data: Indexable },
|
|
||||||
config: {
|
|
||||||
metrics: string[];
|
|
||||||
metricTypes: string[];
|
|
||||||
metricConfig: MetricConfigOpt[];
|
|
||||||
},
|
|
||||||
) {
|
|
||||||
if (resp.errors) {
|
|
||||||
ElMessage.error(resp.errors);
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
if (!resp.data) {
|
|
||||||
ElMessage.error("The query is wrong");
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
const source: { [key: string]: unknown } = {};
|
|
||||||
const keys = Object.keys(resp.data);
|
|
||||||
|
|
||||||
config.metricTypes.forEach((type: string, index) => {
|
|
||||||
const m = config.metrics[index];
|
|
||||||
const c = (config.metricConfig && config.metricConfig[index]) || {};
|
|
||||||
|
|
||||||
if (type === MetricQueryTypes.ReadMetricsValues) {
|
|
||||||
source[c.label || m] = (resp.data[keys[index]] && calculateExp(resp.data[keys[index]].values.values, c)) || [];
|
|
||||||
}
|
|
||||||
if (type === MetricQueryTypes.ReadLabeledMetricsValues) {
|
|
||||||
const resVal = Object.values(resp.data)[0] || [];
|
|
||||||
const labels = (c.label || "").split(",").map((item: string) => item.replace(/^\s*|\s*$/g, ""));
|
|
||||||
const labelsIdx = (c.labelsIndex || "").split(",").map((item: string) => item.replace(/^\s*|\s*$/g, ""));
|
|
||||||
for (const item of resVal) {
|
|
||||||
const values = item.values.values.map((d: { value: number; isEmptyValue: boolean }) =>
|
|
||||||
d.isEmptyValue ? NaN : aggregation(Number(d.value), c),
|
|
||||||
);
|
|
||||||
const indexNum = labelsIdx.findIndex((d: string) => d === item.label);
|
|
||||||
if (labels[indexNum] && indexNum > -1) {
|
|
||||||
source[labels[indexNum]] = values;
|
|
||||||
} else {
|
|
||||||
source[item.label] = values;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (type === MetricQueryTypes.ReadMetricsValue) {
|
|
||||||
const v = Object.values(resp.data)[0] || {};
|
|
||||||
source[m] = v.isEmptyValue ? NaN : aggregation(Number(v.value), c);
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
(
|
|
||||||
[MetricQueryTypes.ReadRecords, MetricQueryTypes.ReadSampledRecords, MetricQueryTypes.SortMetrics] as string[]
|
|
||||||
).includes(type)
|
|
||||||
) {
|
|
||||||
source[m] = (Object.values(resp.data)[0] || []).map((d: { value: unknown; name: string }) => {
|
|
||||||
d.value = aggregation(Number(d.value), c);
|
|
||||||
|
|
||||||
return d;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (type === MetricQueryTypes.READHEATMAP) {
|
|
||||||
const resVal = Object.values(resp.data)[0] || {};
|
|
||||||
const nodes = [] as Indexable[];
|
|
||||||
if (!(resVal && resVal.values)) {
|
|
||||||
source[m] = { nodes: [] };
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
resVal.values.forEach((items: { values: number[] }, x: number) => {
|
|
||||||
const grids = items.values.map((val: number, y: number) => [x, y, val]);
|
|
||||||
|
|
||||||
nodes.push(...grids);
|
|
||||||
});
|
|
||||||
let buckets = [] as Indexable[];
|
|
||||||
if (resVal.buckets.length) {
|
|
||||||
buckets = [resVal.buckets[0].min, ...resVal.buckets.map((item: { min: string; max: string }) => item.max)];
|
|
||||||
}
|
|
||||||
|
|
||||||
source[m] = { nodes, buckets }; // nodes: number[][]
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return source;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function useQueryPodsMetrics(
|
|
||||||
pods: Array<(Instance | Endpoint | Service) & Indexable>,
|
|
||||||
config: {
|
|
||||||
metrics: string[];
|
|
||||||
metricTypes: string[];
|
|
||||||
metricConfig: MetricConfigOpt[];
|
|
||||||
},
|
|
||||||
scope: string,
|
|
||||||
) {
|
|
||||||
const metricTypes = (config.metricTypes || []).filter((m: string) => m);
|
|
||||||
if (!metricTypes.length) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const metrics = (config.metrics || []).filter((m: string) => m);
|
|
||||||
if (!metrics.length) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const appStore = useAppStoreWithOut();
|
|
||||||
const selectorStore = useSelectorStore();
|
|
||||||
const conditions: { [key: string]: unknown } = {
|
|
||||||
duration: appStore.durationTime,
|
|
||||||
};
|
|
||||||
const variables: string[] = [`$duration: Duration!`];
|
|
||||||
const currentService = selectorStore.currentService || {};
|
|
||||||
const fragmentList = pods.map((d: (Instance | Endpoint | Service) & Indexable, index: number) => {
|
|
||||||
const param = {
|
|
||||||
serviceName: scope === "Service" ? d.label : currentService.label,
|
|
||||||
serviceInstanceName: scope === "ServiceInstance" ? d.label : undefined,
|
|
||||||
endpointName: scope === "Endpoint" ? d.label : undefined,
|
|
||||||
normal: scope === "Service" ? d.normal : currentService.normal,
|
|
||||||
};
|
|
||||||
const f = metrics.map((name: string, idx: number) => {
|
|
||||||
const metricType = metricTypes[idx] || "";
|
|
||||||
variables.push(`$condition${index}${idx}: MetricsCondition!`);
|
|
||||||
conditions[`condition${index}${idx}`] = {
|
|
||||||
name,
|
|
||||||
entity: param,
|
|
||||||
};
|
|
||||||
let labelStr = "";
|
|
||||||
if (metricType === MetricQueryTypes.ReadLabeledMetricsValues) {
|
|
||||||
const c = config.metricConfig[idx] || {};
|
|
||||||
variables.push(`$labels${index}${idx}: [String!]!`);
|
|
||||||
labelStr = `labels: $labels${index}${idx}, `;
|
|
||||||
const labels = (c.labelsIndex || "").split(",").map((item: string) => item.replace(/^\s*|\s*$/g, ""));
|
|
||||||
conditions[`labels${index}${idx}`] = labels;
|
|
||||||
}
|
|
||||||
const t =
|
|
||||||
metricType === MetricQueryTypes.ReadMetricsValue ? MetricQueryTypes.ReadNullableMetricsValue : metricType;
|
|
||||||
return `${name}${index}${idx}: ${t}(condition: $condition${index}${idx}, ${labelStr}duration: $duration)${RespFields[t]}`;
|
|
||||||
});
|
|
||||||
return f;
|
|
||||||
});
|
|
||||||
const fragment = fragmentList.flat(1).join(" ");
|
|
||||||
const queryStr = `query queryData(${variables}) {${fragment}}`;
|
|
||||||
|
|
||||||
return { queryStr, conditions };
|
|
||||||
}
|
|
||||||
|
|
||||||
export function usePodsSource(
|
|
||||||
pods: Array<Instance | Endpoint>,
|
|
||||||
resp: { errors: string; data: Indexable },
|
|
||||||
config: {
|
|
||||||
metrics: string[];
|
|
||||||
metricTypes: string[];
|
|
||||||
metricConfig: MetricConfigOpt[];
|
|
||||||
},
|
|
||||||
): Indexable {
|
|
||||||
if (resp.errors) {
|
|
||||||
ElMessage.error(resp.errors);
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
const names: string[] = [];
|
|
||||||
const metricConfigArr: MetricConfigOpt[] = [];
|
|
||||||
const metricTypesArr: string[] = [];
|
|
||||||
const data = pods.map((d: any, idx: number) => {
|
|
||||||
config.metrics.map((name: string, index: number) => {
|
|
||||||
const c: any = (config.metricConfig && config.metricConfig[index]) || {};
|
|
||||||
const key = name + idx + index;
|
|
||||||
if (config.metricTypes[index] === MetricQueryTypes.ReadMetricsValue) {
|
|
||||||
const v = resp.data[key];
|
|
||||||
d[name] = v.isEmptyValue ? NaN : aggregation(v.value, c);
|
|
||||||
if (idx === 0) {
|
|
||||||
names.push(name);
|
|
||||||
metricConfigArr.push(c);
|
|
||||||
metricTypesArr.push(config.metricTypes[index]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (config.metricTypes[index] === MetricQueryTypes.ReadMetricsValues) {
|
|
||||||
d[name] = {};
|
|
||||||
if ([Calculations.Average, Calculations.ApdexAvg, Calculations.PercentageAvg].includes(c.calculation)) {
|
|
||||||
d[name]["avg"] = calculateExp(resp.data[key].values.values, c);
|
|
||||||
}
|
|
||||||
d[name]["values"] = resp.data[key].values.values.map((val: { value: number; isEmptyValue: boolean }) =>
|
|
||||||
val.isEmptyValue ? NaN : aggregation(val.value, c),
|
|
||||||
);
|
|
||||||
if (idx === 0) {
|
|
||||||
names.push(name);
|
|
||||||
metricConfigArr.push(c);
|
|
||||||
metricTypesArr.push(config.metricTypes[index]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (config.metricTypes[index] === MetricQueryTypes.ReadLabeledMetricsValues) {
|
|
||||||
const resVal = resp.data[key] || [];
|
|
||||||
const labels = (c.label || "").split(",").map((item: string) => item.replace(/^\s*|\s*$/g, ""));
|
|
||||||
const labelsIdx = (c.labelsIndex || "").split(",").map((item: string) => item.replace(/^\s*|\s*$/g, ""));
|
|
||||||
for (let i = 0; i < resVal.length; i++) {
|
|
||||||
const item = resVal[i];
|
|
||||||
const values = item.values.values.map((d: { value: number; isEmptyValue: boolean }) =>
|
|
||||||
d.isEmptyValue ? NaN : aggregation(Number(d.value), c),
|
|
||||||
);
|
|
||||||
const indexNum = labelsIdx.findIndex((d: string) => d === item.label);
|
|
||||||
let key = item.label;
|
|
||||||
if (labels[indexNum] && indexNum > -1) {
|
|
||||||
key = labels[indexNum];
|
|
||||||
}
|
|
||||||
if (!d[key]) {
|
|
||||||
d[key] = {};
|
|
||||||
}
|
|
||||||
if ([Calculations.Average, Calculations.ApdexAvg, Calculations.PercentageAvg].includes(c.calculation)) {
|
|
||||||
d[key]["avg"] = calculateExp(item.values.values, c);
|
|
||||||
}
|
|
||||||
d[key]["values"] = values;
|
|
||||||
if (idx === 0) {
|
|
||||||
names.push(key);
|
|
||||||
metricConfigArr.push({ ...c, index: i });
|
|
||||||
metricTypesArr.push(config.metricTypes[index]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return d;
|
|
||||||
});
|
|
||||||
return { data, names, metricConfigArr, metricTypesArr };
|
|
||||||
}
|
|
||||||
export function useQueryTopologyMetrics(metrics: string[], ids: string[]) {
|
|
||||||
const appStore = useAppStoreWithOut();
|
|
||||||
const conditions: { [key: string]: unknown } = {
|
|
||||||
duration: appStore.durationTime,
|
|
||||||
ids,
|
|
||||||
};
|
|
||||||
const variables: string[] = [`$duration: Duration!`, `$ids: [ID!]!`];
|
|
||||||
const fragmentList = metrics.map((d: string, index: number) => {
|
|
||||||
conditions[`m${index}`] = d;
|
|
||||||
variables.push(`$m${index}: String!`);
|
|
||||||
|
|
||||||
return `${d}: getValues(metric: {
|
|
||||||
name: $m${index}
|
|
||||||
ids: $ids
|
|
||||||
}, duration: $duration) {
|
|
||||||
values {
|
|
||||||
id
|
|
||||||
value
|
|
||||||
}
|
|
||||||
}`;
|
|
||||||
});
|
|
||||||
const queryStr = `query queryData(${variables}) {${fragmentList.join(" ")}}`;
|
|
||||||
|
|
||||||
return { queryStr, conditions };
|
|
||||||
}
|
|
||||||
export function calculateExp(
|
|
||||||
list: { value: number; isEmptyValue: boolean }[],
|
|
||||||
config: { calculation?: string },
|
|
||||||
): (number | string)[] {
|
|
||||||
const arr = list.filter((d: { value: number; isEmptyValue: boolean }) => !d.isEmptyValue);
|
|
||||||
const sum = arr.length ? arr.map((d: { value: number }) => Number(d.value)).reduce((a, b) => a + b) : 0;
|
|
||||||
let data: (number | string)[] = [];
|
|
||||||
switch (config.calculation) {
|
|
||||||
case Calculations.Average:
|
|
||||||
data = [(sum / arr.length).toFixed(2)];
|
|
||||||
break;
|
|
||||||
case Calculations.PercentageAvg:
|
|
||||||
data = [(sum / arr.length / 100).toFixed(2)];
|
|
||||||
break;
|
|
||||||
case Calculations.ApdexAvg:
|
|
||||||
data = [(sum / arr.length / 10000).toFixed(2)];
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
data = list.map((d: { value: number; isEmptyValue: boolean }) =>
|
|
||||||
d.isEmptyValue ? NaN : aggregation(d.value, config),
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function aggregation(val: number, config: { calculation?: string }): number | string {
|
|
||||||
let data: number | string = Number(val);
|
|
||||||
|
|
||||||
switch (config.calculation) {
|
|
||||||
case Calculations.Percentage:
|
|
||||||
data = (val / 100).toFixed(2);
|
|
||||||
break;
|
|
||||||
case Calculations.PercentageAvg:
|
|
||||||
data = (val / 100).toFixed(2);
|
|
||||||
break;
|
|
||||||
case Calculations.ByteToKB:
|
|
||||||
data = (val / 1024).toFixed(2);
|
|
||||||
break;
|
|
||||||
case Calculations.ByteToMB:
|
|
||||||
data = (val / 1024 / 1024).toFixed(2);
|
|
||||||
break;
|
|
||||||
case Calculations.ByteToGB:
|
|
||||||
data = (val / 1024 / 1024 / 1024).toFixed(2);
|
|
||||||
break;
|
|
||||||
case Calculations.Apdex:
|
|
||||||
data = (val / 10000).toFixed(2);
|
|
||||||
break;
|
|
||||||
case Calculations.ConvertSeconds:
|
|
||||||
data = dayjs(val * 1000).format("YYYY-MM-DD HH:mm:ss");
|
|
||||||
break;
|
|
||||||
case Calculations.ConvertMilliseconds:
|
|
||||||
data = dayjs(val).format("YYYY-MM-DD HH:mm:ss");
|
|
||||||
break;
|
|
||||||
case Calculations.MsToS:
|
|
||||||
data = (val / 1000).toFixed(2);
|
|
||||||
break;
|
|
||||||
case Calculations.SecondToDay:
|
|
||||||
data = (val / 86400).toFixed(2);
|
|
||||||
break;
|
|
||||||
case Calculations.NanosecondToMillisecond:
|
|
||||||
data = (val / 1000 / 1000).toFixed(2);
|
|
||||||
break;
|
|
||||||
case Calculations.ApdexAvg:
|
|
||||||
data = (val / 10000).toFixed(2);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
data;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
|
@@ -48,8 +48,14 @@ limitations under the License. -->
|
|||||||
@input="changeTimeRange"
|
@input="changeTimeRange"
|
||||||
/>
|
/>
|
||||||
<span> UTC{{ appStore.utcHour >= 0 ? "+" : "" }}{{ `${appStore.utcHour}:${appStore.utcMin}` }} </span>
|
<span> UTC{{ appStore.utcHour >= 0 ? "+" : "" }}{{ `${appStore.utcHour}:${appStore.utcMin}` }} </span>
|
||||||
<span class="ml-5">
|
<span class="ml-5" ref="themeSwitchRef">
|
||||||
<el-switch v-model="theme" :active-icon="Moon" :inactive-icon="Sunny" inline-prompt @change="changeTheme" />
|
<el-switch
|
||||||
|
v-model="theme"
|
||||||
|
:active-icon="Moon"
|
||||||
|
:inactive-icon="Sunny"
|
||||||
|
inline-prompt
|
||||||
|
@change="handleChangeTheme"
|
||||||
|
/>
|
||||||
</span>
|
</span>
|
||||||
<span title="refresh" class="ghost ml-5 cp" @click="handleReload">
|
<span title="refresh" class="ghost ml-5 cp" @click="handleReload">
|
||||||
<Icon iconName="retry" :loading="appStore.autoRefresh" class="middle" />
|
<Icon iconName="retry" :loading="appStore.autoRefresh" class="middle" />
|
||||||
@@ -67,18 +73,18 @@ limitations under the License. -->
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref, watch } from "vue";
|
import { Themes } from "@/constants/data";
|
||||||
import { useRoute } from "vue-router";
|
import router from "@/router";
|
||||||
import { useI18n } from "vue-i18n";
|
|
||||||
import timeFormat from "@/utils/timeFormat";
|
|
||||||
import { useAppStoreWithOut } from "@/store/modules/app";
|
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||||
import { useDashboardStore } from "@/store/modules/dashboard";
|
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||||
import { ElMessage } from "element-plus";
|
|
||||||
import { MetricCatalog } from "@/views/dashboard/data";
|
|
||||||
import type { DashboardItem } from "@/types/dashboard";
|
import type { DashboardItem } from "@/types/dashboard";
|
||||||
import router from "@/router";
|
import timeFormat from "@/utils/timeFormat";
|
||||||
|
import { MetricCatalog } from "@/views/dashboard/data";
|
||||||
import { ArrowRight, Moon, Sunny } from "@element-plus/icons-vue";
|
import { ArrowRight, Moon, Sunny } from "@element-plus/icons-vue";
|
||||||
import { Themes } from "@/constants/data";
|
import { ElMessage } from "element-plus";
|
||||||
|
import { ref, watch } from "vue";
|
||||||
|
import { useI18n } from "vue-i18n";
|
||||||
|
import { useRoute } from "vue-router";
|
||||||
|
|
||||||
/*global Indexable */
|
/*global Indexable */
|
||||||
const { t, te } = useI18n();
|
const { t, te } = useI18n();
|
||||||
@@ -89,11 +95,13 @@ limitations under the License. -->
|
|||||||
const timeRange = ref<number>(0);
|
const timeRange = ref<number>(0);
|
||||||
const pageTitle = ref<string>("");
|
const pageTitle = ref<string>("");
|
||||||
const theme = ref<boolean>(true);
|
const theme = ref<boolean>(true);
|
||||||
|
const themeSwitchRef = ref<HTMLElement>();
|
||||||
|
|
||||||
const savedTheme = window.localStorage.getItem("theme-is-dark");
|
const savedTheme = window.localStorage.getItem("theme-is-dark");
|
||||||
if (savedTheme === "false") {
|
if (savedTheme === "false") {
|
||||||
theme.value = false;
|
theme.value = false;
|
||||||
} else if (savedTheme === "") {
|
}
|
||||||
|
if (savedTheme === "") {
|
||||||
// read the theme preference from system setting if there is no user setting
|
// read the theme preference from system setting if there is no user setting
|
||||||
theme.value = window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches;
|
theme.value = window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches;
|
||||||
}
|
}
|
||||||
@@ -118,6 +126,35 @@ limitations under the License. -->
|
|||||||
window.localStorage.setItem("theme-is-dark", String(theme.value));
|
window.localStorage.setItem("theme-is-dark", String(theme.value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleChangeTheme() {
|
||||||
|
const x = themeSwitchRef.value?.offsetLeft ?? 0;
|
||||||
|
const y = themeSwitchRef.value?.offsetTop ?? 0;
|
||||||
|
const endRadius = Math.hypot(Math.max(x, innerWidth - x), Math.max(y, innerHeight - y));
|
||||||
|
// compatibility handling
|
||||||
|
if (!document.startViewTransition) {
|
||||||
|
changeTheme();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// api: https://developer.chrome.com/docs/web-platform/view-transitions
|
||||||
|
const transition = document.startViewTransition(() => {
|
||||||
|
changeTheme();
|
||||||
|
});
|
||||||
|
|
||||||
|
transition.ready.then(() => {
|
||||||
|
const clipPath = [`circle(0px at ${x}px ${y}px)`, `circle(${endRadius}px at ${x}px ${y}px)`];
|
||||||
|
document.documentElement.animate(
|
||||||
|
{
|
||||||
|
clipPath: !theme.value ? clipPath.reverse() : clipPath,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
duration: 500,
|
||||||
|
easing: "ease-in",
|
||||||
|
pseudoElement: !theme.value ? "::view-transition-old(root)" : "::view-transition-new(root)",
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function getName(list: any[]) {
|
function getName(list: any[]) {
|
||||||
return list.find((d: any) => d.selected) || {};
|
return list.find((d: any) => d.selected) || {};
|
||||||
}
|
}
|
||||||
|
@@ -94,14 +94,13 @@ const msg = {
|
|||||||
editTab: "Enable editing tab names",
|
editTab: "Enable editing tab names",
|
||||||
label: "Service Name",
|
label: "Service Name",
|
||||||
id: "Service ID",
|
id: "Service ID",
|
||||||
setRoot: "Set this to root",
|
setRoot: "Set Normal to Root",
|
||||||
setNormal: "Set this to normal",
|
setNormal: "Set Root to Normal",
|
||||||
export: "Export Dashboard Templates",
|
export: "Export Dashboard Templates",
|
||||||
import: "Import Dashboard Templates",
|
import: "Import Dashboard Templates",
|
||||||
yes: "Yes",
|
yes: "Yes",
|
||||||
no: "No",
|
no: "No",
|
||||||
tableHeaderCol1: "Name of the first column of the table",
|
tableHeaderCol2: "Name of the last column of the table",
|
||||||
tableHeaderCol2: "Name of the second column of the table",
|
|
||||||
showXAxis: "Show X Axis",
|
showXAxis: "Show X Axis",
|
||||||
showYAxis: "Show Y Axis",
|
showYAxis: "Show Y Axis",
|
||||||
nameError: "The dashboard name cannot be duplicate",
|
nameError: "The dashboard name cannot be duplicate",
|
||||||
@@ -285,7 +284,8 @@ const msg = {
|
|||||||
errorInfo: "Error Info",
|
errorInfo: "Error Info",
|
||||||
stack: "Stack",
|
stack: "Stack",
|
||||||
serviceVersion: "Service Version",
|
serviceVersion: "Service Version",
|
||||||
errorPage: "Error Page",
|
pagePath: "Page Path",
|
||||||
|
errorUrl: "Error Url",
|
||||||
category: "Category",
|
category: "Category",
|
||||||
grade: "Grade",
|
grade: "Grade",
|
||||||
relatedTraceLogs: "Related Logs",
|
relatedTraceLogs: "Related Logs",
|
||||||
@@ -301,7 +301,7 @@ const msg = {
|
|||||||
viewLogs: "View Logs",
|
viewLogs: "View Logs",
|
||||||
logsTagsTip: `Only tags defined in the core/default/searchableLogsTags are searchable.
|
logsTagsTip: `Only tags defined in the core/default/searchableLogsTags are searchable.
|
||||||
Check more details on the Configuration Vocabulary page`,
|
Check more details on the Configuration Vocabulary page`,
|
||||||
keywordsOfContentLogTips: "Current storage of SkyWalking OAP server does not support this.",
|
keywordsOfContentLogTips: "Current storage of SkyWalking OAP server does not support this",
|
||||||
setEvent: "Set Event",
|
setEvent: "Set Event",
|
||||||
viewAttributes: "View",
|
viewAttributes: "View",
|
||||||
attributes: "Attributes",
|
attributes: "Attributes",
|
||||||
@@ -356,7 +356,7 @@ const msg = {
|
|||||||
addKeywordsOfContent: "Please input a keyword of content",
|
addKeywordsOfContent: "Please input a keyword of content",
|
||||||
addExcludingKeywordsOfContent: "Please input a keyword of excluding content",
|
addExcludingKeywordsOfContent: "Please input a keyword of excluding content",
|
||||||
noticeTag: "Please press Enter after inputting a tag(key=value).",
|
noticeTag: "Please press Enter after inputting a tag(key=value).",
|
||||||
conditionNotice: "Notice: Please press Enter after inputting a key of content, exclude key of content(key=value).",
|
conditionNotice: "Notice: Please press Enter after inputting a key of content, exclude key of content(key=value)",
|
||||||
language: "Language",
|
language: "Language",
|
||||||
save: "Save",
|
save: "Save",
|
||||||
editStrategy: "Edit Policies",
|
editStrategy: "Edit Policies",
|
||||||
@@ -378,11 +378,13 @@ const msg = {
|
|||||||
menus: "Menus",
|
menus: "Menus",
|
||||||
saveReload: "Save and reload the page",
|
saveReload: "Save and reload the page",
|
||||||
document: "Documentation",
|
document: "Documentation",
|
||||||
metricMode: "Metric Mode",
|
|
||||||
addExpressions: "Add Expressions",
|
addExpressions: "Add Expressions",
|
||||||
expressions: "Expression",
|
expressions: "Expression",
|
||||||
unhealthyExpression: "Unhealthy Expression",
|
unhealthyExpression: "Unhealthy Expression",
|
||||||
traceDesc:
|
traceDesc:
|
||||||
"The trace segment serves as a representation of a trace portion executed within one single OS process, such as a JVM. It comprises a collection of spans, typically associated with and collected from a single request or execution context.",
|
"The trace segment serves as a representation of a trace portion executed within one single OS process, such as a JVM. It comprises a collection of spans, typically associated with and collected from a single request or execution context.",
|
||||||
|
tabExpressions: "Tab Expressions",
|
||||||
|
hierarchyNodeMetrics: "Metrics for Hierarchy Graph Node",
|
||||||
|
hierarchyNodeDashboard: "As dashboard for Hierarchy Graph Node",
|
||||||
};
|
};
|
||||||
export default msg;
|
export default msg;
|
||||||
|
@@ -101,8 +101,7 @@ const msg = {
|
|||||||
import: "Importar Plantilla Panel",
|
import: "Importar Plantilla Panel",
|
||||||
yes: "Sí",
|
yes: "Sí",
|
||||||
no: "No",
|
no: "No",
|
||||||
tableHeaderCol1: "Nombre de la primera columna de la tabla",
|
tableHeaderCol2: "Nombre de la Último columna de la tabla",
|
||||||
tableHeaderCol2: "Nombre de la segunda columna de la tabla",
|
|
||||||
showXAxis: "Mostrar Eje X",
|
showXAxis: "Mostrar Eje X",
|
||||||
showYAxis: "Mostrar Eje Y",
|
showYAxis: "Mostrar Eje Y",
|
||||||
nameError: "El nombre del panel no puede ser duplicado",
|
nameError: "El nombre del panel no puede ser duplicado",
|
||||||
@@ -284,7 +283,8 @@ const msg = {
|
|||||||
errorInfo: "Info Error",
|
errorInfo: "Info Error",
|
||||||
stack: "Pila",
|
stack: "Pila",
|
||||||
serviceVersion: "Versión Servicio",
|
serviceVersion: "Versión Servicio",
|
||||||
errorPage: "Página de Error",
|
pagePath: "Página de Error",
|
||||||
|
errorUrl: "Ruta de Error",
|
||||||
category: "Categoría",
|
category: "Categoría",
|
||||||
grade: "Grado",
|
grade: "Grado",
|
||||||
relatedTraceLogs: "Registro de Datos Relacionados",
|
relatedTraceLogs: "Registro de Datos Relacionados",
|
||||||
@@ -300,7 +300,7 @@ const msg = {
|
|||||||
viewLogs: "Ver Registro de Datos",
|
viewLogs: "Ver Registro de Datos",
|
||||||
logsTagsTip: `Solamente etiquetas definidas en core/default/searchableLogsTags pueden ser buscadas.
|
logsTagsTip: `Solamente etiquetas definidas en core/default/searchableLogsTags pueden ser buscadas.
|
||||||
Más información en la página de Vocabulario de Configuración`,
|
Más información en la página de Vocabulario de Configuración`,
|
||||||
keywordsOfContentLogTips: "El almacenamiento actual del servidor SkyWalking OAP no lo soporta.",
|
keywordsOfContentLogTips: "El almacenamiento actual del servidor SkyWalking OAP no lo soporta",
|
||||||
setEvent: "Establecer Evento",
|
setEvent: "Establecer Evento",
|
||||||
viewAttributes: "Ver",
|
viewAttributes: "Ver",
|
||||||
serviceEvents: "Eventos Servico",
|
serviceEvents: "Eventos Servico",
|
||||||
@@ -378,11 +378,13 @@ const msg = {
|
|||||||
menus: "Menus",
|
menus: "Menus",
|
||||||
saveReload: "Save and reload the page",
|
saveReload: "Save and reload the page",
|
||||||
document: "Documentation",
|
document: "Documentation",
|
||||||
metricMode: "Metric Mode",
|
|
||||||
addExpressions: "Add Expressions",
|
addExpressions: "Add Expressions",
|
||||||
expressions: "Expression",
|
expressions: "Expression",
|
||||||
unhealthyExpression: "Unhealthy Expression",
|
unhealthyExpression: "Unhealthy Expression",
|
||||||
traceDesc:
|
traceDesc:
|
||||||
"The trace segment serves as a representation of a trace portion executed within one single OS process, such as a JVM. It comprises a collection of spans, typically associated with and collected from a single request or execution context.",
|
"The trace segment serves as a representation of a trace portion executed within one single OS process, such as a JVM. It comprises a collection of spans, typically associated with and collected from a single request or execution context.",
|
||||||
|
tabExpressions: "Tab Expressions",
|
||||||
|
hierarchyNodeMetrics: "Metrics for Hierarchy Graph Node",
|
||||||
|
hierarchyNodeDashboard: "As dashboard for Hierarchy Graph Node",
|
||||||
};
|
};
|
||||||
export default msg;
|
export default msg;
|
||||||
|
@@ -30,6 +30,11 @@ const titles = {
|
|||||||
general_service_virtual_mq: "Virtual MQ",
|
general_service_virtual_mq: "Virtual MQ",
|
||||||
general_service_virtual_mq_desc:
|
general_service_virtual_mq_desc:
|
||||||
"Observe the virtual message queue servers which are conjectured by language agents through various plugins.",
|
"Observe the virtual message queue servers which are conjectured by language agents through various plugins.",
|
||||||
|
// Workflow Scheduler
|
||||||
|
workflow_scheduler: "Workflow Scheduler",
|
||||||
|
workflow_scheduler_desc: "Provide monitoring for workflow scheduling systems.",
|
||||||
|
workflow_scheduler_airflow: "Airflow",
|
||||||
|
workflow_scheduler_airflow_desc: "Observe tasks through telemetry data collected from Apache Airflow.",
|
||||||
// Service Mesh
|
// Service Mesh
|
||||||
service_mesh: "Service Mesh",
|
service_mesh: "Service Mesh",
|
||||||
service_mesh_desc:
|
service_mesh_desc:
|
||||||
@@ -108,6 +113,8 @@ const titles = {
|
|||||||
mq_kafka_desc: "Provide Kafka monitoring through OpenTelemetry's Prometheus Receiver.",
|
mq_kafka_desc: "Provide Kafka monitoring through OpenTelemetry's Prometheus Receiver.",
|
||||||
mq_pulsar: "Pulsar",
|
mq_pulsar: "Pulsar",
|
||||||
mq_pulsar_desc: "Provide Pulsar monitoring through OpenTelemetry's Prometheus Receiver.",
|
mq_pulsar_desc: "Provide Pulsar monitoring through OpenTelemetry's Prometheus Receiver.",
|
||||||
|
mq_rocketmq: "RocketMQ",
|
||||||
|
mq_rocketmq_desc: "Provide RocketMQ monitoring through OpenTelemetry's Prometheus Receiver.",
|
||||||
// self observability
|
// self observability
|
||||||
self_observability: "Self Observability",
|
self_observability: "Self Observability",
|
||||||
self_observability_desc:
|
self_observability_desc:
|
||||||
@@ -118,6 +125,14 @@ const titles = {
|
|||||||
self_observability_satellite: "Satellite",
|
self_observability_satellite: "Satellite",
|
||||||
self_observability_satellite_desc:
|
self_observability_satellite_desc:
|
||||||
"Satellite: an open-source agent designed for the cloud-native infrastructures, which provides a low-cost, high-efficient, and more secure way to collect telemetry data. It is the recommended load balancer for telemetry collecting.",
|
"Satellite: an open-source agent designed for the cloud-native infrastructures, which provides a low-cost, high-efficient, and more secure way to collect telemetry data. It is the recommended load balancer for telemetry collecting.",
|
||||||
|
self_observability_java_agent: "SkyWalking Java Agent",
|
||||||
|
self_observability_java_agent_desc:
|
||||||
|
"The self observability of SkyWalking Java Agent, which provides the abilities to measure the tracing performance and error statistics of plugins.",
|
||||||
|
cilium: "Cilium",
|
||||||
|
cilium_desc:
|
||||||
|
"Cilium is a CNI plugin for Kubernetes that provides eBPF-based networking, security, and load balancing.",
|
||||||
|
cilium_service: "Cilium Service",
|
||||||
|
cilium_service_desc: "Observe Service status and resources from Cilium Hubble.",
|
||||||
};
|
};
|
||||||
|
|
||||||
export default titles;
|
export default titles;
|
||||||
|
@@ -30,6 +30,12 @@ const titles = {
|
|||||||
general_service_virtual_mq: "MQ virtual",
|
general_service_virtual_mq: "MQ virtual",
|
||||||
general_service_virtual_mq_desc:
|
general_service_virtual_mq_desc:
|
||||||
"Observe the virtual message queue servers which are conjectured by language agents through various plugins.",
|
"Observe the virtual message queue servers which are conjectured by language agents through various plugins.",
|
||||||
|
// Workflow Scheduler
|
||||||
|
workflow_scheduler: "Flujo de trabajo",
|
||||||
|
workflow_scheduler_desc: "Proporcionar monitoreo para sistemas de programación de flujos de trabajo.",
|
||||||
|
workflow_scheduler_airflow: "Airflow",
|
||||||
|
workflow_scheduler_airflow_desc:
|
||||||
|
"Observando tareas a través de los datos de telemetría recopilados desde Apache Airflow.",
|
||||||
// Service Mesh
|
// Service Mesh
|
||||||
service_mesh: "Malla de Servicios",
|
service_mesh: "Malla de Servicios",
|
||||||
service_mesh_desc:
|
service_mesh_desc:
|
||||||
@@ -108,6 +114,8 @@ const titles = {
|
|||||||
mq_kafka_desc: "Provide Kafka monitoring through OpenTelemetry's Prometheus Receiver.",
|
mq_kafka_desc: "Provide Kafka monitoring through OpenTelemetry's Prometheus Receiver.",
|
||||||
mq_pulsar: "Pulsar",
|
mq_pulsar: "Pulsar",
|
||||||
mq_pulsar_desc: "Provide Pulsar monitoring through OpenTelemetry's Prometheus Receiver.",
|
mq_pulsar_desc: "Provide Pulsar monitoring through OpenTelemetry's Prometheus Receiver.",
|
||||||
|
mq_rocketmq: "RocketMQ",
|
||||||
|
mq_rocketmq_desc: "Provide RocketMQ monitoring through OpenTelemetry's Prometheus Receiver.",
|
||||||
// self observability
|
// self observability
|
||||||
self_observability: "Self Observability",
|
self_observability: "Self Observability",
|
||||||
self_observability_desc:
|
self_observability_desc:
|
||||||
@@ -118,6 +126,14 @@ const titles = {
|
|||||||
self_observability_satellite: "Satellite",
|
self_observability_satellite: "Satellite",
|
||||||
self_observability_satellite_desc:
|
self_observability_satellite_desc:
|
||||||
"Satellite: an open-source agent designed for the cloud-native infrastructures, which provides a low-cost, high-efficient, and more secure way to collect telemetry data. It is the recommended load balancer for telemetry collecting.",
|
"Satellite: an open-source agent designed for the cloud-native infrastructures, which provides a low-cost, high-efficient, and more secure way to collect telemetry data. It is the recommended load balancer for telemetry collecting.",
|
||||||
|
self_observability_java_agent: "SkyWalking Java Agent",
|
||||||
|
self_observability_java_agent_desc:
|
||||||
|
"The self observability of SkyWalking Java Agent, which provides the abilities to measure the tracing performance and error statistics of plugins.",
|
||||||
|
cilium: "Cilium",
|
||||||
|
cilium_desc:
|
||||||
|
"Cilium es un complemento CNI para Kubernetes que proporciona redes, seguridad y equilibrio de carga basados en eBPF.",
|
||||||
|
cilium_service: "Cilium Service",
|
||||||
|
cilium_service_desc: "Observe el estado del servicio y los recursos de Cilium Hubble.",
|
||||||
};
|
};
|
||||||
|
|
||||||
export default titles;
|
export default titles;
|
||||||
|
@@ -26,6 +26,11 @@ const titles = {
|
|||||||
general_service_virtual_cache_desc: "观察语言代理通过各种插件推测的虚拟缓存服务器。",
|
general_service_virtual_cache_desc: "观察语言代理通过各种插件推测的虚拟缓存服务器。",
|
||||||
general_service_virtual_mq: "虚拟消息队列",
|
general_service_virtual_mq: "虚拟消息队列",
|
||||||
general_service_virtual_mq_desc: "观察语言代理通过各种插件推测的虚拟消息队列服务器。",
|
general_service_virtual_mq_desc: "观察语言代理通过各种插件推测的虚拟消息队列服务器。",
|
||||||
|
// Workflow Scheduler
|
||||||
|
workflow_scheduler: "工作流调度",
|
||||||
|
workflow_scheduler_desc: "提供工作流调度系统监控。",
|
||||||
|
workflow_scheduler_airflow: "Airflow",
|
||||||
|
workflow_scheduler_airflow_desc: "通过从Apache Airflow收集的遥测数据观察任务。",
|
||||||
// Service Mesh
|
// Service Mesh
|
||||||
service_mesh: "服务网格",
|
service_mesh: "服务网格",
|
||||||
service_mesh_desc: "服务网格(Istio)通过分布式或微服务架构解决了开发人员和运营商面临的挑战。",
|
service_mesh_desc: "服务网格(Istio)通过分布式或微服务架构解决了开发人员和运营商面临的挑战。",
|
||||||
@@ -96,6 +101,8 @@ const titles = {
|
|||||||
mq_Kafka_desc: "通过OpenTelemetry的Prometheus接收器提供Kafka监控。",
|
mq_Kafka_desc: "通过OpenTelemetry的Prometheus接收器提供Kafka监控。",
|
||||||
mq_pulsar: "Pulsar",
|
mq_pulsar: "Pulsar",
|
||||||
mq_Pulsar_desc: "通过OpenTelemetry的Prometheus接收器提供Pulsar监控。",
|
mq_Pulsar_desc: "通过OpenTelemetry的Prometheus接收器提供Pulsar监控。",
|
||||||
|
mq_rocketmq: "RocketMQ",
|
||||||
|
mq_rocketmq_desc: "通过OpenTelemetry的Prometheus接收器提供RocketMQ监控。",
|
||||||
// self observability
|
// self observability
|
||||||
self_observability: "自监控",
|
self_observability: "自监控",
|
||||||
self_observability_desc: "自观察性为运行SkyWalking生态系统中的组件和服务器提供了可观察性。",
|
self_observability_desc: "自观察性为运行SkyWalking生态系统中的组件和服务器提供了可观察性。",
|
||||||
@@ -104,6 +111,12 @@ const titles = {
|
|||||||
self_observability_satellite: "Satellite",
|
self_observability_satellite: "Satellite",
|
||||||
self_observability_satellite_desc:
|
self_observability_satellite_desc:
|
||||||
"Satellite:为云原生基础设施设计的开源代理,提供了一种低成本、高效、更安全的遥测数据收集方式。它是遥测采集的推荐负载均衡器。",
|
"Satellite:为云原生基础设施设计的开源代理,提供了一种低成本、高效、更安全的遥测数据收集方式。它是遥测采集的推荐负载均衡器。",
|
||||||
|
self_observability_java_agent: "SkyWalking Java Agent",
|
||||||
|
self_observability_java_agent_desc: "SkyWalking Java Agent 自监控提供了对 agent 插件的性能追踪和错误统计。",
|
||||||
|
cilium: "Cilium",
|
||||||
|
cilium_desc: "Cilium是Kubernetes上的CNI插件,提供基于eBPF的网络、安全和负载均衡。",
|
||||||
|
cilium_service: "Cilium服务",
|
||||||
|
cilium_service_desc: "通过Cilium Hubble收集的遥测数据观察服务。",
|
||||||
};
|
};
|
||||||
|
|
||||||
export default titles;
|
export default titles;
|
||||||
|
@@ -99,8 +99,7 @@ const msg = {
|
|||||||
import: "导入仪表板模板",
|
import: "导入仪表板模板",
|
||||||
yes: "是",
|
yes: "是",
|
||||||
no: "否",
|
no: "否",
|
||||||
tableHeaderCol1: "表格的第一列的名称",
|
tableHeaderCol2: "表格的最后一列的名称",
|
||||||
tableHeaderCol2: "表格的第二列的名称",
|
|
||||||
showXAxis: "显示X轴",
|
showXAxis: "显示X轴",
|
||||||
showYAxis: "显示Y轴",
|
showYAxis: "显示Y轴",
|
||||||
nameError: "仪表板名称不能重复",
|
nameError: "仪表板名称不能重复",
|
||||||
@@ -282,7 +281,8 @@ const msg = {
|
|||||||
errorInfo: "错误信息",
|
errorInfo: "错误信息",
|
||||||
stack: "堆栈",
|
stack: "堆栈",
|
||||||
serviceVersion: "服务版本",
|
serviceVersion: "服务版本",
|
||||||
errorPage: "错误页面",
|
pagePath: "错误页面",
|
||||||
|
errorUrl: "错误路径",
|
||||||
category: "类别",
|
category: "类别",
|
||||||
grade: "等级",
|
grade: "等级",
|
||||||
relatedTraceLogs: "相关的日志",
|
relatedTraceLogs: "相关的日志",
|
||||||
@@ -376,11 +376,13 @@ const msg = {
|
|||||||
menusManagement: "菜单",
|
menusManagement: "菜单",
|
||||||
saveReload: "保存并重新加载页面",
|
saveReload: "保存并重新加载页面",
|
||||||
document: "文档",
|
document: "文档",
|
||||||
metricMode: "指标模式",
|
|
||||||
addExpressions: "添加表达式",
|
addExpressions: "添加表达式",
|
||||||
expressions: "表达式",
|
expressions: "表达式",
|
||||||
unhealthyExpression: "非健康表达式",
|
unhealthyExpression: "非健康表达式",
|
||||||
traceDesc:
|
traceDesc:
|
||||||
"Trace Segment代表在单一操作系统进程(例如JVM)中执行的追踪部分。它包含了一组跨度(spans),这些跨度通常与单一请求或执行上下文关联。",
|
"Trace Segment代表在单一操作系统进程(例如JVM)中执行的追踪部分。它包含了一组跨度(spans),这些跨度通常与单一请求或执行上下文关联。",
|
||||||
|
tabExpressions: "Tab表达式",
|
||||||
|
hierarchyNodeMetrics: "层次图节点的指标",
|
||||||
|
hierarchyNodeDashboard: "作为层次图节点的dashboard",
|
||||||
};
|
};
|
||||||
export default msg;
|
export default msg;
|
||||||
|
@@ -15,6 +15,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
import { createApp } from "vue";
|
import { createApp } from "vue";
|
||||||
|
import { ElLoading } from "element-plus";
|
||||||
import App from "./App.vue";
|
import App from "./App.vue";
|
||||||
import { store } from "./store";
|
import { store } from "./store";
|
||||||
import components from "@/components";
|
import components from "@/components";
|
||||||
@@ -23,6 +24,11 @@ import { useAppStoreWithOut } from "@/store/modules/app";
|
|||||||
import "./styles/index.ts";
|
import "./styles/index.ts";
|
||||||
import "virtual:svg-icons-register";
|
import "virtual:svg-icons-register";
|
||||||
|
|
||||||
|
const loading = ElLoading.service({
|
||||||
|
lock: true,
|
||||||
|
text: "Loading...",
|
||||||
|
background: "rgba(0, 0, 0, 0.8)",
|
||||||
|
});
|
||||||
const app = createApp(App);
|
const app = createApp(App);
|
||||||
const appStore = useAppStoreWithOut();
|
const appStore = useAppStoreWithOut();
|
||||||
|
|
||||||
@@ -34,7 +40,7 @@ mountApp();
|
|||||||
async function mountApp() {
|
async function mountApp() {
|
||||||
await appStore.getActivateMenus();
|
await appStore.getActivateMenus();
|
||||||
await appStore.queryOAPTimeInfo();
|
await appStore.queryOAPTimeInfo();
|
||||||
|
|
||||||
const router = await import("./router");
|
const router = await import("./router");
|
||||||
app.use(router.default).mount("#app");
|
app.use(router.default).mount("#app");
|
||||||
|
loading.close();
|
||||||
}
|
}
|
||||||
|
@@ -21,6 +21,7 @@ import { routesMarketplace } from "./marketplace";
|
|||||||
import { routesAlarm } from "./alarm";
|
import { routesAlarm } from "./alarm";
|
||||||
import routesLayers from "./layer";
|
import routesLayers from "./layer";
|
||||||
import { routesSettings } from "./settings";
|
import { routesSettings } from "./settings";
|
||||||
|
import { routesNotFound } from "./notFound";
|
||||||
|
|
||||||
const routes: RouteRecordRaw[] = [
|
const routes: RouteRecordRaw[] = [
|
||||||
...routesMarketplace,
|
...routesMarketplace,
|
||||||
@@ -28,6 +29,7 @@ const routes: RouteRecordRaw[] = [
|
|||||||
...routesAlarm,
|
...routesAlarm,
|
||||||
...routesDashboard,
|
...routesDashboard,
|
||||||
...routesSettings,
|
...routesSettings,
|
||||||
|
...routesNotFound,
|
||||||
];
|
];
|
||||||
|
|
||||||
const router = createRouter({
|
const router = createRouter({
|
||||||
@@ -47,7 +49,23 @@ router.beforeEach((to, from, next) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (to.path === "/") {
|
if (to.path === "/") {
|
||||||
const defaultPath = (routesLayers[0] && routesLayers[0].children[0].path) || "";
|
let defaultPath = "";
|
||||||
|
for (const route of routesLayers) {
|
||||||
|
for (const child of route.children) {
|
||||||
|
if (child.meta.activate) {
|
||||||
|
defaultPath = child.path;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (defaultPath) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!defaultPath) {
|
||||||
|
defaultPath = "/marketplace";
|
||||||
|
}
|
||||||
|
|
||||||
next({ path: defaultPath });
|
next({ path: defaultPath });
|
||||||
} else {
|
} else {
|
||||||
next();
|
next();
|
||||||
|
26
src/router/notFound.ts
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
/**
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
import type { RouteRecordRaw } from "vue-router";
|
||||||
|
import NotFound from "@/views/NotFound.vue";
|
||||||
|
|
||||||
|
export const routesNotFound: Array<RouteRecordRaw> = [
|
||||||
|
{
|
||||||
|
path: "/:pathMatch(.*)*",
|
||||||
|
name: "NotFound",
|
||||||
|
component: NotFound,
|
||||||
|
},
|
||||||
|
];
|
@@ -14,13 +14,15 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
import { WidgetType } from "@/views/dashboard/data";
|
||||||
|
|
||||||
export const NewControl = {
|
export const NewControl = {
|
||||||
x: 0,
|
x: 0,
|
||||||
y: 0,
|
y: 0,
|
||||||
w: 24,
|
w: 24,
|
||||||
h: 12,
|
h: 12,
|
||||||
i: "0",
|
i: "0",
|
||||||
type: "Widget",
|
type: WidgetType.Widget,
|
||||||
};
|
};
|
||||||
export const TextConfig = {
|
export const TextConfig = {
|
||||||
fontColor: "white",
|
fontColor: "white",
|
||||||
@@ -39,15 +41,15 @@ export const TimeRangeConfig = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const ControlsTypes = [
|
export const ControlsTypes = [
|
||||||
"Trace",
|
WidgetType.Trace,
|
||||||
"Profile",
|
WidgetType.Profile,
|
||||||
"Log",
|
WidgetType.Log,
|
||||||
"DemandLog",
|
WidgetType.DemandLog,
|
||||||
"Ebpf",
|
WidgetType.Ebpf,
|
||||||
"NetworkProfiling",
|
WidgetType.NetworkProfiling,
|
||||||
"ThirdPartyApp",
|
WidgetType.ThirdPartyApp,
|
||||||
"ContinuousProfiling",
|
WidgetType.ContinuousProfiling,
|
||||||
"TaskTimeline",
|
WidgetType.TaskTimeline,
|
||||||
];
|
];
|
||||||
export enum EBPFProfilingTriggerType {
|
export enum EBPFProfilingTriggerType {
|
||||||
FIXED_TIME = "FIXED_TIME",
|
FIXED_TIME = "FIXED_TIME",
|
||||||
|
@@ -19,6 +19,7 @@ import { store } from "@/store";
|
|||||||
import graphql from "@/graphql";
|
import graphql from "@/graphql";
|
||||||
import type { AxiosResponse } from "axios";
|
import type { AxiosResponse } from "axios";
|
||||||
import type { Alarm } from "@/types/alarm";
|
import type { Alarm } from "@/types/alarm";
|
||||||
|
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||||
|
|
||||||
interface AlarmState {
|
interface AlarmState {
|
||||||
loading: boolean;
|
loading: boolean;
|
||||||
@@ -35,7 +36,9 @@ export const alarmStore = defineStore({
|
|||||||
}),
|
}),
|
||||||
actions: {
|
actions: {
|
||||||
async getAlarms(params: Recordable) {
|
async getAlarms(params: Recordable) {
|
||||||
|
this.loading = true;
|
||||||
const res: AxiosResponse = await graphql.query("queryAlarms").params(params);
|
const res: AxiosResponse = await graphql.query("queryAlarms").params(params);
|
||||||
|
this.loading = false;
|
||||||
if (res.data.errors) {
|
if (res.data.errors) {
|
||||||
return res.data;
|
return res.data;
|
||||||
}
|
}
|
||||||
@@ -45,6 +48,20 @@ export const alarmStore = defineStore({
|
|||||||
}
|
}
|
||||||
return res.data;
|
return res.data;
|
||||||
},
|
},
|
||||||
|
async getAlarmTagKeys() {
|
||||||
|
const res: AxiosResponse = await graphql
|
||||||
|
.query("queryAlarmTagKeys")
|
||||||
|
.params({ duration: useAppStoreWithOut().durationTime });
|
||||||
|
|
||||||
|
return res.data;
|
||||||
|
},
|
||||||
|
async getAlarmTagValues(tagKey: string) {
|
||||||
|
const res: AxiosResponse = await graphql
|
||||||
|
.query("queryAlarmTagValues")
|
||||||
|
.params({ tagKey, duration: useAppStoreWithOut().durationTime });
|
||||||
|
|
||||||
|
return res.data;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@@ -24,8 +24,7 @@ import { useSelectorStore } from "@/store/modules/selectors";
|
|||||||
import { NewControl, TextConfig, TimeRangeConfig, ControlsTypes } from "../data";
|
import { NewControl, TextConfig, TimeRangeConfig, ControlsTypes } from "../data";
|
||||||
import type { AxiosResponse } from "axios";
|
import type { AxiosResponse } from "axios";
|
||||||
import { ElMessage } from "element-plus";
|
import { ElMessage } from "element-plus";
|
||||||
import { useI18n } from "vue-i18n";
|
import { EntityType, WidgetType } from "@/views/dashboard/data";
|
||||||
import { EntityType, MetricModes } from "@/views/dashboard/data";
|
|
||||||
interface DashboardState {
|
interface DashboardState {
|
||||||
showConfig: boolean;
|
showConfig: boolean;
|
||||||
layout: LayoutConfig[];
|
layout: LayoutConfig[];
|
||||||
@@ -78,7 +77,7 @@ export const dashboardStore = defineStore({
|
|||||||
setCurrentDashboard(item: DashboardItem) {
|
setCurrentDashboard(item: DashboardItem) {
|
||||||
this.currentDashboard = item;
|
this.currentDashboard = item;
|
||||||
},
|
},
|
||||||
addControl(type: string) {
|
addControl(type: WidgetType) {
|
||||||
const arr = this.layout.map((d: Recordable) => Number(d.i));
|
const arr = this.layout.map((d: Recordable) => Number(d.i));
|
||||||
let index = String(Math.max(...arr) + 1);
|
let index = String(Math.max(...arr) + 1);
|
||||||
if (!this.layout.length) {
|
if (!this.layout.length) {
|
||||||
@@ -89,14 +88,8 @@ export const dashboardStore = defineStore({
|
|||||||
i: index,
|
i: index,
|
||||||
id: index,
|
id: index,
|
||||||
type,
|
type,
|
||||||
metricTypes: [""],
|
|
||||||
metrics: [""],
|
|
||||||
};
|
};
|
||||||
|
if (type === WidgetType.Tab) {
|
||||||
if (type === "Widget") {
|
|
||||||
newItem.metricMode = MetricModes.Expression;
|
|
||||||
}
|
|
||||||
if (type === "Tab") {
|
|
||||||
newItem.h = 36;
|
newItem.h = 36;
|
||||||
newItem.activedTabIndex = 0;
|
newItem.activedTabIndex = 0;
|
||||||
newItem.children = [
|
newItem.children = [
|
||||||
@@ -110,7 +103,7 @@ export const dashboardStore = defineStore({
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
if (type === "Topology") {
|
if (type === WidgetType.Topology) {
|
||||||
newItem.h = 36;
|
newItem.h = 36;
|
||||||
newItem.graph = {
|
newItem.graph = {
|
||||||
showDepth: true,
|
showDepth: true,
|
||||||
@@ -120,11 +113,11 @@ export const dashboardStore = defineStore({
|
|||||||
if (ControlsTypes.includes(type)) {
|
if (ControlsTypes.includes(type)) {
|
||||||
newItem.h = 36;
|
newItem.h = 36;
|
||||||
}
|
}
|
||||||
if (type === "Text") {
|
if (type === WidgetType.Text) {
|
||||||
newItem.h = 6;
|
newItem.h = 6;
|
||||||
newItem.graph = TextConfig;
|
newItem.graph = TextConfig;
|
||||||
}
|
}
|
||||||
if (type === "TimeRange") {
|
if (type === WidgetType.TimeRange) {
|
||||||
newItem.w = 8;
|
newItem.w = 8;
|
||||||
newItem.h = 6;
|
newItem.h = 6;
|
||||||
newItem.graph = TimeRangeConfig;
|
newItem.graph = TimeRangeConfig;
|
||||||
@@ -149,7 +142,7 @@ export const dashboardStore = defineStore({
|
|||||||
};
|
};
|
||||||
this.layout[idx].children?.push(i);
|
this.layout[idx].children?.push(i);
|
||||||
},
|
},
|
||||||
addTabControls(type: string) {
|
addTabControls(type: WidgetType) {
|
||||||
const activedGridItem = this.activedGridItem.split("-")[0];
|
const activedGridItem = this.activedGridItem.split("-")[0];
|
||||||
const idx = this.layout.findIndex((d: LayoutConfig) => d.i === activedGridItem);
|
const idx = this.layout.findIndex((d: LayoutConfig) => d.i === activedGridItem);
|
||||||
if (idx < 0) {
|
if (idx < 0) {
|
||||||
@@ -168,27 +161,21 @@ export const dashboardStore = defineStore({
|
|||||||
i: index,
|
i: index,
|
||||||
id,
|
id,
|
||||||
type,
|
type,
|
||||||
metricTypes: [""],
|
|
||||||
metrics: [""],
|
|
||||||
};
|
};
|
||||||
if (type === "Widget") {
|
if (type === WidgetType.Topology) {
|
||||||
newItem.metricMode = MetricModes.Expression;
|
|
||||||
}
|
|
||||||
if (type === "Topology") {
|
|
||||||
newItem.h = 32;
|
newItem.h = 32;
|
||||||
newItem.graph = {
|
newItem.graph = {
|
||||||
showDepth: true,
|
showDepth: true,
|
||||||
};
|
};
|
||||||
newItem.metricMode = MetricModes.Expression;
|
|
||||||
}
|
}
|
||||||
if (ControlsTypes.includes(type)) {
|
if (ControlsTypes.includes(type)) {
|
||||||
newItem.h = 32;
|
newItem.h = 32;
|
||||||
}
|
}
|
||||||
if (type === "Text") {
|
if (type === WidgetType.Text) {
|
||||||
newItem.h = 6;
|
newItem.h = 6;
|
||||||
newItem.graph = TextConfig;
|
newItem.graph = TextConfig;
|
||||||
}
|
}
|
||||||
if (type === "TimeRange") {
|
if (type === WidgetType.TimeRange) {
|
||||||
newItem.w = 8;
|
newItem.w = 8;
|
||||||
newItem.h = 6;
|
newItem.h = 6;
|
||||||
newItem.graph = TextConfig;
|
newItem.graph = TextConfig;
|
||||||
@@ -292,7 +279,7 @@ export const dashboardStore = defineStore({
|
|||||||
},
|
},
|
||||||
setWidget(param: LayoutConfig) {
|
setWidget(param: LayoutConfig) {
|
||||||
for (let i = 0; i < this.layout.length; i++) {
|
for (let i = 0; i < this.layout.length; i++) {
|
||||||
if (this.layout[i].type === "Tab") {
|
if (this.layout[i].type === WidgetType.Tab) {
|
||||||
if ((this.layout[i].children || []).length) {
|
if ((this.layout[i].children || []).length) {
|
||||||
for (const child of this.layout[i].children || []) {
|
for (const child of this.layout[i].children || []) {
|
||||||
if (child.children && child.children.length) {
|
if (child.children && child.children.length) {
|
||||||
@@ -344,11 +331,9 @@ export const dashboardStore = defineStore({
|
|||||||
const key = [c.layer, c.entity, c.name].join("_");
|
const key = [c.layer, c.entity, c.name].join("_");
|
||||||
|
|
||||||
list.push({
|
list.push({
|
||||||
|
...c,
|
||||||
id: t.id,
|
id: t.id,
|
||||||
layer: c.layer,
|
children: undefined,
|
||||||
entity: c.entity,
|
|
||||||
name: c.name,
|
|
||||||
isRoot: c.isRoot,
|
|
||||||
});
|
});
|
||||||
sessionStorage.setItem(key, JSON.stringify({ id: t.id, configuration: c }));
|
sessionStorage.setItem(key, JSON.stringify({ id: t.id, configuration: c }));
|
||||||
}
|
}
|
||||||
@@ -429,8 +414,7 @@ export const dashboardStore = defineStore({
|
|||||||
d.layer === this.currentDashboard?.layer,
|
d.layer === this.currentDashboard?.layer,
|
||||||
);
|
);
|
||||||
if (index > -1) {
|
if (index > -1) {
|
||||||
const { t } = useI18n();
|
ElMessage.error("The dashboard name cannot be duplicate");
|
||||||
ElMessage.error(t("nameError"));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
res = await graphql.query("addNewTemplate").params({ setting: { configuration: JSON.stringify(c) } });
|
res = await graphql.query("addNewTemplate").params({ setting: { configuration: JSON.stringify(c) } });
|
||||||
|
@@ -16,14 +16,13 @@
|
|||||||
*/
|
*/
|
||||||
import { defineStore } from "pinia";
|
import { defineStore } from "pinia";
|
||||||
import { store } from "@/store";
|
import { store } from "@/store";
|
||||||
import type { Service } from "@/types/selector";
|
import type { Node, Call, HierarchyNode, ServiceHierarchy, InstanceHierarchy } from "@/types/topology";
|
||||||
import type { Node, Call } from "@/types/topology";
|
|
||||||
import graphql from "@/graphql";
|
import graphql from "@/graphql";
|
||||||
import { useSelectorStore } from "@/store/modules/selectors";
|
import { useSelectorStore } from "@/store/modules/selectors";
|
||||||
|
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||||
import { useAppStoreWithOut } from "@/store/modules/app";
|
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||||
import type { AxiosResponse } from "axios";
|
import type { AxiosResponse } from "axios";
|
||||||
import query from "@/graphql/fetch";
|
import query from "@/graphql/fetch";
|
||||||
import { useQueryTopologyMetrics } from "@/hooks/useMetricsProcessor";
|
|
||||||
import { useQueryTopologyExpressionsProcessor } from "@/hooks/useExpressionsProcessor";
|
import { useQueryTopologyExpressionsProcessor } from "@/hooks/useExpressionsProcessor";
|
||||||
import { ElMessage } from "element-plus";
|
import { ElMessage } from "element-plus";
|
||||||
|
|
||||||
@@ -35,9 +34,15 @@ interface TopologyState {
|
|||||||
call: Nullable<Call>;
|
call: Nullable<Call>;
|
||||||
calls: Call[];
|
calls: Call[];
|
||||||
nodes: Node[];
|
nodes: Node[];
|
||||||
|
hierarchyServiceCalls: Call[];
|
||||||
|
hierarchyServiceNodes: HierarchyNode[];
|
||||||
|
hierarchyInstanceCalls: Call[];
|
||||||
|
hierarchyInstanceNodes: HierarchyNode[];
|
||||||
nodeMetricValue: MetricVal;
|
nodeMetricValue: MetricVal;
|
||||||
linkServerMetrics: MetricVal;
|
linkServerMetrics: MetricVal;
|
||||||
linkClientMetrics: MetricVal;
|
linkClientMetrics: MetricVal;
|
||||||
|
hierarchyNodeMetrics: { [key: string]: MetricVal };
|
||||||
|
hierarchyInstanceNodeMetrics: { [key: string]: MetricVal };
|
||||||
}
|
}
|
||||||
|
|
||||||
export const topologyStore = defineStore({
|
export const topologyStore = defineStore({
|
||||||
@@ -45,11 +50,17 @@ export const topologyStore = defineStore({
|
|||||||
state: (): TopologyState => ({
|
state: (): TopologyState => ({
|
||||||
calls: [],
|
calls: [],
|
||||||
nodes: [],
|
nodes: [],
|
||||||
|
hierarchyServiceCalls: [],
|
||||||
|
hierarchyServiceNodes: [],
|
||||||
|
hierarchyInstanceCalls: [],
|
||||||
|
hierarchyInstanceNodes: [],
|
||||||
node: null,
|
node: null,
|
||||||
call: null,
|
call: null,
|
||||||
nodeMetricValue: {},
|
nodeMetricValue: {},
|
||||||
linkServerMetrics: {},
|
linkServerMetrics: {},
|
||||||
linkClientMetrics: {},
|
linkClientMetrics: {},
|
||||||
|
hierarchyNodeMetrics: {},
|
||||||
|
hierarchyInstanceNodeMetrics: {},
|
||||||
}),
|
}),
|
||||||
actions: {
|
actions: {
|
||||||
setNode(node: Node) {
|
setNode(node: Node) {
|
||||||
@@ -75,12 +86,9 @@ export const topologyStore = defineStore({
|
|||||||
},
|
},
|
||||||
setTopology(data: { nodes: Node[]; calls: Call[] }) {
|
setTopology(data: { nodes: Node[]; calls: Call[] }) {
|
||||||
const obj = {} as Recordable;
|
const obj = {} as Recordable;
|
||||||
const services = useSelectorStore().services;
|
|
||||||
const nodes = (data.nodes || []).reduce((prev: Node[], next: Node) => {
|
const nodes = (data.nodes || []).reduce((prev: Node[], next: Node) => {
|
||||||
if (!obj[next.id]) {
|
if (!obj[next.id]) {
|
||||||
obj[next.id] = true;
|
obj[next.id] = true;
|
||||||
const s = services.filter((d: Service) => d.id === next.id)[0] || {};
|
|
||||||
next.layer = s.layers ? s.layers[0] : null;
|
|
||||||
prev.push(next);
|
prev.push(next);
|
||||||
}
|
}
|
||||||
return prev;
|
return prev;
|
||||||
@@ -106,8 +114,107 @@ export const topologyStore = defineStore({
|
|||||||
this.calls = calls;
|
this.calls = calls;
|
||||||
this.nodes = nodes;
|
this.nodes = nodes;
|
||||||
},
|
},
|
||||||
setNodeMetricValue(m: MetricVal) {
|
setHierarchyInstanceTopology(data: InstanceHierarchy, levels: { layer: string; level: number }[]) {
|
||||||
this.nodeMetricValue = m;
|
const relations = data.relations || [];
|
||||||
|
const nodesMap = new Map();
|
||||||
|
const callList = [];
|
||||||
|
|
||||||
|
for (const relation of relations) {
|
||||||
|
const upperId = relation.upperInstance.id;
|
||||||
|
const lowerId = relation.lowerInstance.id;
|
||||||
|
const lowerKey = `${lowerId}-${relation.lowerInstance.layer}`;
|
||||||
|
const upperKey = `${upperId}-${relation.upperInstance.layer}`;
|
||||||
|
const lowerLevel = levels.find(
|
||||||
|
(l: { layer: string; level: number }) => l.layer === relation.lowerInstance.layer,
|
||||||
|
) || { level: undefined };
|
||||||
|
const upperLevel = levels.find(
|
||||||
|
(l: { layer: string; level: number }) => l.layer === relation.upperInstance.layer,
|
||||||
|
) || { level: undefined };
|
||||||
|
const lowerObj = {
|
||||||
|
...relation.lowerInstance,
|
||||||
|
key: lowerId,
|
||||||
|
id: lowerKey,
|
||||||
|
l: lowerLevel.level,
|
||||||
|
};
|
||||||
|
const upperObj = {
|
||||||
|
...relation.upperInstance,
|
||||||
|
key: upperId,
|
||||||
|
id: upperKey,
|
||||||
|
l: upperLevel.level,
|
||||||
|
};
|
||||||
|
if (!nodesMap.get(upperKey)) {
|
||||||
|
nodesMap.set(upperKey, upperObj);
|
||||||
|
}
|
||||||
|
if (!nodesMap.get(lowerKey)) {
|
||||||
|
nodesMap.set(lowerKey, lowerObj);
|
||||||
|
}
|
||||||
|
callList.push({
|
||||||
|
target: lowerKey,
|
||||||
|
source: upperKey,
|
||||||
|
id: `${lowerKey}->${upperKey}`,
|
||||||
|
sourceObj: upperObj,
|
||||||
|
targetObj: lowerObj,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
this.hierarchyInstanceCalls = callList;
|
||||||
|
this.hierarchyInstanceNodes = [];
|
||||||
|
for (const d of nodesMap.values()) {
|
||||||
|
this.hierarchyInstanceNodes.push(d);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
setHierarchyServiceTopology(data: ServiceHierarchy, levels: { layer: string; level: number }[]) {
|
||||||
|
const relations = data.relations || [];
|
||||||
|
const nodesMap = new Map();
|
||||||
|
const callList = [];
|
||||||
|
|
||||||
|
for (const relation of relations) {
|
||||||
|
const upperId = relation.upperService.id;
|
||||||
|
const lowerId = relation.lowerService.id;
|
||||||
|
const lowerKey = `${lowerId}-${relation.lowerService.layer}`;
|
||||||
|
const upperKey = `${upperId}-${relation.upperService.layer}`;
|
||||||
|
const lowerLevel = levels.find(
|
||||||
|
(l: { layer: string; level: number }) => l.layer === relation.lowerService.layer,
|
||||||
|
) || { level: undefined };
|
||||||
|
const upperLevel = levels.find(
|
||||||
|
(l: { layer: string; level: number }) => l.layer === relation.upperService.layer,
|
||||||
|
) || { level: undefined };
|
||||||
|
const lowerObj = {
|
||||||
|
...relation.lowerService,
|
||||||
|
key: lowerId,
|
||||||
|
id: lowerKey,
|
||||||
|
l: lowerLevel.level,
|
||||||
|
};
|
||||||
|
const upperObj = {
|
||||||
|
...relation.upperService,
|
||||||
|
key: upperId,
|
||||||
|
id: upperKey,
|
||||||
|
l: upperLevel.level,
|
||||||
|
};
|
||||||
|
if (!nodesMap.get(upperKey)) {
|
||||||
|
nodesMap.set(upperKey, upperObj);
|
||||||
|
}
|
||||||
|
if (!nodesMap.get(lowerKey)) {
|
||||||
|
nodesMap.set(lowerKey, lowerObj);
|
||||||
|
}
|
||||||
|
callList.push({
|
||||||
|
target: lowerKey,
|
||||||
|
source: upperKey,
|
||||||
|
id: `${lowerKey}->${upperKey}`,
|
||||||
|
sourceObj: upperObj,
|
||||||
|
targetObj: lowerObj,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
this.hierarchyServiceCalls = callList;
|
||||||
|
this.hierarchyServiceNodes = [];
|
||||||
|
for (const d of nodesMap.values()) {
|
||||||
|
this.hierarchyServiceNodes.push(d);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
setHierarchyNodeMetricValue(m: MetricVal, layer: string) {
|
||||||
|
this.hierarchyNodeMetrics[layer] = m;
|
||||||
|
},
|
||||||
|
setHierarchyInstanceNodeMetricValue(m: MetricVal, layer: string) {
|
||||||
|
this.hierarchyInstanceNodeMetrics[layer] = m;
|
||||||
},
|
},
|
||||||
setLinkServerMetrics(m: MetricVal) {
|
setLinkServerMetrics(m: MetricVal) {
|
||||||
this.linkServerMetrics = m;
|
this.linkServerMetrics = m;
|
||||||
@@ -115,12 +222,16 @@ export const topologyStore = defineStore({
|
|||||||
setLinkClientMetrics(m: MetricVal) {
|
setLinkClientMetrics(m: MetricVal) {
|
||||||
this.linkClientMetrics = m;
|
this.linkClientMetrics = m;
|
||||||
},
|
},
|
||||||
|
setNodeMetricValue(m: MetricVal) {
|
||||||
|
this.nodeMetricValue = m;
|
||||||
|
},
|
||||||
setLegendValues(expressions: string, data: { [key: string]: any }) {
|
setLegendValues(expressions: string, data: { [key: string]: any }) {
|
||||||
for (let idx = 0; idx < this.nodes.length; idx++) {
|
const nodeArr = this.nodes.filter((d: Node) => d.isReal);
|
||||||
|
for (let idx = 0; idx < nodeArr.length; idx++) {
|
||||||
for (let index = 0; index < expressions.length; index++) {
|
for (let index = 0; index < expressions.length; index++) {
|
||||||
const k = "expression" + idx + index;
|
const k = "expression" + idx + index;
|
||||||
if (expressions[index]) {
|
if (expressions[index]) {
|
||||||
this.nodes[idx][expressions[index]] = Number(data[k].results[0].values[0].value);
|
nodeArr[idx][expressions[index]] = Number(data[k].results[0].values[0].value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -332,15 +443,6 @@ export const topologyStore = defineStore({
|
|||||||
|
|
||||||
return { calls, nodes };
|
return { calls, nodes };
|
||||||
},
|
},
|
||||||
async getNodeMetricValue(param: { queryStr: string; conditions: { [key: string]: unknown } }) {
|
|
||||||
const res: AxiosResponse = await query(param);
|
|
||||||
|
|
||||||
if (res.data.errors) {
|
|
||||||
return res.data;
|
|
||||||
}
|
|
||||||
this.setNodeMetricValue(res.data.data);
|
|
||||||
return res.data;
|
|
||||||
},
|
|
||||||
async getNodeExpressionValue(param: { queryStr: string; conditions: { [key: string]: unknown } }) {
|
async getNodeExpressionValue(param: { queryStr: string; conditions: { [key: string]: unknown } }) {
|
||||||
const res: AxiosResponse = await query(param);
|
const res: AxiosResponse = await query(param);
|
||||||
|
|
||||||
@@ -350,38 +452,6 @@ export const topologyStore = defineStore({
|
|||||||
|
|
||||||
return res.data;
|
return res.data;
|
||||||
},
|
},
|
||||||
async getLinkClientMetrics(linkClientMetrics: string[]) {
|
|
||||||
if (!linkClientMetrics.length) {
|
|
||||||
this.setLinkClientMetrics({});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const idsC = this.calls.filter((i: Call) => i.detectPoints.includes("CLIENT")).map((b: Call) => b.id);
|
|
||||||
if (!idsC.length) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const param = await useQueryTopologyMetrics(linkClientMetrics, idsC);
|
|
||||||
const res = await this.getCallClientMetrics(param);
|
|
||||||
|
|
||||||
if (res.errors) {
|
|
||||||
ElMessage.error(res.errors);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
async getLinkServerMetrics(linkServerMetrics: string[]) {
|
|
||||||
if (!linkServerMetrics.length) {
|
|
||||||
this.setLinkServerMetrics({});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const idsS = this.calls.filter((i: Call) => i.detectPoints.includes("SERVER")).map((b: Call) => b.id);
|
|
||||||
if (!idsS.length) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const param = await useQueryTopologyMetrics(linkServerMetrics, idsS);
|
|
||||||
const res = await this.getCallServerMetrics(param);
|
|
||||||
|
|
||||||
if (res.errors) {
|
|
||||||
ElMessage.error(res.errors);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
async getLinkExpressions(expressions: string[], type: string) {
|
async getLinkExpressions(expressions: string[], type: string) {
|
||||||
if (!expressions.length) {
|
if (!expressions.length) {
|
||||||
this.setLinkServerMetrics({});
|
this.setLinkServerMetrics({});
|
||||||
@@ -405,22 +475,6 @@ export const topologyStore = defineStore({
|
|||||||
this.setLinkClientMetrics(metrics);
|
this.setLinkClientMetrics(metrics);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async queryNodeMetrics(nodeMetrics: string[]) {
|
|
||||||
if (!nodeMetrics.length) {
|
|
||||||
this.setNodeMetricValue({});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const ids = this.nodes.map((d: Node) => d.id);
|
|
||||||
if (!ids.length) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const param = await useQueryTopologyMetrics(nodeMetrics, ids);
|
|
||||||
const res = await this.getNodeMetricValue(param);
|
|
||||||
|
|
||||||
if (res.errors) {
|
|
||||||
ElMessage.error(res.errors);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
async queryNodeExpressions(expressions: string[]) {
|
async queryNodeExpressions(expressions: string[]) {
|
||||||
if (!expressions.length) {
|
if (!expressions.length) {
|
||||||
this.setNodeMetricValue({});
|
this.setNodeMetricValue({});
|
||||||
@@ -432,7 +486,7 @@ export const topologyStore = defineStore({
|
|||||||
}
|
}
|
||||||
const { getExpressionQuery, handleExpressionValues } = useQueryTopologyExpressionsProcessor(
|
const { getExpressionQuery, handleExpressionValues } = useQueryTopologyExpressionsProcessor(
|
||||||
expressions,
|
expressions,
|
||||||
this.nodes,
|
this.nodes.filter((d: Node) => d.isReal),
|
||||||
);
|
);
|
||||||
const param = getExpressionQuery();
|
const param = getExpressionQuery();
|
||||||
const res = await this.getNodeExpressionValue(param);
|
const res = await this.getNodeExpressionValue(param);
|
||||||
@@ -443,44 +497,97 @@ export const topologyStore = defineStore({
|
|||||||
const metrics = handleExpressionValues(res.data);
|
const metrics = handleExpressionValues(res.data);
|
||||||
this.setNodeMetricValue(metrics);
|
this.setNodeMetricValue(metrics);
|
||||||
},
|
},
|
||||||
async getLegendMetrics(param: { queryStr: string; conditions: { [key: string]: unknown } }) {
|
async getHierarchyServiceTopology() {
|
||||||
const res: AxiosResponse = await query(param);
|
const dashboardStore = useDashboardStore();
|
||||||
|
const { currentService } = useSelectorStore();
|
||||||
|
const id = this.node ? this.node.id : (currentService || {}).id;
|
||||||
|
let layer = dashboardStore.layerId;
|
||||||
|
if (this.node) {
|
||||||
|
layer = this.node.layers.includes(dashboardStore.layerId)
|
||||||
|
? dashboardStore.layerId
|
||||||
|
: this.node.layers.filter((d: string) => d !== dashboardStore.layerId)[0];
|
||||||
|
}
|
||||||
|
if (!(id && layer)) {
|
||||||
|
return new Promise((resolve) => resolve({}));
|
||||||
|
}
|
||||||
|
const res: AxiosResponse = await graphql
|
||||||
|
.query("getHierarchyServiceTopology")
|
||||||
|
.params({ serviceId: id, layer: layer });
|
||||||
if (res.data.errors) {
|
if (res.data.errors) {
|
||||||
return res.data;
|
return res.data;
|
||||||
}
|
}
|
||||||
const data = res.data.data;
|
const resp = await this.getListLayerLevels();
|
||||||
const metrics = Object.keys(data);
|
if (resp.errors) {
|
||||||
this.nodes = this.nodes.map((d: Node & Recordable) => {
|
return resp;
|
||||||
for (const m of metrics) {
|
|
||||||
for (const val of data[m].values) {
|
|
||||||
if (d.id === val.id) {
|
|
||||||
d[m] = val.value;
|
|
||||||
}
|
}
|
||||||
}
|
const levels = resp.data.levels || [];
|
||||||
}
|
this.setHierarchyServiceTopology(res.data.data.hierarchyServiceTopology || {}, levels);
|
||||||
return d;
|
|
||||||
});
|
|
||||||
return res.data;
|
return res.data;
|
||||||
},
|
},
|
||||||
async getCallServerMetrics(param: { queryStr: string; conditions: { [key: string]: unknown } }) {
|
async getListLayerLevels() {
|
||||||
const res: AxiosResponse = await query(param);
|
const res: AxiosResponse = await graphql.query("queryListLayerLevels").params({});
|
||||||
|
|
||||||
if (res.data.errors) {
|
|
||||||
return res.data;
|
|
||||||
}
|
|
||||||
this.setLinkServerMetrics(res.data.data);
|
|
||||||
return res.data;
|
return res.data;
|
||||||
},
|
},
|
||||||
async getCallClientMetrics(param: { queryStr: string; conditions: { [key: string]: unknown } }) {
|
async getHierarchyInstanceTopology() {
|
||||||
const res: AxiosResponse = await query(param);
|
const { currentPod } = useSelectorStore();
|
||||||
|
const dashboardStore = useDashboardStore();
|
||||||
|
|
||||||
|
if (!(currentPod && dashboardStore.layerId)) {
|
||||||
|
return new Promise((resolve) => resolve({}));
|
||||||
|
}
|
||||||
|
const res: AxiosResponse = await graphql
|
||||||
|
.query("getHierarchyInstanceTopology")
|
||||||
|
.params({ instanceId: currentPod.id, layer: dashboardStore.layerId });
|
||||||
if (res.data.errors) {
|
if (res.data.errors) {
|
||||||
return res.data;
|
return res.data;
|
||||||
}
|
}
|
||||||
this.setLinkClientMetrics(res.data.data);
|
const resp = await this.getListLayerLevels();
|
||||||
|
if (resp.errors) {
|
||||||
|
return resp;
|
||||||
|
}
|
||||||
|
const levels = resp.data.levels || [];
|
||||||
|
this.setHierarchyInstanceTopology(res.data.data.hierarchyInstanceTopology || {}, levels);
|
||||||
return res.data;
|
return res.data;
|
||||||
},
|
},
|
||||||
|
async queryHierarchyExpressions(expressions: string[], nodes: Node[]) {
|
||||||
|
const { getExpressionQuery, handleExpressionValues } = useQueryTopologyExpressionsProcessor(expressions, nodes);
|
||||||
|
const param = getExpressionQuery();
|
||||||
|
const res = await this.getNodeExpressionValue(param);
|
||||||
|
if (res.errors) {
|
||||||
|
ElMessage.error(res.errors);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const metrics = handleExpressionValues(res.data);
|
||||||
|
return metrics;
|
||||||
|
},
|
||||||
|
async queryHierarchyNodeExpressions(expressions: string[], layer: string) {
|
||||||
|
const nodes = this.hierarchyServiceNodes.filter((n: HierarchyNode) => n.layer === layer);
|
||||||
|
if (!nodes.length) {
|
||||||
|
this.setHierarchyNodeMetricValue({}, layer);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!expressions.length) {
|
||||||
|
this.setHierarchyNodeMetricValue({}, layer);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const metrics = await this.queryHierarchyExpressions(expressions, nodes);
|
||||||
|
this.setHierarchyNodeMetricValue(metrics, layer);
|
||||||
|
},
|
||||||
|
async queryHierarchyInstanceNodeExpressions(expressions: string[], layer: string) {
|
||||||
|
const nodes = this.hierarchyInstanceNodes.filter((n: HierarchyNode) => n.layer === layer);
|
||||||
|
|
||||||
|
if (!expressions.length) {
|
||||||
|
this.setHierarchyInstanceNodeMetricValue({}, layer);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!nodes.length) {
|
||||||
|
this.setHierarchyInstanceNodeMetricValue({}, layer);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const metrics = await this.queryHierarchyExpressions(expressions, nodes);
|
||||||
|
this.setHierarchyInstanceNodeMetricValue(metrics, layer);
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@@ -23,7 +23,6 @@ import type { AxiosResponse } from "axios";
|
|||||||
import { useAppStoreWithOut } from "@/store/modules/app";
|
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||||
import { useSelectorStore } from "@/store/modules/selectors";
|
import { useSelectorStore } from "@/store/modules/selectors";
|
||||||
import { QueryOrders } from "@/views/dashboard/data";
|
import { QueryOrders } from "@/views/dashboard/data";
|
||||||
|
|
||||||
interface TraceState {
|
interface TraceState {
|
||||||
services: Service[];
|
services: Service[];
|
||||||
instances: Instance[];
|
instances: Instance[];
|
||||||
@@ -168,6 +167,7 @@ export const traceStore = defineStore({
|
|||||||
return res.data;
|
return res.data;
|
||||||
}
|
}
|
||||||
const data = res.data.data.trace.spans;
|
const data = res.data.data.trace.spans;
|
||||||
|
|
||||||
this.setTraceSpans(data || []);
|
this.setTraceSpans(data || []);
|
||||||
return res.data;
|
return res.data;
|
||||||
},
|
},
|
||||||
|
@@ -15,9 +15,19 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
@use "element-plus/theme-chalk/src/dark/css-vars.scss" as *;
|
@use "element-plus/theme-chalk/src/dark/css-vars.scss" as *;
|
||||||
|
@keyframes topo-dash {
|
||||||
|
from {
|
||||||
|
stroke-dashoffset: 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
to {
|
||||||
|
stroke-dashoffset: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
:root {
|
:root {
|
||||||
--sw-green: #70c877;
|
--sw-green: #70c877;
|
||||||
--sw-orange: #e6a23c;
|
--sw-orange: #e6a23c;
|
||||||
|
--sw-topo-animation: topo-dash 0.3s linear infinite;
|
||||||
}
|
}
|
||||||
|
|
||||||
html {
|
html {
|
||||||
@@ -58,14 +68,14 @@ html {
|
|||||||
--sw-time-axis-text: #4d4d4d;
|
--sw-time-axis-text: #4d4d4d;
|
||||||
--sw-drawer-header: #72767b;
|
--sw-drawer-header: #72767b;
|
||||||
--sw-marketplace-border: #dedfe0;
|
--sw-marketplace-border: #dedfe0;
|
||||||
--sw-grid-item-active: #79bbff;
|
--sw-grid-item-active: #d4d7de;
|
||||||
}
|
}
|
||||||
|
|
||||||
html.dark {
|
html.dark {
|
||||||
--el-color-primary: #409eff;
|
--el-color-primary: #409eff;
|
||||||
--theme-background: #212224;
|
--theme-background: #212224;
|
||||||
--font-color: #fafbfc;
|
--font-color: #fafbfc;
|
||||||
--disabled-color: #ccc;
|
--disabled-color: #999;
|
||||||
--dashboard-tool-bg: #000;
|
--dashboard-tool-bg: #000;
|
||||||
--text-color-placeholder: #ccc;
|
--text-color-placeholder: #ccc;
|
||||||
--border-color: #262629;
|
--border-color: #262629;
|
||||||
@@ -82,7 +92,7 @@ html.dark {
|
|||||||
--sw-config-header: #303133;
|
--sw-config-header: #303133;
|
||||||
--sw-topology-color: #ccc;
|
--sw-topology-color: #ccc;
|
||||||
--vis-tooltip-bg: #414243;
|
--vis-tooltip-bg: #414243;
|
||||||
--sw-topology-switch-icon: #aaa;
|
--sw-topology-switch-icon: #999;
|
||||||
--sw-topology-box-shadow: 0 0 2px 0 #444;
|
--sw-topology-box-shadow: 0 0 2px 0 #444;
|
||||||
--sw-topology-setting-bg: #333;
|
--sw-topology-setting-bg: #333;
|
||||||
--sw-topology-border: 1px solid #666;
|
--sw-topology-border: 1px solid #666;
|
||||||
@@ -250,3 +260,27 @@ div:has(> a.menu-title) {
|
|||||||
.el-input-number .el-input__inner {
|
.el-input-number .el-input__inner {
|
||||||
text-align: left !important;
|
text-align: left !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
html {
|
||||||
|
&::view-transition-old(root),
|
||||||
|
&::view-transition-new(root) {
|
||||||
|
animation: none;
|
||||||
|
mix-blend-mode: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.dark {
|
||||||
|
&::view-transition-old(root) {
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
&::view-transition-new(root) {
|
||||||
|
z-index: 999;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&::view-transition-old(root) {
|
||||||
|
z-index: 999;
|
||||||
|
}
|
||||||
|
&::view-transition-new(root) {
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
2
src/types/app.d.ts
vendored
@@ -59,7 +59,7 @@ export interface SubItem {
|
|||||||
icon: string;
|
icon: string;
|
||||||
title: string;
|
title: string;
|
||||||
activate: boolean;
|
activate: boolean;
|
||||||
name?: string;
|
name: string;
|
||||||
path?: string;
|
path?: string;
|
||||||
notShow?: boolean;
|
notShow?: boolean;
|
||||||
id?: string;
|
id?: string;
|
||||||
|
59
src/types/auto-imports.d.ts
vendored
@@ -1,52 +1,9 @@
|
|||||||
// Generated by 'unplugin-auto-import'
|
/* eslint-disable */
|
||||||
// We suggest you to commit this file into source control
|
/* prettier-ignore */
|
||||||
declare global {
|
// @ts-nocheck
|
||||||
const computed: typeof import('vue')['computed']
|
// noinspection JSUnusedGlobalSymbols
|
||||||
const createApp: typeof import('vue')['createApp']
|
// Generated by unplugin-auto-import
|
||||||
const customRef: typeof import('vue')['customRef']
|
|
||||||
const defineAsyncComponent: typeof import('vue')['defineAsyncComponent']
|
|
||||||
const defineComponent: typeof import('vue')['defineComponent']
|
|
||||||
const effectScope: typeof import('vue')['effectScope']
|
|
||||||
const EffectScope: typeof import('vue')['EffectScope']
|
|
||||||
const getCurrentInstance: typeof import('vue')['getCurrentInstance']
|
|
||||||
const getCurrentScope: typeof import('vue')['getCurrentScope']
|
|
||||||
const h: typeof import('vue')['h']
|
|
||||||
const inject: typeof import('vue')['inject']
|
|
||||||
const isReadonly: typeof import('vue')['isReadonly']
|
|
||||||
const isRef: typeof import('vue')['isRef']
|
|
||||||
const markRaw: typeof import('vue')['markRaw']
|
|
||||||
const nextTick: typeof import('vue')['nextTick']
|
|
||||||
const onActivated: typeof import('vue')['onActivated']
|
|
||||||
const onBeforeMount: typeof import('vue')['onBeforeMount']
|
|
||||||
const onBeforeUnmount: typeof import('vue')['onBeforeUnmount']
|
|
||||||
const onBeforeUpdate: typeof import('vue')['onBeforeUpdate']
|
|
||||||
const onDeactivated: typeof import('vue')['onDeactivated']
|
|
||||||
const onErrorCaptured: typeof import('vue')['onErrorCaptured']
|
|
||||||
const onMounted: typeof import('vue')['onMounted']
|
|
||||||
const onRenderTracked: typeof import('vue')['onRenderTracked']
|
|
||||||
const onRenderTriggered: typeof import('vue')['onRenderTriggered']
|
|
||||||
const onScopeDispose: typeof import('vue')['onScopeDispose']
|
|
||||||
const onServerPrefetch: typeof import('vue')['onServerPrefetch']
|
|
||||||
const onUnmounted: typeof import('vue')['onUnmounted']
|
|
||||||
const onUpdated: typeof import('vue')['onUpdated']
|
|
||||||
const provide: typeof import('vue')['provide']
|
|
||||||
const reactive: typeof import('vue')['reactive']
|
|
||||||
const readonly: typeof import('vue')['readonly']
|
|
||||||
const ref: typeof import('vue')['ref']
|
|
||||||
const resolveComponent: typeof import('vue')['resolveComponent']
|
|
||||||
const shallowReactive: typeof import('vue')['shallowReactive']
|
|
||||||
const shallowReadonly: typeof import('vue')['shallowReadonly']
|
|
||||||
const shallowRef: typeof import('vue')['shallowRef']
|
|
||||||
const toRaw: typeof import('vue')['toRaw']
|
|
||||||
const toRef: typeof import('vue')['toRef']
|
|
||||||
const toRefs: typeof import('vue')['toRefs']
|
|
||||||
const triggerRef: typeof import('vue')['triggerRef']
|
|
||||||
const unref: typeof import('vue')['unref']
|
|
||||||
const useAttrs: typeof import('vue')['useAttrs']
|
|
||||||
const useCssModule: typeof import('vue')['useCssModule']
|
|
||||||
const useCssVars: typeof import('vue')['useCssVars']
|
|
||||||
const useSlots: typeof import('vue')['useSlots']
|
|
||||||
const watch: typeof import('vue')['watch']
|
|
||||||
const watchEffect: typeof import('vue')['watchEffect']
|
|
||||||
}
|
|
||||||
export {}
|
export {}
|
||||||
|
declare global {
|
||||||
|
|
||||||
|
}
|
||||||
|
16
src/types/components.d.ts
vendored
@@ -1,9 +1,11 @@
|
|||||||
// generated by unplugin-vue-components
|
/* eslint-disable */
|
||||||
// We suggest you to commit this file into source control
|
// @ts-nocheck
|
||||||
|
// Generated by unplugin-vue-components
|
||||||
// Read more: https://github.com/vuejs/core/pull/3399
|
// Read more: https://github.com/vuejs/core/pull/3399
|
||||||
import '@vue/runtime-core'
|
export {}
|
||||||
|
|
||||||
declare module '@vue/runtime-core' {
|
/* prettier-ignore */
|
||||||
|
declare module 'vue' {
|
||||||
export interface GlobalComponents {
|
export interface GlobalComponents {
|
||||||
DateCalendar: typeof import('./../components/DateCalendar.vue')['default']
|
DateCalendar: typeof import('./../components/DateCalendar.vue')['default']
|
||||||
ElBreadcrumb: typeof import('element-plus/es')['ElBreadcrumb']
|
ElBreadcrumb: typeof import('element-plus/es')['ElBreadcrumb']
|
||||||
@@ -42,7 +44,6 @@ declare module '@vue/runtime-core' {
|
|||||||
ElTooltip: typeof import('element-plus/es')['ElTooltip']
|
ElTooltip: typeof import('element-plus/es')['ElTooltip']
|
||||||
Graph: typeof import('./../components/Graph.vue')['default']
|
Graph: typeof import('./../components/Graph.vue')['default']
|
||||||
Icon: typeof import('./../components/Icon.vue')['default']
|
Icon: typeof import('./../components/Icon.vue')['default']
|
||||||
Loading: typeof import('element-plus/es')['ElLoadingDirective']
|
|
||||||
Radio: typeof import('./../components/Radio.vue')['default']
|
Radio: typeof import('./../components/Radio.vue')['default']
|
||||||
RouterLink: typeof import('vue-router')['RouterLink']
|
RouterLink: typeof import('vue-router')['RouterLink']
|
||||||
RouterView: typeof import('vue-router')['RouterView']
|
RouterView: typeof import('vue-router')['RouterView']
|
||||||
@@ -51,6 +52,7 @@ declare module '@vue/runtime-core' {
|
|||||||
Tags: typeof import('./../components/Tags.vue')['default']
|
Tags: typeof import('./../components/Tags.vue')['default']
|
||||||
TimePicker: typeof import('./../components/TimePicker.vue')['default']
|
TimePicker: typeof import('./../components/TimePicker.vue')['default']
|
||||||
}
|
}
|
||||||
|
export interface ComponentCustomProperties {
|
||||||
|
vLoading: typeof import('element-plus/es')['ElLoadingDirective']
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export {}
|
|
||||||
|
10
src/types/dashboard.d.ts
vendored
@@ -21,6 +21,9 @@ export type DashboardItem = {
|
|||||||
layer: string;
|
layer: string;
|
||||||
isRoot: boolean;
|
isRoot: boolean;
|
||||||
name: string;
|
name: string;
|
||||||
|
isDefault: boolean;
|
||||||
|
expressions?: string[];
|
||||||
|
expressionsConfig?: MetricConfigOpt[];
|
||||||
};
|
};
|
||||||
export interface LayoutConfig {
|
export interface LayoutConfig {
|
||||||
x: number;
|
x: number;
|
||||||
@@ -29,14 +32,11 @@ export interface LayoutConfig {
|
|||||||
h: number;
|
h: number;
|
||||||
i: string;
|
i: string;
|
||||||
type: string;
|
type: string;
|
||||||
metricMode?: string;
|
|
||||||
widget?: WidgetConfig;
|
widget?: WidgetConfig;
|
||||||
graph?: GraphConfig;
|
graph?: GraphConfig;
|
||||||
metrics?: string[];
|
|
||||||
expressions?: string[];
|
expressions?: string[];
|
||||||
metricTypes?: string[];
|
|
||||||
typesOfMQE?: string[];
|
typesOfMQE?: string[];
|
||||||
children?: { name: string; children: LayoutConfig[] }[];
|
children?: { name: string; children: LayoutConfig[]; expression?: string; enable?: boolean }[];
|
||||||
activedTabIndex?: number;
|
activedTabIndex?: number;
|
||||||
metricConfig?: MetricConfigOpt[];
|
metricConfig?: MetricConfigOpt[];
|
||||||
id?: string;
|
id?: string;
|
||||||
@@ -74,7 +74,6 @@ export type Filters = {
|
|||||||
export type MetricConfigOpt = {
|
export type MetricConfigOpt = {
|
||||||
unit?: string;
|
unit?: string;
|
||||||
label?: string;
|
label?: string;
|
||||||
calculation?: string;
|
|
||||||
labelsIndex?: string;
|
labelsIndex?: string;
|
||||||
sortOrder?: string;
|
sortOrder?: string;
|
||||||
topN?: number;
|
topN?: number;
|
||||||
@@ -137,7 +136,6 @@ export interface TextConfig {
|
|||||||
export interface TableConfig {
|
export interface TableConfig {
|
||||||
type?: string;
|
type?: string;
|
||||||
showTableValues: boolean;
|
showTableValues: boolean;
|
||||||
tableHeaderCol1: string;
|
|
||||||
tableHeaderCol2: string;
|
tableHeaderCol2: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
15
src/types/ebpf.d.ts
vendored
@@ -77,6 +77,21 @@ export type StackElement = {
|
|||||||
rateOfRoot?: string;
|
rateOfRoot?: string;
|
||||||
rateOfParent: string;
|
rateOfParent: string;
|
||||||
};
|
};
|
||||||
|
export type TraceProfilingElement = {
|
||||||
|
id: string;
|
||||||
|
originId: string;
|
||||||
|
name: string;
|
||||||
|
parentId: string;
|
||||||
|
codeSignature: string;
|
||||||
|
count: number;
|
||||||
|
stackType: string;
|
||||||
|
value: number;
|
||||||
|
children?: TraceProfilingElement[];
|
||||||
|
rateOfRoot?: string;
|
||||||
|
rateOfParent: string;
|
||||||
|
duration: number;
|
||||||
|
durationChildExcluded: number;
|
||||||
|
};
|
||||||
export type AnalyzationTrees = {
|
export type AnalyzationTrees = {
|
||||||
id: string;
|
id: string;
|
||||||
parentId: string;
|
parentId: string;
|
||||||
|
9
src/types/global.d.ts
vendored
@@ -15,11 +15,11 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
import type {
|
import type {
|
||||||
|
ComponentPublicInstance,
|
||||||
ComponentRenderProxy,
|
ComponentRenderProxy,
|
||||||
|
FunctionalComponent,
|
||||||
VNode,
|
VNode,
|
||||||
VNodeChild,
|
VNodeChild,
|
||||||
ComponentPublicInstance,
|
|
||||||
FunctionalComponent,
|
|
||||||
PropType as VuePropType,
|
PropType as VuePropType,
|
||||||
} from "vue";
|
} from "vue";
|
||||||
|
|
||||||
@@ -39,6 +39,11 @@ declare global {
|
|||||||
lastBuildTime: string;
|
lastBuildTime: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Document
|
||||||
|
interface Document {
|
||||||
|
startViewTransition(callback: () => void): any;
|
||||||
|
}
|
||||||
|
|
||||||
// vue
|
// vue
|
||||||
declare type PropType<T> = VuePropType<T>;
|
declare type PropType<T> = VuePropType<T>;
|
||||||
declare type VueNode = VNodeChild | JSX.Element;
|
declare type VueNode = VNodeChild | JSX.Element;
|
||||||
|
36
src/types/topology.d.ts
vendored
@@ -14,6 +14,7 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export interface Call {
|
export interface Call {
|
||||||
source: string | any;
|
source: string | any;
|
||||||
target: string | any;
|
target: string | any;
|
||||||
@@ -31,15 +32,48 @@ export interface Call {
|
|||||||
targetY?: number;
|
targetY?: number;
|
||||||
targetX?: number;
|
targetX?: number;
|
||||||
}
|
}
|
||||||
|
export interface HierarchyNode {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
layer: string;
|
||||||
|
level?: number;
|
||||||
|
key: string;
|
||||||
|
}
|
||||||
export interface Node {
|
export interface Node {
|
||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
type: string;
|
type: string;
|
||||||
isReal: boolean;
|
isReal: boolean;
|
||||||
layer?: string;
|
layers: string[];
|
||||||
serviceName?: string;
|
serviceName?: string;
|
||||||
height?: number;
|
height?: number;
|
||||||
|
width?: number;
|
||||||
x?: number;
|
x?: number;
|
||||||
y?: number;
|
y?: number;
|
||||||
level?: number;
|
level?: number;
|
||||||
|
l?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ServiceHierarchy {
|
||||||
|
relations: HierarchyServiceRelation[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface HierarchyServiceRelation {
|
||||||
|
upperService: HierarchyRelated;
|
||||||
|
lowerService: HierarchyRelated;
|
||||||
|
}
|
||||||
|
|
||||||
|
type HierarchyRelated = {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
layer: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export interface InstanceHierarchy {
|
||||||
|
relations: HierarchyInstanceRelation[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface HierarchyInstanceRelation {
|
||||||
|
upperInstance: HierarchyRelated;
|
||||||
|
lowerInstance: HierarchyRelated;
|
||||||
}
|
}
|
||||||
|
29
src/utils/debounce.ts
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
/**
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export function debounce(callback: Function, dur: number) {
|
||||||
|
let timer: any;
|
||||||
|
|
||||||
|
return function () {
|
||||||
|
if (timer) {
|
||||||
|
clearTimeout(timer);
|
||||||
|
}
|
||||||
|
timer = setTimeout(function () {
|
||||||
|
callback();
|
||||||
|
}, dur);
|
||||||
|
};
|
||||||
|
}
|
24
src/utils/flameGraph.ts
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
/**
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export function treeForeach(tree: any, func: (node: any) => void) {
|
||||||
|
for (const data of tree) {
|
||||||
|
data.children && treeForeach(data.children, func);
|
||||||
|
func(data);
|
||||||
|
}
|
||||||
|
return tree;
|
||||||
|
}
|
44
src/utils/mutation.ts
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
/**
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
* contributor license agreements. See the NOTICE file distributed with
|
||||||
|
* this work for additional information regarding copyright ownership.
|
||||||
|
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
* (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export class mutationObserver {
|
||||||
|
private static mutationObserverMap: Map<string, MutationObserver> = new Map<string, MutationObserver>();
|
||||||
|
|
||||||
|
static create(key: string, callback: MutationCallback) {
|
||||||
|
const observer = new MutationObserver(callback);
|
||||||
|
mutationObserver.mutationObserverMap.set(key, observer);
|
||||||
|
}
|
||||||
|
|
||||||
|
static observe(key: string, target: Node, options?: MutationObserverInit) {
|
||||||
|
const observer = mutationObserver.mutationObserverMap.get(key);
|
||||||
|
if (observer) {
|
||||||
|
observer.observe(target, options);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static deleteObserve(key: string): void {
|
||||||
|
this.disconnect(key);
|
||||||
|
this.mutationObserverMap.delete(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
static disconnect(key: string): void {
|
||||||
|
const observer = this.mutationObserverMap.get(key);
|
||||||
|
if (observer) {
|
||||||
|
observer.disconnect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -14,11 +14,20 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License. -->
|
limitations under the License. -->
|
||||||
<template>
|
<template>
|
||||||
<div class="menus flex-v">
|
<div class="menus flex-v">
|
||||||
|
<div>
|
||||||
|
<el-input v-model="searchText" placeholder="Please input name" class="input-with-search" @change="searchMenus">
|
||||||
|
<template #append>
|
||||||
|
<el-button size="small">
|
||||||
|
<Icon size="sm" iconName="search" />
|
||||||
|
</el-button>
|
||||||
|
</template>
|
||||||
|
</el-input>
|
||||||
|
</div>
|
||||||
<div class="category-body flex-h">
|
<div class="category-body flex-h">
|
||||||
<div class="mr-20 mt-10 flex-h category">
|
<div class="mr-20 mt-10 flex-h category">
|
||||||
<el-card
|
<el-card
|
||||||
class="item"
|
class="item"
|
||||||
v-for="(menu, index) in appStore.allMenus"
|
v-for="(menu, index) in menus"
|
||||||
:key="index"
|
:key="index"
|
||||||
@click="handleItems(menu)"
|
@click="handleItems(menu)"
|
||||||
:class="currentItems.name === menu.name ? 'active' : ''"
|
:class="currentItems.name === menu.name ? 'active' : ''"
|
||||||
@@ -54,15 +63,36 @@ limitations under the License. -->
|
|||||||
import { ref } from "vue";
|
import { ref } from "vue";
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
import { useAppStoreWithOut } from "@/store/modules/app";
|
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||||
import type { MenuOptions } from "@/types/app";
|
import type { MenuOptions, SubItem } from "@/types/app";
|
||||||
|
|
||||||
const { t, te } = useI18n();
|
const { t, te } = useI18n();
|
||||||
const appStore = useAppStoreWithOut();
|
const appStore = useAppStoreWithOut();
|
||||||
const currentItems = ref<MenuOptions>(appStore.allMenus[0] || {});
|
const currentItems = ref<MenuOptions>(appStore.allMenus[0] || {});
|
||||||
|
const searchText = ref<string>("");
|
||||||
|
const menus = ref<MenuOptions[]>(appStore.allMenus || []);
|
||||||
|
|
||||||
function handleItems(item: MenuOptions) {
|
function handleItems(item: MenuOptions) {
|
||||||
currentItems.value = item;
|
currentItems.value = item;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function searchMenus() {
|
||||||
|
if (!searchText.value) {
|
||||||
|
menus.value = appStore.allMenus;
|
||||||
|
currentItems.value = menus.value[0] || {};
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
menus.value = appStore.allMenus.filter(
|
||||||
|
(item: MenuOptions) =>
|
||||||
|
(te(item.i18nKey) ? t(item.i18nKey) : item.title).toLowerCase().includes(searchText.value.toLowerCase()) ||
|
||||||
|
!!item.subItems.find((subItem: SubItem) =>
|
||||||
|
(te(subItem.i18nKey) ? t(subItem.i18nKey) : item.title)
|
||||||
|
.toLowerCase()
|
||||||
|
.includes(searchText.value.toLowerCase()),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
currentItems.value = menus.value[0] || {};
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.menus {
|
.menus {
|
||||||
@@ -111,11 +141,16 @@ limitations under the License. -->
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.input-with-search {
|
||||||
|
width: 300px;
|
||||||
|
}
|
||||||
|
|
||||||
.category {
|
.category {
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
border-right: 1px solid var(--sw-marketplace-border);
|
border-right: 1px solid var(--sw-marketplace-border);
|
||||||
align-content: flex-start;
|
align-content: flex-start;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
33
src/views/NotFound.vue
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
<!-- Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
contributor license agreements. See the NOTICE file distributed with
|
||||||
|
this work for additional information regarding copyright ownership.
|
||||||
|
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
(the "License"); you may not use this file except in compliance with
|
||||||
|
the License. You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License. -->
|
||||||
|
<template>
|
||||||
|
<div class="not-found flex-h">
|
||||||
|
<Icon size="largest" iconName="logo-light" />
|
||||||
|
<h1 class="ml-20">404 Page Not Found</h1>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.not-found {
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
width: 160px;
|
||||||
|
height: 160px;
|
||||||
|
}
|
||||||
|
</style>
|
@@ -13,7 +13,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|||||||
See the License for the specific language governing permissions and
|
See the License for the specific language governing permissions and
|
||||||
limitations under the License. -->
|
limitations under the License. -->
|
||||||
<template>
|
<template>
|
||||||
<div class="timeline-table clear">
|
<div class="timeline-table clear" v-loading="alarmStore.loading">
|
||||||
<div v-for="(i, index) in alarmStore.alarms" :key="index" class="clear timeline-item">
|
<div v-for="(i, index) in alarmStore.alarms" :key="index" class="clear timeline-item">
|
||||||
<div class="g-sm-3 grey sm hide-xs time-line tr">
|
<div class="g-sm-3 grey sm hide-xs time-line tr">
|
||||||
{{ dateFormat(parseInt(i.startTime)) }}
|
{{ dateFormat(parseInt(i.startTime)) }}
|
||||||
|
@@ -21,15 +21,7 @@ limitations under the License. -->
|
|||||||
<span class="remove-icon" @click="removeTags(index)">×</span>
|
<span class="remove-icon" @click="removeTags(index)">×</span>
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
<el-input
|
<el-popover trigger="click" :visible="visible" width="300px">
|
||||||
v-if="type === 'ALARM'"
|
|
||||||
size="small"
|
|
||||||
v-model="tags"
|
|
||||||
class="trace-new-tag"
|
|
||||||
@change="addLabels"
|
|
||||||
:placeholder="t('addTags')"
|
|
||||||
/>
|
|
||||||
<el-popover v-else trigger="click" :visible="visible" width="300px">
|
|
||||||
<template #reference>
|
<template #reference>
|
||||||
<el-input
|
<el-input
|
||||||
size="small"
|
size="small"
|
||||||
@@ -47,7 +39,7 @@ limitations under the License. -->
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</el-popover>
|
</el-popover>
|
||||||
<span class="tags-tip" :class="type !== 'ALARM' && tagArr.length ? 'link-tips' : ''">
|
<span class="tags-tip" :class="tagArr.length ? 'link-tips' : ''">
|
||||||
<a
|
<a
|
||||||
target="blank"
|
target="blank"
|
||||||
href="https://github.com/apache/skywalking/blob/master/docs/en/setup/backend/configuration-vocabulary.md"
|
href="https://github.com/apache/skywalking/blob/master/docs/en/setup/backend/configuration-vocabulary.md"
|
||||||
@@ -68,6 +60,7 @@ limitations under the License. -->
|
|||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
import { useTraceStore } from "@/store/modules/trace";
|
import { useTraceStore } from "@/store/modules/trace";
|
||||||
import { useLogStore } from "@/store/modules/log";
|
import { useLogStore } from "@/store/modules/log";
|
||||||
|
import { useAlarmStore } from "@/store/modules/alarm";
|
||||||
import { ElMessage } from "element-plus";
|
import { ElMessage } from "element-plus";
|
||||||
import { useAppStoreWithOut } from "@/store/modules/app";
|
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||||
|
|
||||||
@@ -79,6 +72,7 @@ limitations under the License. -->
|
|||||||
const traceStore = useTraceStore();
|
const traceStore = useTraceStore();
|
||||||
const logStore = useLogStore();
|
const logStore = useLogStore();
|
||||||
const appStore = useAppStoreWithOut();
|
const appStore = useAppStoreWithOut();
|
||||||
|
const alarmStore = useAlarmStore();
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const tags = ref<string>("");
|
const tags = ref<string>("");
|
||||||
const tagsList = ref<string[]>([]);
|
const tagsList = ref<string[]>([]);
|
||||||
@@ -121,10 +115,18 @@ limitations under the License. -->
|
|||||||
let resp: Recordable = {};
|
let resp: Recordable = {};
|
||||||
if (props.type === "TRACE") {
|
if (props.type === "TRACE") {
|
||||||
resp = await traceStore.getTagKeys();
|
resp = await traceStore.getTagKeys();
|
||||||
} else {
|
}
|
||||||
|
if (props.type === "LOG") {
|
||||||
resp = await logStore.getLogTagKeys();
|
resp = await logStore.getLogTagKeys();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (props.type === "ALARM") {
|
||||||
|
resp = await alarmStore.getAlarmTagKeys();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!resp.data) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (resp.errors) {
|
if (resp.errors) {
|
||||||
ElMessage.error(resp.errors);
|
ElMessage.error(resp.errors);
|
||||||
return;
|
return;
|
||||||
@@ -140,10 +142,17 @@ limitations under the License. -->
|
|||||||
let resp: Recordable = {};
|
let resp: Recordable = {};
|
||||||
if (props.type === "TRACE") {
|
if (props.type === "TRACE") {
|
||||||
resp = await traceStore.getTagValues(param);
|
resp = await traceStore.getTagValues(param);
|
||||||
} else {
|
}
|
||||||
|
if (props.type === "LOG") {
|
||||||
resp = await logStore.getLogTagValues(param);
|
resp = await logStore.getLogTagValues(param);
|
||||||
}
|
}
|
||||||
|
if (props.type === "ALARM") {
|
||||||
|
resp = await alarmStore.getAlarmTagValues(param);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!resp.data) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (resp.errors) {
|
if (resp.errors) {
|
||||||
ElMessage.error(resp.errors);
|
ElMessage.error(resp.errors);
|
||||||
return;
|
return;
|
||||||
|
@@ -57,14 +57,23 @@ limitations under the License. -->
|
|||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="layer" label="Layer" width="160" />
|
<el-table-column prop="layer" label="Layer" width="160" />
|
||||||
<el-table-column prop="entity" label="Entity" width="200" />
|
<el-table-column prop="entity" label="Entity" width="200" />
|
||||||
<el-table-column prop="isRoot" label="Root" width="60">
|
<el-table-column prop="isRoot" label="Root" width="150">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<span>
|
<el-popconfirm
|
||||||
{{ scope.row.isRoot ? t("yes") : t("no") }}
|
:title="t('rootTitle')"
|
||||||
</span>
|
@confirm="setRoot(scope.row)"
|
||||||
|
v-if="[EntityType[0].value, EntityType[1].value].includes(scope.row.entity)"
|
||||||
|
>
|
||||||
|
<template #reference>
|
||||||
|
<el-button size="small" style="width: 110px">
|
||||||
|
{{ scope.row.isRoot ? t("setNormal") : t("setRoot") }}
|
||||||
|
</el-button>
|
||||||
|
</template>
|
||||||
|
</el-popconfirm>
|
||||||
|
<span v-else> -- </span>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="Operations" width="350">
|
<el-table-column label="Operations" width="400">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-button size="small" @click="handleEdit(scope.row)">
|
<el-button size="small" @click="handleEdit(scope.row)">
|
||||||
{{ t("edit") }}
|
{{ t("edit") }}
|
||||||
@@ -72,6 +81,14 @@ limitations under the License. -->
|
|||||||
<el-button size="small" @click="handleRename(scope.row)">
|
<el-button size="small" @click="handleRename(scope.row)">
|
||||||
{{ t("rename") }}
|
{{ t("rename") }}
|
||||||
</el-button>
|
</el-button>
|
||||||
|
<el-button
|
||||||
|
v-if="[EntityType[0].value, EntityType[3].value].includes(scope.row.entity)"
|
||||||
|
size="small"
|
||||||
|
@click="handleEditMQE(scope.row)"
|
||||||
|
>
|
||||||
|
Hierarchy Graph
|
||||||
|
</el-button>
|
||||||
|
<span v-else class="placeholder"></span>
|
||||||
<el-popconfirm :title="t('deleteTitle')" @confirm="handleDelete(scope.row)">
|
<el-popconfirm :title="t('deleteTitle')" @confirm="handleDelete(scope.row)">
|
||||||
<template #reference>
|
<template #reference>
|
||||||
<el-button size="small" type="danger">
|
<el-button size="small" type="danger">
|
||||||
@@ -79,17 +96,6 @@ limitations under the License. -->
|
|||||||
</el-button>
|
</el-button>
|
||||||
</template>
|
</template>
|
||||||
</el-popconfirm>
|
</el-popconfirm>
|
||||||
<el-popconfirm
|
|
||||||
:title="t('rootTitle')"
|
|
||||||
@confirm="setRoot(scope.row)"
|
|
||||||
v-if="[EntityType[0].value, EntityType[1].value].includes(scope.row.entity)"
|
|
||||||
>
|
|
||||||
<template #reference>
|
|
||||||
<el-button size="small" style="width: 110px" type="danger">
|
|
||||||
{{ scope.row.isRoot ? t("setNormal") : t("setRoot") }}
|
|
||||||
</el-button>
|
|
||||||
</template>
|
|
||||||
</el-popconfirm>
|
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
@@ -125,6 +131,43 @@ limitations under the License. -->
|
|||||||
@next-click="changePage"
|
@next-click="changePage"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<el-dialog v-model="MQEVisible" title="Hierarchy Graph" width="400px">
|
||||||
|
<div class="mb-10">
|
||||||
|
<span class="label mr-10">{{ t("hierarchyNodeDashboard") }}</span>
|
||||||
|
<el-switch v-model="currentRow.isDefault" style="height: 25px" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<span class="label">{{ t("hierarchyNodeMetrics") }}</span>
|
||||||
|
<el-popover placement="left" :width="400" trigger="click">
|
||||||
|
<template #reference>
|
||||||
|
<span>
|
||||||
|
<Icon class="cp ml-5" iconName="mode_edit" size="middle" />
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
<Metrics
|
||||||
|
:type="'hierarchyServicesConfig'"
|
||||||
|
:expressions="currentRow.expressions || []"
|
||||||
|
:layer="currentRow.layer"
|
||||||
|
:entity="currentRow.entity"
|
||||||
|
@update="updateSettings"
|
||||||
|
/>
|
||||||
|
</el-popover>
|
||||||
|
</div>
|
||||||
|
<div class="mt-10 expressions">
|
||||||
|
<Tags
|
||||||
|
:tags="currentRow.expressions || []"
|
||||||
|
:vertical="true"
|
||||||
|
:text="t('addExpressions')"
|
||||||
|
@change="(param: string[]) => changeExpressions(param)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<template #footer>
|
||||||
|
<span class="dialog-footer">
|
||||||
|
<el-button @click="MQEVisible = false"> Cancel </el-button>
|
||||||
|
<el-button type="primary" @click="saveMQE"> Confirm </el-button>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -139,8 +182,10 @@ limitations under the License. -->
|
|||||||
import { saveFile, readFile } from "@/utils/file";
|
import { saveFile, readFile } from "@/utils/file";
|
||||||
import { EntityType } from "./data";
|
import { EntityType } from "./data";
|
||||||
import { isEmptyObject } from "@/utils/is";
|
import { isEmptyObject } from "@/utils/is";
|
||||||
|
import { WidgetType } from "@/views/dashboard/data";
|
||||||
|
import Metrics from "@/views/dashboard/related/topology/config/Metrics.vue";
|
||||||
|
|
||||||
/*global Nullable*/
|
/*global Nullable, Recordable*/
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const dashboardStore = useDashboardStore();
|
const dashboardStore = useDashboardStore();
|
||||||
const pageSize = 20;
|
const pageSize = 20;
|
||||||
@@ -152,6 +197,8 @@ limitations under the License. -->
|
|||||||
const multipleTableRef = ref<InstanceType<typeof ElTable>>();
|
const multipleTableRef = ref<InstanceType<typeof ElTable>>();
|
||||||
const multipleSelection = ref<DashboardItem[]>([]);
|
const multipleSelection = ref<DashboardItem[]>([]);
|
||||||
const dashboardFile = ref<Nullable<HTMLDivElement>>(null);
|
const dashboardFile = ref<Nullable<HTMLDivElement>>(null);
|
||||||
|
const MQEVisible = ref<boolean>(false);
|
||||||
|
const currentRow = ref<DashboardItem | Recordable>({});
|
||||||
|
|
||||||
const handleSelectionChange = (val: DashboardItem[]) => {
|
const handleSelectionChange = (val: DashboardItem[]) => {
|
||||||
multipleSelection.value = val;
|
multipleSelection.value = val;
|
||||||
@@ -161,8 +208,103 @@ limitations under the License. -->
|
|||||||
await dashboardStore.setDashboards();
|
await dashboardStore.setDashboards();
|
||||||
searchDashboards(1);
|
searchDashboards(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function changeExpressions(params: string[]) {
|
||||||
|
currentRow.value.expressions = params;
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateSettings(config: Record<string, never>) {
|
||||||
|
currentRow.value = {
|
||||||
|
...currentRow.value,
|
||||||
|
expressionsConfig: config.hierarchyServicesConfig,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleEditMQE(row: DashboardItem) {
|
||||||
|
MQEVisible.value = !MQEVisible.value;
|
||||||
|
currentRow.value = row;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function saveMQE() {
|
||||||
|
if (!currentRow.value.expressionsConfig) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const items: DashboardItem[] = [];
|
||||||
|
loading.value = true;
|
||||||
|
for (const d of dashboardStore.dashboards) {
|
||||||
|
if (d.id === currentRow.value.id) {
|
||||||
|
d.isDefault = currentRow.value.isDefault || false;
|
||||||
|
d.expressions = currentRow.value.expressions;
|
||||||
|
d.expressionsConfig = currentRow.value.expressionsConfig;
|
||||||
|
const key = [d.layer, d.entity, d.name].join("_");
|
||||||
|
const layout = sessionStorage.getItem(key) || "{}";
|
||||||
|
const c = {
|
||||||
|
...JSON.parse(layout).configuration,
|
||||||
|
...d,
|
||||||
|
};
|
||||||
|
delete c.id;
|
||||||
|
const setting = {
|
||||||
|
id: d.id,
|
||||||
|
configuration: JSON.stringify(c),
|
||||||
|
};
|
||||||
|
|
||||||
|
const res = await dashboardStore.updateDashboard(setting);
|
||||||
|
if (res.data.changeTemplate.status) {
|
||||||
|
sessionStorage.setItem(
|
||||||
|
key,
|
||||||
|
JSON.stringify({
|
||||||
|
id: d.id,
|
||||||
|
configuration: c,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
loading.value = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (
|
||||||
|
d.layer === currentRow.value.layer &&
|
||||||
|
[EntityType[0].value].includes(d.entity) &&
|
||||||
|
!currentRow.value.isDefault &&
|
||||||
|
d.isDefault
|
||||||
|
) {
|
||||||
|
d.isDefault = false;
|
||||||
|
const key = [d.layer, d.entity, d.name].join("_");
|
||||||
|
const layout = sessionStorage.getItem(key) || "{}";
|
||||||
|
const c = {
|
||||||
|
...JSON.parse(layout).configuration,
|
||||||
|
...d,
|
||||||
|
};
|
||||||
|
const setting = {
|
||||||
|
id: d.id,
|
||||||
|
configuration: JSON.stringify(c),
|
||||||
|
};
|
||||||
|
const res = await dashboardStore.updateDashboard(setting);
|
||||||
|
if (res.data.changeTemplate.status) {
|
||||||
|
sessionStorage.setItem(
|
||||||
|
key,
|
||||||
|
JSON.stringify({
|
||||||
|
id: d.id,
|
||||||
|
configuration: c,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
loading.value = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
items.push(d);
|
||||||
|
}
|
||||||
|
dashboardStore.resetDashboards(items);
|
||||||
|
searchDashboards(currentPage.value);
|
||||||
|
loading.value = false;
|
||||||
|
MQEVisible.value = false;
|
||||||
|
}
|
||||||
|
|
||||||
async function importTemplates(event: any) {
|
async function importTemplates(event: any) {
|
||||||
const arr: any = await readFile(event);
|
const arr: any = await readFile(event);
|
||||||
|
|
||||||
for (const item of arr) {
|
for (const item of arr) {
|
||||||
const { layer, name, entity } = item.configuration;
|
const { layer, name, entity } = item.configuration;
|
||||||
const index = dashboardStore.dashboards.findIndex(
|
const index = dashboardStore.dashboards.findIndex(
|
||||||
@@ -174,17 +316,19 @@ limitations under the License. -->
|
|||||||
}
|
}
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
for (const item of arr) {
|
for (const item of arr) {
|
||||||
const { layer, name, entity, isRoot, children } = item.configuration;
|
const { layer, name, entity, isRoot, children, isDefault, expressions, expressionsConfig } = item.configuration;
|
||||||
const index = dashboardStore.dashboards.findIndex((d: DashboardItem) => d.id === item.id);
|
const index = dashboardStore.dashboards.findIndex((d: DashboardItem) => d.id === item.id);
|
||||||
const p: DashboardItem = {
|
const p: DashboardItem = {
|
||||||
name: name.split(" ").join("-"),
|
name: name.split(" ").join("-"),
|
||||||
layer: layer,
|
layer: layer,
|
||||||
entity: entity,
|
entity: entity,
|
||||||
isRoot: false,
|
isRoot: isRoot || false,
|
||||||
|
isDefault: isDefault || false,
|
||||||
|
expressions: expressions,
|
||||||
|
expressionsConfig: expressionsConfig,
|
||||||
};
|
};
|
||||||
if (index > -1) {
|
if (index > -1) {
|
||||||
p.id = item.id;
|
p.id = item.id;
|
||||||
p.isRoot = isRoot;
|
|
||||||
}
|
}
|
||||||
dashboardStore.setCurrentDashboard(p);
|
dashboardStore.setCurrentDashboard(p);
|
||||||
dashboardStore.setLayout(children);
|
dashboardStore.setLayout(children);
|
||||||
@@ -193,6 +337,7 @@ limitations under the License. -->
|
|||||||
dashboards.value = dashboardStore.dashboards;
|
dashboards.value = dashboardStore.dashboards;
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
dashboardFile.value = null;
|
dashboardFile.value = null;
|
||||||
|
searchDashboards(currentPage.value);
|
||||||
}
|
}
|
||||||
function exportTemplates() {
|
function exportTemplates() {
|
||||||
if (!multipleSelection.value.length) {
|
if (!multipleSelection.value.length) {
|
||||||
@@ -207,6 +352,7 @@ limitations under the License. -->
|
|||||||
return layout;
|
return layout;
|
||||||
});
|
});
|
||||||
for (const item of templates) {
|
for (const item of templates) {
|
||||||
|
delete item.configuration.id;
|
||||||
optimizeTemplate(item.configuration.children);
|
optimizeTemplate(item.configuration.children);
|
||||||
}
|
}
|
||||||
const name = `dashboards.json`;
|
const name = `dashboards.json`;
|
||||||
@@ -215,6 +361,20 @@ limitations under the License. -->
|
|||||||
multipleTableRef.value!.clearSelection();
|
multipleTableRef.value!.clearSelection();
|
||||||
}, 2000);
|
}, 2000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function removeUnusedConfig(config: any) {
|
||||||
|
// remove `General` metrics config
|
||||||
|
delete config.metrics;
|
||||||
|
delete config.metricTypes;
|
||||||
|
delete config.metricMode;
|
||||||
|
delete config.linkServerMetrics;
|
||||||
|
delete config.linkClientMetrics;
|
||||||
|
delete config.nodeMetric;
|
||||||
|
if (([WidgetType.Topology] as string[]).includes(config.type)) {
|
||||||
|
delete config.legend;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function optimizeTemplate(
|
function optimizeTemplate(
|
||||||
children: (LayoutConfig & {
|
children: (LayoutConfig & {
|
||||||
moved?: boolean;
|
moved?: boolean;
|
||||||
@@ -232,6 +392,8 @@ limitations under the License. -->
|
|||||||
delete child.label;
|
delete child.label;
|
||||||
delete child.value;
|
delete child.value;
|
||||||
delete child.filters;
|
delete child.filters;
|
||||||
|
delete child.typesOfMQE;
|
||||||
|
delete child.subTypesOfMQE;
|
||||||
if (isEmptyObject(child.graph)) {
|
if (isEmptyObject(child.graph)) {
|
||||||
delete child.graph;
|
delete child.graph;
|
||||||
}
|
}
|
||||||
@@ -246,17 +408,8 @@ limitations under the License. -->
|
|||||||
if (isEmptyObject(child.widget)) {
|
if (isEmptyObject(child.widget)) {
|
||||||
delete child.widget;
|
delete child.widget;
|
||||||
}
|
}
|
||||||
if (!(child.metrics && child.metrics.length && child.metrics[0])) {
|
|
||||||
delete child.metrics;
|
|
||||||
}
|
|
||||||
if (!(child.metricTypes && child.metricTypes.length && child.metricTypes[0])) {
|
|
||||||
delete child.metricTypes;
|
|
||||||
}
|
|
||||||
if (child.metricConfig && child.metricConfig.length) {
|
if (child.metricConfig && child.metricConfig.length) {
|
||||||
child.metricConfig.forEach((c, index) => {
|
child.metricConfig.forEach((c, index) => {
|
||||||
if (!c.calculation) {
|
|
||||||
delete c.calculation;
|
|
||||||
}
|
|
||||||
if (!c.unit) {
|
if (!c.unit) {
|
||||||
delete c.unit;
|
delete c.unit;
|
||||||
}
|
}
|
||||||
@@ -271,12 +424,24 @@ limitations under the License. -->
|
|||||||
if (!(child.metricConfig && child.metricConfig.length)) {
|
if (!(child.metricConfig && child.metricConfig.length)) {
|
||||||
delete child.metricConfig;
|
delete child.metricConfig;
|
||||||
}
|
}
|
||||||
if (child.type === "Tab") {
|
removeUnusedConfig(child);
|
||||||
|
if (child.type === WidgetType.Tab) {
|
||||||
for (const item of child.children || []) {
|
for (const item of child.children || []) {
|
||||||
optimizeTemplate(item.children);
|
optimizeTemplate(item.children);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (["Trace", "Topology", "Tab", "Profile", "Ebpf", "Log"].includes(child.type)) {
|
if (
|
||||||
|
(
|
||||||
|
[
|
||||||
|
WidgetType.Trace,
|
||||||
|
WidgetType.Topology,
|
||||||
|
WidgetType.Tab,
|
||||||
|
WidgetType.Profile,
|
||||||
|
WidgetType.Ebpf,
|
||||||
|
WidgetType.Log,
|
||||||
|
] as string[]
|
||||||
|
).includes(child.type)
|
||||||
|
) {
|
||||||
delete child.widget;
|
delete child.widget;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -316,7 +481,7 @@ limitations under the License. -->
|
|||||||
configuration: JSON.stringify(c),
|
configuration: JSON.stringify(c),
|
||||||
};
|
};
|
||||||
const res = await dashboardStore.updateDashboard(setting);
|
const res = await dashboardStore.updateDashboard(setting);
|
||||||
if (res.data.changeTemplate.id) {
|
if (res.data.changeTemplate.status) {
|
||||||
sessionStorage.setItem(
|
sessionStorage.setItem(
|
||||||
key,
|
key,
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
@@ -324,6 +489,9 @@ limitations under the License. -->
|
|||||||
configuration: c,
|
configuration: c,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
} else {
|
||||||
|
loading.value = false;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (
|
if (
|
||||||
@@ -344,7 +512,7 @@ limitations under the License. -->
|
|||||||
configuration: JSON.stringify(c),
|
configuration: JSON.stringify(c),
|
||||||
};
|
};
|
||||||
const res = await dashboardStore.updateDashboard(setting);
|
const res = await dashboardStore.updateDashboard(setting);
|
||||||
if (res.data.changeTemplate.id) {
|
if (res.data.changeTemplate.status) {
|
||||||
sessionStorage.setItem(
|
sessionStorage.setItem(
|
||||||
key,
|
key,
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
@@ -352,15 +520,19 @@ limitations under the License. -->
|
|||||||
configuration: c,
|
configuration: c,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
} else {
|
||||||
|
loading.value = false;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
items.push(d);
|
items.push(d);
|
||||||
}
|
}
|
||||||
dashboardStore.resetDashboards(items);
|
dashboardStore.resetDashboards(items);
|
||||||
searchDashboards(1);
|
searchDashboards(currentPage.value);
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleRename(row: DashboardItem) {
|
function handleRename(row: DashboardItem) {
|
||||||
ElMessageBox.prompt("Please input dashboard name", "Edit", {
|
ElMessageBox.prompt("Please input dashboard name", "Edit", {
|
||||||
confirmButtonText: "OK",
|
confirmButtonText: "OK",
|
||||||
@@ -405,7 +577,7 @@ limitations under the License. -->
|
|||||||
...d,
|
...d,
|
||||||
name: value,
|
name: value,
|
||||||
});
|
});
|
||||||
dashboards.value = dashboardStore.dashboards.map((item: any) => {
|
dashboards.value = dashboardStore.dashboards.map((item: DashboardItem) => {
|
||||||
if (dashboardStore.currentDashboard.id === item.id) {
|
if (dashboardStore.currentDashboard.id === item.id) {
|
||||||
item = dashboardStore.currentDashboard;
|
item = dashboardStore.currentDashboard;
|
||||||
}
|
}
|
||||||
@@ -436,8 +608,9 @@ limitations under the License. -->
|
|||||||
loading.value = false;
|
loading.value = false;
|
||||||
sessionStorage.setItem("dashboards", JSON.stringify(dashboards.value));
|
sessionStorage.setItem("dashboards", JSON.stringify(dashboards.value));
|
||||||
sessionStorage.removeItem(`${row.layer}_${row.entity}_${row.name}`);
|
sessionStorage.removeItem(`${row.layer}_${row.entity}_${row.name}`);
|
||||||
|
searchDashboards(currentPage.value);
|
||||||
}
|
}
|
||||||
function searchDashboards(pageIndex?: any) {
|
function searchDashboards(pageIndex: number) {
|
||||||
const list = JSON.parse(sessionStorage.getItem("dashboards") || "[]");
|
const list = JSON.parse(sessionStorage.getItem("dashboards") || "[]");
|
||||||
const arr = list.filter((d: { name: string }) => d.name.includes(searchText.value));
|
const arr = list.filter((d: { name: string }) => d.name.includes(searchText.value));
|
||||||
|
|
||||||
@@ -520,4 +693,17 @@ limitations under the License. -->
|
|||||||
display: inline-block;
|
display: inline-block;
|
||||||
margin-left: 10px;
|
margin-left: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.placeholder {
|
||||||
|
display: inline-block;
|
||||||
|
width: 136px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.expressions {
|
||||||
|
height: 300px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.label {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@@ -15,9 +15,9 @@ limitations under the License. -->
|
|||||||
<template>
|
<template>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<span>{{ decodeURIComponent(title) }}</span>
|
<span>{{ title }}</span>
|
||||||
<div class="tips" v-show="tips">
|
<div class="tips" v-show="tips">
|
||||||
<el-tooltip :content="decodeURIComponent(tips) || ''">
|
<el-tooltip :content="tips || ''">
|
||||||
<span>
|
<span>
|
||||||
<Icon iconName="info_outline" size="sm" />
|
<Icon iconName="info_outline" size="sm" />
|
||||||
</span>
|
</span>
|
||||||
@@ -32,10 +32,7 @@ limitations under the License. -->
|
|||||||
:config="{
|
:config="{
|
||||||
i: 0,
|
i: 0,
|
||||||
...graph,
|
...graph,
|
||||||
metrics: config.metrics,
|
|
||||||
metricTypes: config.metricTypes,
|
|
||||||
metricConfig: config.metricConfig,
|
metricConfig: config.metricConfig,
|
||||||
metricMode: config.metricMode,
|
|
||||||
expressions: config.expressions || [],
|
expressions: config.expressions || [],
|
||||||
typesOfMQE: typesOfMQE || [],
|
typesOfMQE: typesOfMQE || [],
|
||||||
subExpressions: config.subExpressions || [],
|
subExpressions: config.subExpressions || [],
|
||||||
@@ -56,12 +53,10 @@ limitations under the License. -->
|
|||||||
import { useRoute } from "vue-router";
|
import { useRoute } from "vue-router";
|
||||||
import { useSelectorStore } from "@/store/modules/selectors";
|
import { useSelectorStore } from "@/store/modules/selectors";
|
||||||
import { useDashboardStore } from "@/store/modules/dashboard";
|
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||||
import { useQueryProcessor, useSourceProcessor } from "@/hooks/useMetricsProcessor";
|
import { useDashboardQueryProcessor } from "@/hooks/useExpressionsProcessor";
|
||||||
import { useExpressionsQueryProcessor } from "@/hooks/useExpressionsProcessor";
|
|
||||||
import graphs from "./graphs";
|
import graphs from "./graphs";
|
||||||
import { EntityType } from "./data";
|
import { EntityType } from "./data";
|
||||||
import timeFormat from "@/utils/timeFormat";
|
import timeFormat from "@/utils/timeFormat";
|
||||||
import { MetricModes } from "./data";
|
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: "WidgetPage",
|
name: "WidgetPage",
|
||||||
@@ -132,37 +127,20 @@ limitations under the License. -->
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
async function queryMetrics() {
|
async function queryMetrics() {
|
||||||
const isExpression = config.value.metricMode === MetricModes.Expression;
|
|
||||||
if (isExpression) {
|
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
const params = await useExpressionsQueryProcessor({
|
const metrics: { [key: string]: { source: { [key: string]: unknown }; typesOfMQE: string[] } } =
|
||||||
|
await useDashboardQueryProcessor([
|
||||||
|
{
|
||||||
metrics: config.value.expressions || [],
|
metrics: config.value.expressions || [],
|
||||||
metricConfig: config.value.metricConfig || [],
|
metricConfig: config.value.metricConfig || [],
|
||||||
subExpressions: config.value.subExpressions || [],
|
subExpressions: config.value.subExpressions || [],
|
||||||
});
|
id: config.value.i,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
const params = metrics[config.value.i];
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
source.value = params.source || {};
|
source.value = params.source || {};
|
||||||
typesOfMQE.value = params.typesOfMQE;
|
typesOfMQE.value = params.typesOfMQE;
|
||||||
return;
|
|
||||||
}
|
|
||||||
const params = await useQueryProcessor({ ...config.value });
|
|
||||||
if (!params) {
|
|
||||||
source.value = {};
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
loading.value = true;
|
|
||||||
const json = await dashboardStore.fetchMetricValue(params);
|
|
||||||
loading.value = false;
|
|
||||||
if (!json) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const d = {
|
|
||||||
metrics: config.value.metrics || [],
|
|
||||||
metricTypes: config.value.metricTypes || [],
|
|
||||||
metricConfig: config.value.metricConfig || [],
|
|
||||||
};
|
|
||||||
source.value = await useSourceProcessor(json, d);
|
|
||||||
}
|
}
|
||||||
watch(
|
watch(
|
||||||
() => appStoreWithOut.durationTime,
|
() => appStoreWithOut.durationTime,
|
||||||
@@ -209,7 +187,7 @@ limitations under the License. -->
|
|||||||
height: 25px;
|
height: 25px;
|
||||||
line-height: 25px;
|
line-height: 25px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
background-color: aliceblue;
|
background-color: var(--sw-config-header);
|
||||||
font-size: $font-size-smaller;
|
font-size: $font-size-smaller;
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
@@ -54,7 +54,6 @@ limitations under the License. -->
|
|||||||
import copy from "@/utils/copy";
|
import copy from "@/utils/copy";
|
||||||
import { RefreshOptions } from "@/views/dashboard/data";
|
import { RefreshOptions } from "@/views/dashboard/data";
|
||||||
import { TimeType } from "@/constants/data";
|
import { TimeType } from "@/constants/data";
|
||||||
import { MetricModes } from "../data";
|
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const appStore = useAppStoreWithOut();
|
const appStore = useAppStoreWithOut();
|
||||||
@@ -88,8 +87,7 @@ limitations under the License. -->
|
|||||||
step: appStore.durationRow.step,
|
step: appStore.durationRow.step,
|
||||||
utc: appStore.utc,
|
utc: appStore.utc,
|
||||||
});
|
});
|
||||||
const { widget, graph, metrics, metricTypes, metricConfig, metricMode, expressions, typesOfMQE, subExpressions } =
|
const { widget, graph, metricConfig, expressions, typesOfMQE, subExpressions } = dashboardStore.selectedGrid;
|
||||||
dashboardStore.selectedGrid;
|
|
||||||
const c = (metricConfig || []).map((d: any) => {
|
const c = (metricConfig || []).map((d: any) => {
|
||||||
const t: any = {};
|
const t: any = {};
|
||||||
if (d.label) {
|
if (d.label) {
|
||||||
@@ -103,20 +101,14 @@ limitations under the License. -->
|
|||||||
const opt: any = {
|
const opt: any = {
|
||||||
type: dashboardStore.selectedGrid.type,
|
type: dashboardStore.selectedGrid.type,
|
||||||
graph: graph,
|
graph: graph,
|
||||||
metricMode,
|
|
||||||
metricConfig: c,
|
metricConfig: c,
|
||||||
height: dashboardStore.selectedGrid.h * 20 + 60,
|
height: dashboardStore.selectedGrid.h * 20 + 60,
|
||||||
};
|
};
|
||||||
if (metricMode === MetricModes.Expression) {
|
|
||||||
opt.expressions = expressions;
|
opt.expressions = expressions;
|
||||||
opt.typesOfMQE = typesOfMQE;
|
opt.typesOfMQE = typesOfMQE;
|
||||||
if (subExpressions && subExpressions.length) {
|
if (subExpressions && subExpressions.length) {
|
||||||
opt.subExpressions = subExpressions;
|
opt.subExpressions = subExpressions;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
opt.metrics = metrics;
|
|
||||||
opt.metricTypes = metricTypes;
|
|
||||||
}
|
|
||||||
if (widget) {
|
if (widget) {
|
||||||
opt.widget = {
|
opt.widget = {
|
||||||
title: encodeURIComponent(widget.title || ""),
|
title: encodeURIComponent(widget.title || ""),
|
||||||
|
110
src/views/dashboard/configuration/Tab.vue
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
<!-- Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
contributor license agreements. See the NOTICE file distributed with
|
||||||
|
this work for additional information regarding copyright ownership.
|
||||||
|
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
(the "License"); you may not use this file except in compliance with
|
||||||
|
the License. You may obtain a copy of the License at
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License. -->
|
||||||
|
<template>
|
||||||
|
<div class="item">
|
||||||
|
<span class="label">{{ t("tabExpressions") }}</span>
|
||||||
|
<div class="mt-10" v-for="(child, index) in widgetTabs || []" :key="index">
|
||||||
|
<span class="name">{{ child.name }}</span>
|
||||||
|
<el-input class="input" size="small" v-model="expressions[child.name]" @change="changeExpression(child.name)" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="footer">
|
||||||
|
<el-button size="small" @click="cancelConfig">
|
||||||
|
{{ t("cancel") }}
|
||||||
|
</el-button>
|
||||||
|
<el-button size="small" type="primary" @click="applyConfig">
|
||||||
|
{{ t("apply") }}
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { useI18n } from "vue-i18n";
|
||||||
|
import { reactive, computed } from "vue";
|
||||||
|
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||||
|
import { ElMessage } from "element-plus";
|
||||||
|
import { WidgetType, ListEntity } from "@/views/dashboard/data";
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
const dashboardStore = useDashboardStore();
|
||||||
|
const originConfig = dashboardStore.selectedGrid;
|
||||||
|
const expressions = reactive<{ [key: string]: string }>({});
|
||||||
|
const widgetTabs = computed(() =>
|
||||||
|
(dashboardStore.selectedGrid.children || []).filter((child: any) =>
|
||||||
|
child.children.find(
|
||||||
|
(item: any) =>
|
||||||
|
item.type === WidgetType.Widget &&
|
||||||
|
!(Object.keys(ListEntity).includes(item.graph.type as string) && child.children.length === 1),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
for (const child of originConfig.children || []) {
|
||||||
|
expressions[child.name] = child.expression || "";
|
||||||
|
}
|
||||||
|
function changeExpression(name: string) {
|
||||||
|
if (expressions[name] && !expressions[name].includes("is_present")) {
|
||||||
|
ElMessage.error("Only support the is_present function");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const children = JSON.parse(JSON.stringify(dashboardStore.selectedGrid.children || []));
|
||||||
|
|
||||||
|
for (const item of children) {
|
||||||
|
if (item.name === name) {
|
||||||
|
item.expression = expressions[name];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dashboardStore.selectWidget({ ...dashboardStore.selectedGrid, children });
|
||||||
|
}
|
||||||
|
function applyConfig() {
|
||||||
|
dashboardStore.setConfigPanel(false);
|
||||||
|
dashboardStore.setConfigs(dashboardStore.selectedGrid);
|
||||||
|
}
|
||||||
|
|
||||||
|
function cancelConfig() {
|
||||||
|
dashboardStore.selectWidget(originConfig);
|
||||||
|
dashboardStore.setConfigPanel(false);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.label {
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 500;
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input {
|
||||||
|
width: 500px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer {
|
||||||
|
position: fixed;
|
||||||
|
bottom: 0;
|
||||||
|
right: 0;
|
||||||
|
border-top: 1px solid $border-color-primary;
|
||||||
|
padding: 10px;
|
||||||
|
text-align: right;
|
||||||
|
width: 100%;
|
||||||
|
background-color: $theme-background;
|
||||||
|
}
|
||||||
|
|
||||||
|
.name {
|
||||||
|
width: 180px;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
</style>
|
@@ -34,11 +34,8 @@ limitations under the License. -->
|
|||||||
...graph,
|
...graph,
|
||||||
legend: (dashboardStore.selectedGrid.graph || {}).legend,
|
legend: (dashboardStore.selectedGrid.graph || {}).legend,
|
||||||
i: dashboardStore.selectedGrid.i,
|
i: dashboardStore.selectedGrid.i,
|
||||||
metrics: dashboardStore.selectedGrid.metrics,
|
|
||||||
metricTypes: dashboardStore.selectedGrid.metricTypes,
|
|
||||||
metricConfig: dashboardStore.selectedGrid.metricConfig,
|
metricConfig: dashboardStore.selectedGrid.metricConfig,
|
||||||
relatedTrace: dashboardStore.selectedGrid.relatedTrace,
|
relatedTrace: dashboardStore.selectedGrid.relatedTrace,
|
||||||
metricMode: dashboardStore.selectedGrid.metricMode,
|
|
||||||
expressions: dashboardStore.selectedGrid.expressions || [],
|
expressions: dashboardStore.selectedGrid.expressions || [],
|
||||||
typesOfMQE: dashboardStore.selectedGrid.typesOfMQE || [],
|
typesOfMQE: dashboardStore.selectedGrid.typesOfMQE || [],
|
||||||
subExpressions: dashboardStore.selectedGrid.subExpressions || [],
|
subExpressions: dashboardStore.selectedGrid.subExpressions || [],
|
||||||
@@ -89,7 +86,6 @@ limitations under the License. -->
|
|||||||
import type { Option } from "@/types/app";
|
import type { Option } from "@/types/app";
|
||||||
import graphs from "../graphs";
|
import graphs from "../graphs";
|
||||||
import CustomOptions from "./widget/index";
|
import CustomOptions from "./widget/index";
|
||||||
import { MetricModes } from "../data";
|
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: "WidgetEdit",
|
name: "WidgetEdit",
|
||||||
@@ -142,23 +138,6 @@ limitations under the License. -->
|
|||||||
|
|
||||||
function applyConfig() {
|
function applyConfig() {
|
||||||
dashboardStore.setConfigPanel(false);
|
dashboardStore.setConfigPanel(false);
|
||||||
const { metricMode } = dashboardStore.selectedGrid;
|
|
||||||
let p = {};
|
|
||||||
if (metricMode === MetricModes.Expression) {
|
|
||||||
p = {
|
|
||||||
metrics: [],
|
|
||||||
metricTypes: [],
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
p = {
|
|
||||||
expressions: [],
|
|
||||||
typesOfMQE: [],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
dashboardStore.selectWidget({
|
|
||||||
...dashboardStore.selectedGrid,
|
|
||||||
...p,
|
|
||||||
});
|
|
||||||
dashboardStore.setConfigs(dashboardStore.selectedGrid);
|
dashboardStore.setConfigs(dashboardStore.selectedGrid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -22,8 +22,10 @@ import Event from "./Event.vue";
|
|||||||
import TimeRange from "./TimeRange.vue";
|
import TimeRange from "./TimeRange.vue";
|
||||||
import ThirdPartyApp from "./ThirdPartyApp.vue";
|
import ThirdPartyApp from "./ThirdPartyApp.vue";
|
||||||
import ContinuousProfiling from "./ContinuousProfiling.vue";
|
import ContinuousProfiling from "./ContinuousProfiling.vue";
|
||||||
|
import Tab from "./Tab.vue";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
Tab,
|
||||||
Text,
|
Text,
|
||||||
Widget,
|
Widget,
|
||||||
Topology,
|
Topology,
|
||||||
|
@@ -22,16 +22,6 @@ limitations under the License. -->
|
|||||||
@change="updateConfig({ showTableValues })"
|
@change="updateConfig({ showTableValues })"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="item">
|
|
||||||
<span class="label">{{ t("tableHeaderCol1") }}</span>
|
|
||||||
<el-input
|
|
||||||
class="input"
|
|
||||||
v-model="tableHeaderCol1"
|
|
||||||
size="small"
|
|
||||||
placeholder="none"
|
|
||||||
@change="updateConfig({ tableHeaderCol1 })"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div class="item">
|
<div class="item">
|
||||||
<span class="label">{{ t("tableHeaderCol2") }}</span>
|
<span class="label">{{ t("tableHeaderCol2") }}</span>
|
||||||
<el-input
|
<el-input
|
||||||
@@ -52,7 +42,6 @@ limitations under the License. -->
|
|||||||
const dashboardStore = useDashboardStore();
|
const dashboardStore = useDashboardStore();
|
||||||
const graph = dashboardStore.selectedGrid.graph || {};
|
const graph = dashboardStore.selectedGrid.graph || {};
|
||||||
const showTableValues = ref(graph.showTableValues);
|
const showTableValues = ref(graph.showTableValues);
|
||||||
const tableHeaderCol1 = ref(graph.tableHeaderCol1);
|
|
||||||
const tableHeaderCol2 = ref(graph.tableHeaderCol2);
|
const tableHeaderCol2 = ref(graph.tableHeaderCol2);
|
||||||
|
|
||||||
function updateConfig(param: { [key: string]: unknown }) {
|
function updateConfig(param: { [key: string]: unknown }) {
|
||||||
|
@@ -25,28 +25,20 @@ limitations under the License. -->
|
|||||||
:clearable="true"
|
:clearable="true"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>{{ t("metrics") }}</div>
|
|
||||||
<div class="flex-h">
|
<div class="flex-h">
|
||||||
<el-switch
|
<div>{{ t("metrics") }}</div>
|
||||||
v-model="isExpression"
|
<div class="link">
|
||||||
class="mb-5"
|
|
||||||
active-text="Expressions"
|
|
||||||
inactive-text="General"
|
|
||||||
size="small"
|
|
||||||
@change="changeMetricMode"
|
|
||||||
/>
|
|
||||||
<div class="ml-5 link">
|
|
||||||
<a target="_blank" href="https://skywalking.apache.org/docs/main/next/en/api/metrics-query-expression/">
|
<a target="_blank" href="https://skywalking.apache.org/docs/main/next/en/api/metrics-query-expression/">
|
||||||
<Icon iconName="info_outline" size="middle" />
|
<Icon iconName="info_outline" size="middle" />
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="isExpression && states.isList">
|
<div v-if="states.isList">
|
||||||
<span class="title">{{ t("summary") }}</span>
|
<span class="title">{{ t("summary") }}</span>
|
||||||
<span>{{ t("detail") }}</span>
|
<span>{{ t("detail") }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div v-for="(metric, index) in states.metrics" :key="index" class="mb-10">
|
<div v-for="(metric, index) in states.metrics" :key="index" class="mb-10">
|
||||||
<span v-if="isExpression">
|
<span>
|
||||||
<div class="expression-param" contenteditable="true" @blur="changeExpression($event, index)">
|
<div class="expression-param" contenteditable="true" @blur="changeExpression($event, index)">
|
||||||
{{ metric }}
|
{{ metric }}
|
||||||
</div>
|
</div>
|
||||||
@@ -59,24 +51,6 @@ limitations under the License. -->
|
|||||||
{{ states.subMetrics[index] }}
|
{{ states.subMetrics[index] }}
|
||||||
</div>
|
</div>
|
||||||
</span>
|
</span>
|
||||||
<span v-else>
|
|
||||||
<Selector
|
|
||||||
:value="metric"
|
|
||||||
:options="states.metricList"
|
|
||||||
size="small"
|
|
||||||
placeholder="Select a metric"
|
|
||||||
@change="changeMetrics(index, $event)"
|
|
||||||
class="selectors"
|
|
||||||
/>
|
|
||||||
<Selector
|
|
||||||
:value="states.metricTypes[index]"
|
|
||||||
:options="states.metricTypeList[index]"
|
|
||||||
size="small"
|
|
||||||
:disabled="graph.type && !states.isList && index !== 0"
|
|
||||||
@change="changeMetricType(index, $event)"
|
|
||||||
class="selectors"
|
|
||||||
/>
|
|
||||||
</span>
|
|
||||||
<el-popover placement="top" :width="400" trigger="click">
|
<el-popover placement="top" :width="400" trigger="click">
|
||||||
<template #reference>
|
<template #reference>
|
||||||
<span @click="setMetricConfig(index)">
|
<span @click="setMetricConfig(index)">
|
||||||
@@ -88,7 +62,7 @@ limitations under the License. -->
|
|||||||
<span
|
<span
|
||||||
v-show="
|
v-show="
|
||||||
states.isList ||
|
states.isList ||
|
||||||
[ProtocolTypes.ReadMetricsValues, ExpressionResultType.TIME_SERIES_VALUES as string].includes(states.metricTypes[0])
|
[ExpressionResultType.TIME_SERIES_VALUES as string].includes(states.metricTypes[0])
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
<Icon
|
<Icon
|
||||||
@@ -100,13 +74,13 @@ limitations under the License. -->
|
|||||||
/>
|
/>
|
||||||
<Icon class="cp" iconName="remove_circle_outline" size="middle" @click="deleteMetric(index)" />
|
<Icon class="cp" iconName="remove_circle_outline" size="middle" @click="deleteMetric(index)" />
|
||||||
</span>
|
</span>
|
||||||
<div v-if="(states.tips || [])[index] && isExpression" class="ml-10 red sm">
|
<div v-if="(states.tips || [])[index]" class="ml-10 red sm">
|
||||||
{{ states.tips[index] }}
|
{{ states.tips[index] }}
|
||||||
</div>
|
</div>
|
||||||
<div v-if="(errors || [])[index] && isExpression" class="ml-10 red sm">
|
<div v-if="(errors || [])[index]" class="ml-10 red sm">
|
||||||
{{ (errors || [])[index] }}
|
{{ (errors || [])[index] }}
|
||||||
</div>
|
</div>
|
||||||
<div v-if="(subErrors || [])[index] && isExpression" class="ml-10 red sm">
|
<div v-if="(subErrors || [])[index]" class="ml-10 red sm">
|
||||||
{{ (subErrors || [])[index] }}
|
{{ (subErrors || [])[index] }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -128,21 +102,15 @@ limitations under the License. -->
|
|||||||
import type { Option } from "@/types/app";
|
import type { Option } from "@/types/app";
|
||||||
import { useDashboardStore } from "@/store/modules/dashboard";
|
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||||
import {
|
import {
|
||||||
MetricTypes,
|
|
||||||
ListChartTypes,
|
ListChartTypes,
|
||||||
DefaultGraphConfig,
|
DefaultGraphConfig,
|
||||||
EntityType,
|
EntityType,
|
||||||
ChartTypes,
|
ChartTypes,
|
||||||
PodsChartTypes,
|
PodsChartTypes,
|
||||||
MetricsType,
|
|
||||||
ProtocolTypes,
|
|
||||||
ExpressionResultType,
|
ExpressionResultType,
|
||||||
MetricModes,
|
} from "@/views/dashboard/data";
|
||||||
} from "../../../data";
|
|
||||||
import { ElMessage } from "element-plus";
|
|
||||||
import Icon from "@/components/Icon.vue";
|
import Icon from "@/components/Icon.vue";
|
||||||
import { useQueryProcessor, useSourceProcessor } from "@/hooks/useMetricsProcessor";
|
import { useDashboardQueryProcessor } from "@/hooks/useExpressionsProcessor";
|
||||||
import { useExpressionsQueryProcessor } from "@/hooks/useExpressionsProcessor";
|
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
import type { DashboardItem, MetricConfigOpt } from "@/types/dashboard";
|
import type { DashboardItem, MetricConfigOpt } from "@/types/dashboard";
|
||||||
import Standard from "./Standard.vue";
|
import Standard from "./Standard.vue";
|
||||||
@@ -160,16 +128,11 @@ limitations under the License. -->
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
const dashboardStore = useDashboardStore();
|
const dashboardStore = useDashboardStore();
|
||||||
const isExpression = ref<boolean>(dashboardStore.selectedGrid.metricMode === MetricModes.Expression);
|
const metrics = computed(() => dashboardStore.selectedGrid.expressions || []);
|
||||||
const metrics = computed(
|
const subMetrics = computed(() => dashboardStore.selectedGrid.subExpressions || []);
|
||||||
() => (isExpression.value ? dashboardStore.selectedGrid.expressions : dashboardStore.selectedGrid.metrics) || [],
|
const subMetricTypes = computed(() => dashboardStore.selectedGrid.subTypesOfMQE || []);
|
||||||
);
|
|
||||||
const subMetrics = computed(() => (isExpression.value ? dashboardStore.selectedGrid.subExpressions : []) || []);
|
|
||||||
const subMetricTypes = computed(() => (isExpression.value ? dashboardStore.selectedGrid.subTypesOfMQE : []) || []);
|
|
||||||
const graph = computed(() => dashboardStore.selectedGrid.graph || {});
|
const graph = computed(() => dashboardStore.selectedGrid.graph || {});
|
||||||
const metricTypes = computed(
|
const typesOfMQE = computed(() => dashboardStore.selectedGrid.typesOfMQE || []);
|
||||||
() => (isExpression.value ? dashboardStore.selectedGrid.typesOfMQE : dashboardStore.selectedGrid.metricTypes) || [],
|
|
||||||
);
|
|
||||||
const states = reactive<{
|
const states = reactive<{
|
||||||
metrics: string[];
|
metrics: string[];
|
||||||
subMetrics: string[];
|
subMetrics: string[];
|
||||||
@@ -177,17 +140,15 @@ limitations under the License. -->
|
|||||||
metricTypes: string[];
|
metricTypes: string[];
|
||||||
metricTypeList: Option[][];
|
metricTypeList: Option[][];
|
||||||
isList: boolean;
|
isList: boolean;
|
||||||
metricList: (Option & { type: string })[];
|
|
||||||
dashboardName: string;
|
dashboardName: string;
|
||||||
dashboardList: ((DashboardItem & { label: string; value: string }) | any)[];
|
dashboardList: ((DashboardItem & { label: string; value: string }) | any)[];
|
||||||
tips: string[];
|
tips: string[];
|
||||||
subTips: string[];
|
subTips: string[];
|
||||||
}>({
|
}>({
|
||||||
metrics: metrics.value.length ? metrics.value : [""],
|
metrics: metrics.value.length ? metrics.value : [""],
|
||||||
metricTypes: metricTypes.value.length ? metricTypes.value : [""],
|
metricTypes: typesOfMQE.value.length ? typesOfMQE.value : [""],
|
||||||
metricTypeList: [],
|
metricTypeList: [],
|
||||||
isList: false,
|
isList: false,
|
||||||
metricList: [],
|
|
||||||
dashboardName: graph.value.dashboardName,
|
dashboardName: graph.value.dashboardName,
|
||||||
dashboardList: [{ label: "", value: "" }],
|
dashboardList: [{ label: "", value: "" }],
|
||||||
tips: [],
|
tips: [],
|
||||||
@@ -199,16 +160,13 @@ limitations under the License. -->
|
|||||||
unit: "",
|
unit: "",
|
||||||
label: "",
|
label: "",
|
||||||
labelsIndex: "",
|
labelsIndex: "",
|
||||||
calculation: "",
|
|
||||||
sortOrder: "DES",
|
sortOrder: "DES",
|
||||||
});
|
});
|
||||||
|
|
||||||
states.isList = ListChartTypes.includes(graph.value.type);
|
states.isList = ListChartTypes.includes(graph.value.type);
|
||||||
const defaultLen = ref<number>(states.isList ? 5 : 20);
|
const defaultLen = ref<number>(states.isList ? 5 : 20);
|
||||||
const backupMetricConfig = ref<MetricConfigOpt[]>([]);
|
|
||||||
|
|
||||||
setDashboards();
|
setDashboards();
|
||||||
setMetricType();
|
|
||||||
|
|
||||||
const setVisTypes = computed(() => {
|
const setVisTypes = computed(() => {
|
||||||
let graphs = [];
|
let graphs = [];
|
||||||
@@ -223,70 +181,6 @@ limitations under the License. -->
|
|||||||
return graphs;
|
return graphs;
|
||||||
});
|
});
|
||||||
|
|
||||||
async function setMetricType(chart?: any) {
|
|
||||||
const g = chart || dashboardStore.selectedGrid.graph || {};
|
|
||||||
let arr: any[] = states.metricList;
|
|
||||||
if (!chart) {
|
|
||||||
const json = await dashboardStore.fetchMetricList();
|
|
||||||
if (json.errors) {
|
|
||||||
ElMessage.error(json.errors);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
arr = json.data.metrics;
|
|
||||||
}
|
|
||||||
states.metricList = (arr || []).filter((d: { type: string }) => {
|
|
||||||
if (states.isList) {
|
|
||||||
if (d.type === MetricsType.REGULAR_VALUE || d.type === MetricsType.LABELED_VALUE) {
|
|
||||||
return d;
|
|
||||||
}
|
|
||||||
} else if (g.type === "Table") {
|
|
||||||
if (d.type === MetricsType.LABELED_VALUE || d.type === MetricsType.REGULAR_VALUE) {
|
|
||||||
return d;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return d;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (isExpression.value) {
|
|
||||||
if (states.metrics && states.metrics[0]) {
|
|
||||||
queryMetrics();
|
|
||||||
} else {
|
|
||||||
emit("update", {});
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const metrics: any = states.metricList.filter((d: { value: string; type: string }) =>
|
|
||||||
states.metrics.includes(d.value),
|
|
||||||
);
|
|
||||||
|
|
||||||
if (metrics.length) {
|
|
||||||
// keep states.metrics index
|
|
||||||
const m = metrics.map((d: { value: string }) => d.value);
|
|
||||||
states.metrics = states.metrics.filter((d) => m.includes(d));
|
|
||||||
} else {
|
|
||||||
states.metrics = [""];
|
|
||||||
states.metricTypes = [""];
|
|
||||||
}
|
|
||||||
dashboardStore.selectWidget({
|
|
||||||
...dashboardStore.selectedGrid,
|
|
||||||
metrics: states.metrics,
|
|
||||||
metricTypes: states.metricTypes,
|
|
||||||
graph: g,
|
|
||||||
});
|
|
||||||
states.metricTypeList = [];
|
|
||||||
for (const metric of metrics) {
|
|
||||||
if (states.metrics.includes(metric.value)) {
|
|
||||||
const arr = setMetricTypeList(metric.type);
|
|
||||||
states.metricTypeList.push(arr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (states.metrics && states.metrics[0]) {
|
|
||||||
queryMetrics();
|
|
||||||
} else {
|
|
||||||
emit("update", {});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function setDashboards(type?: string) {
|
function setDashboards(type?: string) {
|
||||||
const chart = type || (dashboardStore.selectedGrid.graph && dashboardStore.selectedGrid.graph.type);
|
const chart = type || (dashboardStore.selectedGrid.graph && dashboardStore.selectedGrid.graph.type);
|
||||||
const list = JSON.parse(sessionStorage.getItem("dashboards") || "[]");
|
const list = JSON.parse(sessionStorage.getItem("dashboards") || "[]");
|
||||||
@@ -308,6 +202,11 @@ limitations under the License. -->
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
states.dashboardList = arr.length ? arr : [{ label: "", value: "" }];
|
states.dashboardList = arr.length ? arr : [{ label: "", value: "" }];
|
||||||
|
if (states.metrics && states.metrics[0]) {
|
||||||
|
queryMetrics();
|
||||||
|
} else {
|
||||||
|
emit("update", {});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function changeChartType(item: Option) {
|
function changeChartType(item: Option) {
|
||||||
@@ -316,8 +215,6 @@ limitations under the License. -->
|
|||||||
if (states.isList) {
|
if (states.isList) {
|
||||||
dashboardStore.selectWidget({
|
dashboardStore.selectWidget({
|
||||||
...dashboardStore.selectedGrid,
|
...dashboardStore.selectedGrid,
|
||||||
metrics: [""],
|
|
||||||
metricTypes: [""],
|
|
||||||
expressions: [""],
|
expressions: [""],
|
||||||
typesOfMQE: [""],
|
typesOfMQE: [""],
|
||||||
});
|
});
|
||||||
@@ -326,113 +223,36 @@ limitations under the License. -->
|
|||||||
defaultLen.value = 5;
|
defaultLen.value = 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isExpression.value) {
|
|
||||||
dashboardStore.selectWidget({
|
dashboardStore.selectWidget({
|
||||||
...dashboardStore.selectedGrid,
|
...dashboardStore.selectedGrid,
|
||||||
graph: chart,
|
graph: chart,
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
setMetricType(chart);
|
|
||||||
}
|
|
||||||
setDashboards(chart.type);
|
setDashboards(chart.type);
|
||||||
states.dashboardName = "";
|
states.dashboardName = "";
|
||||||
defaultLen.value = 10;
|
defaultLen.value = 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
function changeMetrics(index: number, arr: (Option & { type: string })[] | any) {
|
|
||||||
if (!arr.length) {
|
|
||||||
states.metricTypeList = [];
|
|
||||||
states.metricTypes = [];
|
|
||||||
dashboardStore.selectWidget({
|
|
||||||
...dashboardStore.selectedGrid,
|
|
||||||
...{ metricTypes: states.metricTypes, metrics: states.metrics },
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
states.metrics[index] = arr[0].value;
|
|
||||||
const typeOfMetrics = arr[0].type;
|
|
||||||
|
|
||||||
states.metricTypeList[index] = setMetricTypeList(typeOfMetrics);
|
|
||||||
states.metricTypes[index] = MetricTypes[typeOfMetrics][0].value;
|
|
||||||
dashboardStore.selectWidget({
|
|
||||||
...dashboardStore.selectedGrid,
|
|
||||||
...{ metricTypes: states.metricTypes, metrics: states.metrics },
|
|
||||||
});
|
|
||||||
if (states.isList) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
queryMetrics();
|
|
||||||
}
|
|
||||||
|
|
||||||
function changeMetricType(index: number, opt: Option[] | any) {
|
|
||||||
const metric = states.metricList.filter((d: Option) => states.metrics[index] === d.value)[0] || {};
|
|
||||||
const l = setMetricTypeList(metric.type);
|
|
||||||
if (states.isList) {
|
|
||||||
states.metricTypes[index] = opt[0].value;
|
|
||||||
states.metricTypeList[index] = l;
|
|
||||||
} else {
|
|
||||||
states.metricTypes = states.metricTypes.map((d: string) => {
|
|
||||||
d = opt[0].value;
|
|
||||||
return d;
|
|
||||||
});
|
|
||||||
states.metricTypeList = states.metricTypeList.map((d: Option[]) => {
|
|
||||||
d = l;
|
|
||||||
|
|
||||||
return d;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
dashboardStore.selectWidget({
|
|
||||||
...dashboardStore.selectedGrid,
|
|
||||||
...{ metricTypes: states.metricTypes },
|
|
||||||
});
|
|
||||||
if (states.isList) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
queryMetrics();
|
|
||||||
}
|
|
||||||
async function queryMetrics() {
|
async function queryMetrics() {
|
||||||
if (states.isList) {
|
if (states.isList) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (isExpression.value) {
|
|
||||||
queryMetricsWithExpressions();
|
queryMetricsWithExpressions();
|
||||||
return;
|
|
||||||
}
|
|
||||||
const { metricConfig, metricTypes, metrics } = dashboardStore.selectedGrid;
|
|
||||||
if (!(metrics && metrics[0] && metricTypes && metricTypes[0])) {
|
|
||||||
return emit("update", {});
|
|
||||||
}
|
|
||||||
const params = useQueryProcessor({ ...states, metricConfig });
|
|
||||||
if (!params) {
|
|
||||||
emit("update", {});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
emit("loading", true);
|
|
||||||
const json = await dashboardStore.fetchMetricValue(params);
|
|
||||||
emit("loading", false);
|
|
||||||
if (json.errors) {
|
|
||||||
ElMessage.error(json.errors);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const source = useSourceProcessor(json, { ...states, metricConfig });
|
|
||||||
emit("update", source);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function queryMetricsWithExpressions() {
|
async function queryMetricsWithExpressions() {
|
||||||
const { expressions, metricConfig } = dashboardStore.selectedGrid;
|
const { expressions, metricConfig, i } = dashboardStore.selectedGrid;
|
||||||
if (!(expressions && expressions[0])) {
|
if (!(expressions && expressions[0])) {
|
||||||
return emit("update", {});
|
return emit("update", {});
|
||||||
}
|
}
|
||||||
|
|
||||||
const params: Indexable = (await useExpressionsQueryProcessor({ ...states, metricConfig })) || {};
|
const metrics: Indexable = (await useDashboardQueryProcessor([{ ...states, metricConfig, id: i }])) || {};
|
||||||
|
const params = metrics[i];
|
||||||
states.tips = params.tips || [];
|
states.tips = params.tips || [];
|
||||||
states.metricTypes = params.typesOfMQE || [];
|
states.metricTypes = params.typesOfMQE || [];
|
||||||
dashboardStore.selectWidget({
|
dashboardStore.selectWidget({
|
||||||
...dashboardStore.selectedGrid,
|
...dashboardStore.selectedGrid,
|
||||||
typesOfMQE: states.metricTypes,
|
typesOfMQE: states.metricTypes,
|
||||||
});
|
});
|
||||||
|
|
||||||
emit("update", params.source || {});
|
emit("update", params.source || {});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -454,31 +274,23 @@ limitations under the License. -->
|
|||||||
function addMetric() {
|
function addMetric() {
|
||||||
states.metrics.push("");
|
states.metrics.push("");
|
||||||
states.tips.push("");
|
states.tips.push("");
|
||||||
if (isExpression.value && states.isList) {
|
if (states.isList) {
|
||||||
states.subMetrics.push("");
|
states.subMetrics.push("");
|
||||||
states.subTips.push("");
|
states.subTips.push("");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!states.isList) {
|
if (!states.isList) {
|
||||||
states.metricTypes.push(states.metricTypes[0]);
|
states.metricTypes.push(states.metricTypes[0]);
|
||||||
if (!isExpression.value) {
|
|
||||||
states.metricTypeList.push(states.metricTypeList[0]);
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
states.metricTypes.push("");
|
states.metricTypes.push("");
|
||||||
if (isExpression.value && states.isList) {
|
|
||||||
states.subMetricTypes.push("");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
function deleteMetric(index: number) {
|
function deleteMetric(index: number) {
|
||||||
if (states.metrics.length === 1) {
|
if (states.metrics.length === 1) {
|
||||||
states.metrics = [""];
|
states.metrics = [""];
|
||||||
states.metricTypes = [""];
|
states.metricTypes = [""];
|
||||||
states.tips = [""];
|
states.tips = [""];
|
||||||
let v = {};
|
let v: any = { typesOfMQE: states.metricTypes, expressions: states.metrics };
|
||||||
if (isExpression.value) {
|
|
||||||
v = { typesOfMQE: states.metricTypes, expressions: states.metrics };
|
|
||||||
if (states.isList) {
|
if (states.isList) {
|
||||||
states.subMetrics = [""];
|
states.subMetrics = [""];
|
||||||
states.subMetricTypes = [""];
|
states.subMetricTypes = [""];
|
||||||
@@ -489,9 +301,6 @@ limitations under the License. -->
|
|||||||
subExpressions: states.subMetrics,
|
subExpressions: states.subMetrics,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
v = { metricTypes: states.metricTypes, metrics: states.metrics };
|
|
||||||
}
|
|
||||||
dashboardStore.selectWidget({
|
dashboardStore.selectWidget({
|
||||||
...dashboardStore.selectedGrid,
|
...dashboardStore.selectedGrid,
|
||||||
...v,
|
...v,
|
||||||
@@ -505,7 +314,6 @@ limitations under the License. -->
|
|||||||
const config = dashboardStore.selectedGrid.metricConfig || [];
|
const config = dashboardStore.selectedGrid.metricConfig || [];
|
||||||
const metricConfig = config[index] ? config.splice(index, 1) : config;
|
const metricConfig = config[index] ? config.splice(index, 1) : config;
|
||||||
let p = {};
|
let p = {};
|
||||||
if (isExpression.value) {
|
|
||||||
if (states.isList) {
|
if (states.isList) {
|
||||||
states.subMetrics.splice(index, 1);
|
states.subMetrics.splice(index, 1);
|
||||||
states.subMetricTypes.splice(index, 1);
|
states.subMetricTypes.splice(index, 1);
|
||||||
@@ -518,24 +326,14 @@ limitations under the License. -->
|
|||||||
subExpressions: states.subMetrics,
|
subExpressions: states.subMetrics,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
p = { metricTypes: states.metricTypes, metrics: states.metrics };
|
|
||||||
}
|
|
||||||
dashboardStore.selectWidget({
|
dashboardStore.selectWidget({
|
||||||
...dashboardStore.selectedGrid,
|
...dashboardStore.selectedGrid,
|
||||||
...p,
|
...p,
|
||||||
metricConfig,
|
metricConfig,
|
||||||
});
|
});
|
||||||
|
queryMetrics();
|
||||||
}
|
}
|
||||||
function setMetricTypeList(type: string) {
|
|
||||||
if (type !== MetricsType.REGULAR_VALUE) {
|
|
||||||
return MetricTypes[type];
|
|
||||||
}
|
|
||||||
if (states.isList || graph.value.type === "Table") {
|
|
||||||
return [MetricTypes.REGULAR_VALUE[0], MetricTypes.REGULAR_VALUE[1]];
|
|
||||||
}
|
|
||||||
return MetricTypes[type];
|
|
||||||
}
|
|
||||||
function setMetricConfig(index: number) {
|
function setMetricConfig(index: number) {
|
||||||
const n = {
|
const n = {
|
||||||
unit: "",
|
unit: "",
|
||||||
@@ -553,20 +351,6 @@ limitations under the License. -->
|
|||||||
...dashboardStore.selectedGrid.metricConfig[index],
|
...dashboardStore.selectedGrid.metricConfig[index],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
function changeMetricMode() {
|
|
||||||
states.metrics = metrics.value.length ? metrics.value : [""];
|
|
||||||
states.subMetrics = subMetrics.value.length ? subMetrics.value : [""];
|
|
||||||
states.metricTypes = metricTypes.value.length ? metricTypes.value : [""];
|
|
||||||
states.subMetricTypes = subMetricTypes.value.length ? subMetricTypes.value : [""];
|
|
||||||
const config = dashboardStore.selectedGrid.metricConfig;
|
|
||||||
dashboardStore.selectWidget({
|
|
||||||
...dashboardStore.selectedGrid,
|
|
||||||
metricMode: isExpression.value ? MetricModes.Expression : MetricModes.General,
|
|
||||||
metricConfig: backupMetricConfig.value,
|
|
||||||
});
|
|
||||||
backupMetricConfig.value = config;
|
|
||||||
queryMetrics();
|
|
||||||
}
|
|
||||||
async function changeExpression(event: any, index: number) {
|
async function changeExpression(event: any, index: number) {
|
||||||
const params = (event.target.textContent || "").replace(/\s+/g, "");
|
const params = (event.target.textContent || "").replace(/\s+/g, "");
|
||||||
|
|
||||||
@@ -651,5 +435,6 @@ limitations under the License. -->
|
|||||||
.link {
|
.link {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
color: $active-color;
|
color: $active-color;
|
||||||
|
padding-left: 2px;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@@ -28,7 +28,7 @@ limitations under the License. -->
|
|||||||
"
|
"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="item mb-10" v-if="hasLabel || isExpression">
|
<div class="item mb-10">
|
||||||
<span class="label">{{ t("labels") }}</span>
|
<span class="label">{{ t("labels") }}</span>
|
||||||
<el-input
|
<el-input
|
||||||
class="input"
|
class="input"
|
||||||
@@ -42,7 +42,7 @@ limitations under the License. -->
|
|||||||
"
|
"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="item mb-10" v-if="isList && isExpression">
|
<div class="item mb-10" v-if="isList">
|
||||||
<span class="label">{{ t("detailLabel") }}</span>
|
<span class="label">{{ t("detailLabel") }}</span>
|
||||||
<el-input
|
<el-input
|
||||||
class="input"
|
class="input"
|
||||||
@@ -56,30 +56,6 @@ limitations under the License. -->
|
|||||||
"
|
"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="item mb-10" v-if="[ProtocolTypes.ReadLabeledMetricsValues].includes(metricType) && !isExpression">
|
|
||||||
<span class="label">{{ t("labelsIndex") }}</span>
|
|
||||||
<el-input
|
|
||||||
class="input"
|
|
||||||
v-model="currentMetric.labelsIndex"
|
|
||||||
size="small"
|
|
||||||
placeholder="auto"
|
|
||||||
@change="
|
|
||||||
updateConfig(index, {
|
|
||||||
labelsIndex: encodeURIComponent(currentMetric.labelsIndex || ''),
|
|
||||||
})
|
|
||||||
"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div class="item mb-10" v-show="!isExpression">
|
|
||||||
<span class="label">{{ t("aggregation") }}</span>
|
|
||||||
<SelectSingle
|
|
||||||
:value="currentMetric.calculation"
|
|
||||||
:options="CalculationOpts"
|
|
||||||
@change="changeConfigs(index, { calculation: $event })"
|
|
||||||
class="selectors"
|
|
||||||
:clearable="true"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div class="item mb-10" v-show="isTopn">
|
<div class="item mb-10" v-show="isTopn">
|
||||||
<span class="label">{{ t("sortOrder") }}</span>
|
<span class="label">{{ t("sortOrder") }}</span>
|
||||||
<SelectSingle
|
<SelectSingle
|
||||||
@@ -108,10 +84,9 @@ limitations under the License. -->
|
|||||||
import { ref, watch, computed } from "vue";
|
import { ref, watch, computed } from "vue";
|
||||||
import type { PropType } from "vue";
|
import type { PropType } from "vue";
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
import { SortOrder, CalculationOpts, MetricModes } from "../../../data";
|
import { SortOrder, ExpressionResultType, ListChartTypes } from "@/views/dashboard/data";
|
||||||
import { useDashboardStore } from "@/store/modules/dashboard";
|
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||||
import type { MetricConfigOpt } from "@/types/dashboard";
|
import type { MetricConfigOpt } from "@/types/dashboard";
|
||||||
import { ListChartTypes, ProtocolTypes } from "../../../data";
|
|
||||||
|
|
||||||
/*global defineEmits, defineProps */
|
/*global defineEmits, defineProps */
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
@@ -124,30 +99,17 @@ limitations under the License. -->
|
|||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const emit = defineEmits(["update"]);
|
const emit = defineEmits(["update"]);
|
||||||
const dashboardStore = useDashboardStore();
|
const dashboardStore = useDashboardStore();
|
||||||
const isExpression = ref<boolean>(dashboardStore.selectedGrid.metricMode === MetricModes.Expression);
|
|
||||||
const currentMetric = ref<MetricConfigOpt>({
|
const currentMetric = ref<MetricConfigOpt>({
|
||||||
...props.currentMetricConfig,
|
...props.currentMetricConfig,
|
||||||
topN: props.currentMetricConfig.topN || 10,
|
topN: props.currentMetricConfig.topN || 10,
|
||||||
});
|
});
|
||||||
const metricTypes = computed(
|
const metricTypes = computed(() => dashboardStore.selectedGrid.typesOfMQE || []);
|
||||||
() => (isExpression.value ? dashboardStore.selectedGrid.typesOfMQE : dashboardStore.selectedGrid.metricTypes) || [],
|
|
||||||
);
|
|
||||||
const metricType = computed(() => metricTypes.value[props.index]);
|
|
||||||
const hasLabel = computed(() => {
|
|
||||||
const graph = dashboardStore.selectedGrid.graph || {};
|
|
||||||
return (
|
|
||||||
ListChartTypes.includes(graph.type) ||
|
|
||||||
[ProtocolTypes.ReadLabeledMetricsValues, ProtocolTypes.ReadMetricsValues].includes(metricType.value)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
const isList = computed(() => {
|
const isList = computed(() => {
|
||||||
const graph = dashboardStore.selectedGrid.graph || {};
|
const graph = dashboardStore.selectedGrid.graph || {};
|
||||||
return ListChartTypes.includes(graph.type);
|
return ListChartTypes.includes(graph.type);
|
||||||
});
|
});
|
||||||
const isTopn = computed(() =>
|
const isTopn = computed(() =>
|
||||||
[ProtocolTypes.SortMetrics, ProtocolTypes.ReadSampledRecords, ProtocolTypes.ReadRecords].includes(
|
[ExpressionResultType.RECORD_LIST, ExpressionResultType.SORTED_LIST].includes(metricTypes.value[props.index]),
|
||||||
metricTypes.value[props.index],
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
function updateConfig(index: number, param: { [key: string]: string }) {
|
function updateConfig(index: number, param: { [key: string]: string }) {
|
||||||
@@ -170,7 +132,6 @@ limitations under the License. -->
|
|||||||
watch(
|
watch(
|
||||||
() => props.currentMetricConfig,
|
() => props.currentMetricConfig,
|
||||||
() => {
|
() => {
|
||||||
isExpression.value = dashboardStore.selectedGrid.metricMode === MetricModes.Expression;
|
|
||||||
currentMetric.value = {
|
currentMetric.value = {
|
||||||
...props.currentMetricConfig,
|
...props.currentMetricConfig,
|
||||||
topN: Number(props.currentMetricConfig.topN) || 10,
|
topN: Number(props.currentMetricConfig.topN) || 10,
|
||||||
|
@@ -15,11 +15,12 @@ limitations under the License. -->
|
|||||||
<template>
|
<template>
|
||||||
<div class="flex-h tab-header">
|
<div class="flex-h tab-header">
|
||||||
<div class="tabs scroll_bar_style" @click="handleClick">
|
<div class="tabs scroll_bar_style" @click="handleClick">
|
||||||
|
<template v-for="(child, idx) in data.children || []">
|
||||||
<span
|
<span
|
||||||
v-for="(child, idx) in data.children || []"
|
|
||||||
:key="idx"
|
:key="idx"
|
||||||
:class="{ active: activeTabIndex === idx }"
|
:class="{ active: activeTabIndex === idx }"
|
||||||
@click="clickTabs($event, idx)"
|
@click="clickTabs($event, idx)"
|
||||||
|
v-if="child.enable !== false"
|
||||||
>
|
>
|
||||||
<input
|
<input
|
||||||
@click="editTabName($event, idx)"
|
@click="editTabName($event, idx)"
|
||||||
@@ -38,6 +39,17 @@ limitations under the License. -->
|
|||||||
v-if="dashboardStore.editMode && canEditTabName"
|
v-if="dashboardStore.editMode && canEditTabName"
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
|
</template>
|
||||||
|
<template v-for="(child, idx) in data.children || []">
|
||||||
|
<span
|
||||||
|
:key="idx"
|
||||||
|
:style="{ width: getStringWidth(child.name) + 'px' }"
|
||||||
|
v-if="child.enable === false"
|
||||||
|
class="tab-diabled"
|
||||||
|
>
|
||||||
|
{{ child.name }}
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
<span class="tab-icons">
|
<span class="tab-icons">
|
||||||
<el-tooltip content="Copy Link" placement="bottom">
|
<el-tooltip content="Copy Link" placement="bottom">
|
||||||
<i @click="copyLink">
|
<i @click="copyLink">
|
||||||
@@ -56,10 +68,13 @@ limitations under the License. -->
|
|||||||
<div class="operations" v-if="dashboardStore.editMode">
|
<div class="operations" v-if="dashboardStore.editMode">
|
||||||
<el-dropdown placement="bottom" trigger="click" :width="200">
|
<el-dropdown placement="bottom" trigger="click" :width="200">
|
||||||
<span class="icon-operation">
|
<span class="icon-operation">
|
||||||
<Icon iconName="ellipsis_v" size="middle" />
|
<Icon class="icon-tool" iconName="ellipsis_v" size="middle" />
|
||||||
</span>
|
</span>
|
||||||
<template #dropdown>
|
<template #dropdown>
|
||||||
<el-dropdown-menu>
|
<el-dropdown-menu>
|
||||||
|
<el-dropdown-item @click="editConfig">
|
||||||
|
<span>{{ t("edit") }}</span>
|
||||||
|
</el-dropdown-item>
|
||||||
<el-dropdown-item @click="canEditTabName = true">
|
<el-dropdown-item @click="canEditTabName = true">
|
||||||
<span class="edit-tab">{{ t("editTab") }}</span>
|
<span class="edit-tab">{{ t("editTab") }}</span>
|
||||||
</el-dropdown-item>
|
</el-dropdown-item>
|
||||||
@@ -98,6 +113,7 @@ limitations under the License. -->
|
|||||||
:data="item"
|
:data="item"
|
||||||
:activeIndex="`${data.i}-${activeTabIndex}-${item.i}`"
|
:activeIndex="`${data.i}-${activeTabIndex}-${item.i}`"
|
||||||
:needQuery="needQuery"
|
:needQuery="needQuery"
|
||||||
|
:metricsValues="metricsValues"
|
||||||
/>
|
/>
|
||||||
</grid-item>
|
</grid-item>
|
||||||
</grid-layout>
|
</grid-layout>
|
||||||
@@ -105,21 +121,26 @@ limitations under the License. -->
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { ref, watch, defineComponent, toRefs } from "vue";
|
import { ref, watch, defineComponent, toRefs, onUnmounted } from "vue";
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
import { useRoute } from "vue-router";
|
import { useRoute } from "vue-router";
|
||||||
import type { PropType } from "vue";
|
import type { PropType } from "vue";
|
||||||
import type { LayoutConfig } from "@/types/dashboard";
|
import type { LayoutConfig } from "@/types/dashboard";
|
||||||
import { useDashboardStore } from "@/store/modules/dashboard";
|
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||||
import controls from "./tab";
|
import controls from "./tab";
|
||||||
import { dragIgnoreFrom } from "../data";
|
import { dragIgnoreFrom, WidgetType } from "../data";
|
||||||
import copy from "@/utils/copy";
|
import copy from "@/utils/copy";
|
||||||
|
import { useDashboardQueryProcessor } from "@/hooks/useExpressionsProcessor";
|
||||||
|
|
||||||
const props = {
|
const props = {
|
||||||
data: {
|
data: {
|
||||||
type: Object as PropType<LayoutConfig>,
|
type: Object as PropType<LayoutConfig>,
|
||||||
default: () => ({ children: [] }),
|
default: () => ({ children: [] }),
|
||||||
},
|
},
|
||||||
|
metricsValues: {
|
||||||
|
type: Object as PropType<any>,
|
||||||
|
default: () => ({}),
|
||||||
|
},
|
||||||
active: { type: Boolean, default: false },
|
active: { type: Boolean, default: false },
|
||||||
};
|
};
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
@@ -137,13 +158,17 @@ limitations under the License. -->
|
|||||||
const editTabIndex = ref<number>(NaN); // edit tab item name
|
const editTabIndex = ref<number>(NaN); // edit tab item name
|
||||||
const canEditTabName = ref<boolean>(false);
|
const canEditTabName = ref<boolean>(false);
|
||||||
const needQuery = ref<boolean>(false);
|
const needQuery = ref<boolean>(false);
|
||||||
|
|
||||||
dashboardStore.setActiveTabIndex(activeTabIndex);
|
|
||||||
const l = dashboardStore.layout.findIndex((d: LayoutConfig) => d.i === props.data.i);
|
const l = dashboardStore.layout.findIndex((d: LayoutConfig) => d.i === props.data.i);
|
||||||
|
|
||||||
|
dashboardStore.setActiveTabIndex(activeTabIndex.value);
|
||||||
if (dashboardStore.layout[l].children.length) {
|
if (dashboardStore.layout[l].children.length) {
|
||||||
dashboardStore.setCurrentTabItems(dashboardStore.layout[l].children[activeTabIndex.value].children);
|
const tab = dashboardStore.layout[l].children[activeTabIndex.value];
|
||||||
|
dashboardStore.setCurrentTabItems(
|
||||||
|
tab.enable === false ? [] : dashboardStore.layout[l].children[activeTabIndex.value].children,
|
||||||
|
);
|
||||||
dashboardStore.setActiveTabIndex(activeTabIndex.value, props.data.i);
|
dashboardStore.setActiveTabIndex(activeTabIndex.value, props.data.i);
|
||||||
}
|
}
|
||||||
|
queryExpressions();
|
||||||
|
|
||||||
function clickTabs(e: Event, idx: number) {
|
function clickTabs(e: Event, idx: number) {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
@@ -224,6 +249,59 @@ limitations under the License. -->
|
|||||||
copy(path);
|
copy(path);
|
||||||
}
|
}
|
||||||
document.body.addEventListener("click", handleClick, false);
|
document.body.addEventListener("click", handleClick, false);
|
||||||
|
|
||||||
|
function editConfig() {
|
||||||
|
dashboardStore.setConfigPanel(true);
|
||||||
|
dashboardStore.selectWidget(props.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function queryExpressions() {
|
||||||
|
const tabsProps = props.data;
|
||||||
|
const metrics = [];
|
||||||
|
for (const child of tabsProps.children || []) {
|
||||||
|
child.expression && metrics.push(child.expression);
|
||||||
|
}
|
||||||
|
if (!metrics.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const values: { [key: string]: any } =
|
||||||
|
(await useDashboardQueryProcessor([{ metrics, id: props.data.i }])) || {};
|
||||||
|
for (const child of tabsProps.children || []) {
|
||||||
|
const params = values[props.data.i];
|
||||||
|
if (params.source[child.expression || ""]) {
|
||||||
|
child.enable =
|
||||||
|
!!Number(params.source[child.expression || ""]) &&
|
||||||
|
!!child.children.find((item: { type: string }) => item.type === WidgetType.Widget);
|
||||||
|
} else {
|
||||||
|
child.enable = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dashboardStore.setConfigs(tabsProps);
|
||||||
|
if (((props.data.children || [])[activeTabIndex.value] || {}).enable === false) {
|
||||||
|
const index = (props.data.children || []).findIndex((tab: any) => tab.enable !== false) || 0;
|
||||||
|
const items = ((props.data.children || [])[index] || {}).children;
|
||||||
|
dashboardStore.setCurrentTabItems(items || []);
|
||||||
|
dashboardStore.activeGridItem(0);
|
||||||
|
activeTabIndex.value = index;
|
||||||
|
dashboardStore.setActiveTabIndex(activeTabIndex.value);
|
||||||
|
needQuery.value = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
document.body.removeEventListener("click", handleClick, false);
|
||||||
|
});
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => (props.data.children || []).map((d: any) => d.expression),
|
||||||
|
(old: string[], data: string[]) => {
|
||||||
|
if (JSON.stringify(data) === JSON.stringify(old)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
queryExpressions();
|
||||||
|
},
|
||||||
|
);
|
||||||
watch(
|
watch(
|
||||||
() => dashboardStore.activedGridItem,
|
() => dashboardStore.activedGridItem,
|
||||||
(data) => {
|
(data) => {
|
||||||
@@ -266,6 +344,7 @@ limitations under the License. -->
|
|||||||
clickTabs,
|
clickTabs,
|
||||||
copyLink,
|
copyLink,
|
||||||
getStringWidth,
|
getStringWidth,
|
||||||
|
editConfig,
|
||||||
...toRefs(props),
|
...toRefs(props),
|
||||||
activeTabWidget,
|
activeTabWidget,
|
||||||
dashboardStore,
|
dashboardStore,
|
||||||
@@ -288,6 +367,7 @@ limitations under the License. -->
|
|||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
overflow-y: hidden;
|
overflow-y: hidden;
|
||||||
padding: 0 10px;
|
padding: 0 10px;
|
||||||
|
display: inline-flex;
|
||||||
|
|
||||||
span {
|
span {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
@@ -310,6 +390,18 @@ limitations under the License. -->
|
|||||||
background-color: $theme-background;
|
background-color: $theme-background;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.tab-diabled {
|
||||||
|
max-width: 150px;
|
||||||
|
outline: none;
|
||||||
|
color: $disabled-color;
|
||||||
|
font-style: normal;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
margin-right: 20px;
|
||||||
|
background-color: $theme-background;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
.tab-icons {
|
.tab-icons {
|
||||||
i {
|
i {
|
||||||
margin-right: 3px;
|
margin-right: 3px;
|
||||||
|
@@ -25,22 +25,34 @@ limitations under the License. -->
|
|||||||
</div>
|
</div>
|
||||||
</el-popover>
|
</el-popover>
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<Filter :needQuery="needQuery" :data="data" />
|
<Filter :needQuery="needQuery" :data="data" @get="getService" @search="popSegmentList" />
|
||||||
</div>
|
</div>
|
||||||
<div class="trace flex-h">
|
<div class="trace flex-h">
|
||||||
<TraceList />
|
<TraceList class="trace-list" :style="`width: ${currentWidth}px;`" />
|
||||||
<TraceDetail />
|
<div
|
||||||
|
@mouseover="showIcon = true"
|
||||||
|
@mouseout="showIcon = false"
|
||||||
|
@mousedown="mousedown($event)"
|
||||||
|
@mouseup="mouseup($event)"
|
||||||
|
>
|
||||||
|
<div class="trace-line" />
|
||||||
|
<span class="trace-icon" v-show="showIcon" @mousedown="triggerArrow" @mouseup="stopObserve($event)">
|
||||||
|
<Icon class="trace-arrow" :icon-name="isLeft ? 'chevron-left' : 'chevron-right'" size="lg" />
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<TraceDetail :serviceId="serviceId" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { provide } from "vue";
|
import { provide, ref, onMounted, onUnmounted } from "vue";
|
||||||
import type { PropType } from "vue";
|
import type { PropType } from "vue";
|
||||||
import Filter from "../related/trace/Filter.vue";
|
import Filter from "../related/trace/Filter.vue";
|
||||||
import TraceList from "../related/trace/TraceList.vue";
|
import TraceList from "../related/trace/TraceList.vue";
|
||||||
import TraceDetail from "../related/trace/Detail.vue";
|
import TraceDetail from "../related/trace/Detail.vue";
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
import { useDashboardStore } from "@/store/modules/dashboard";
|
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||||
|
import { mutationObserver } from "@/utils/mutation";
|
||||||
|
|
||||||
/* global defineProps */
|
/* global defineProps */
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
@@ -52,11 +64,76 @@ limitations under the License. -->
|
|||||||
needQuery: { type: Boolean, default: true },
|
needQuery: { type: Boolean, default: true },
|
||||||
});
|
});
|
||||||
provide("options", props.data);
|
provide("options", props.data);
|
||||||
|
const defaultWidth = 280,
|
||||||
|
minArrowLeftWidth = 120;
|
||||||
|
const serviceId = ref<string>("");
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const dashboardStore = useDashboardStore();
|
const dashboardStore = useDashboardStore();
|
||||||
|
const isLeft = ref<boolean>(true);
|
||||||
|
const showIcon = ref<boolean>(false);
|
||||||
|
const currentWidth = ref<number>(defaultWidth);
|
||||||
|
const isDrag = ref<boolean>(false);
|
||||||
|
|
||||||
function removeWidget() {
|
function removeWidget() {
|
||||||
dashboardStore.removeControls(props.data);
|
dashboardStore.removeControls(props.data);
|
||||||
}
|
}
|
||||||
|
function getService(id: string) {
|
||||||
|
serviceId.value = id;
|
||||||
|
}
|
||||||
|
// When click the arrow, the width of the segment list is determined by the direction it points to.
|
||||||
|
function triggerArrow() {
|
||||||
|
currentWidth.value = isLeft.value ? 0 : defaultWidth;
|
||||||
|
isLeft.value = !isLeft.value;
|
||||||
|
startObserve();
|
||||||
|
}
|
||||||
|
function popSegmentList() {
|
||||||
|
if (currentWidth.value >= defaultWidth) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
currentWidth.value = defaultWidth;
|
||||||
|
isLeft.value = true;
|
||||||
|
}
|
||||||
|
function startObserve() {
|
||||||
|
mutationObserver.observe("trigger-resize", document.querySelector(".trace-list")!, {
|
||||||
|
attributes: true,
|
||||||
|
attributeFilter: ["style"],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function stopObserve(event: MouseEvent) {
|
||||||
|
mutationObserver.disconnect("trigger-resize");
|
||||||
|
event.stopPropagation();
|
||||||
|
}
|
||||||
|
const mousemove = (event: MouseEvent) => {
|
||||||
|
if (!isDrag.value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const diffX = event.clientX;
|
||||||
|
let leftWidth = document.querySelector(".trace-list")!.getBoundingClientRect();
|
||||||
|
currentWidth.value = diffX - leftWidth.left;
|
||||||
|
isLeft.value = currentWidth.value >= minArrowLeftWidth;
|
||||||
|
};
|
||||||
|
const mouseup = (event: MouseEvent) => {
|
||||||
|
showIcon.value = false;
|
||||||
|
isDrag.value = false;
|
||||||
|
stopObserve(event);
|
||||||
|
};
|
||||||
|
const mousedown = (event: MouseEvent) => {
|
||||||
|
if ((event.target as HTMLDivElement)?.className === "trace-line") {
|
||||||
|
isDrag.value = true;
|
||||||
|
startObserve();
|
||||||
|
event.stopPropagation();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
onMounted(() => {
|
||||||
|
document.addEventListener("mousedown", mousedown);
|
||||||
|
document.addEventListener("mousemove", mousemove);
|
||||||
|
document.addEventListener("mouseup", mouseup);
|
||||||
|
});
|
||||||
|
onUnmounted(() => {
|
||||||
|
document.removeEventListener("mousedown", mousedown);
|
||||||
|
document.removeEventListener("mousemove", mousemove);
|
||||||
|
document.removeEventListener("mouseup", mouseup);
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.trace-wrapper {
|
.trace-wrapper {
|
||||||
@@ -64,7 +141,6 @@ limitations under the License. -->
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
font-size: $font-size-smaller;
|
font-size: $font-size-smaller;
|
||||||
position: relative;
|
position: relative;
|
||||||
overflow: auto;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.delete {
|
.delete {
|
||||||
@@ -77,7 +153,7 @@ limitations under the License. -->
|
|||||||
padding: 10px;
|
padding: 10px;
|
||||||
font-size: $font-size-smaller;
|
font-size: $font-size-smaller;
|
||||||
border-bottom: 1px solid $border-color;
|
border-bottom: 1px solid $border-color;
|
||||||
min-width: 1200px;
|
min-width: 1000px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tools {
|
.tools {
|
||||||
@@ -97,6 +173,42 @@ limitations under the License. -->
|
|||||||
min-height: calc(100% - 150px);
|
min-height: calc(100% - 150px);
|
||||||
width: 100%;
|
width: 100%;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
min-width: 1200px;
|
min-width: 1000px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.trace-list {
|
||||||
|
max-width: 480px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.trace-line {
|
||||||
|
position: relative;
|
||||||
|
width: 2px;
|
||||||
|
height: 100%;
|
||||||
|
background-color: #e8e8e8;
|
||||||
|
cursor: ew-resize;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: $active-color;
|
||||||
|
background-color: $active-background;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.trace-icon {
|
||||||
|
position: absolute;
|
||||||
|
cursor: pointer;
|
||||||
|
top: calc(50% - 15px);
|
||||||
|
text-align: center;
|
||||||
|
width: 24px;
|
||||||
|
height: 24px;
|
||||||
|
transform: translateX(-11px);
|
||||||
|
line-height: 24px;
|
||||||
|
border-radius: 50%;
|
||||||
|
background-color: $layout-background;
|
||||||
|
box-shadow: 0 3px 5px rgb(45 60 80 / 20%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.trace-arrow {
|
||||||
|
padding-bottom: 1px;
|
||||||
|
color: $active-color;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@@ -51,15 +51,12 @@ limitations under the License. -->
|
|||||||
:data="state.source"
|
:data="state.source"
|
||||||
:config="{
|
:config="{
|
||||||
...data.graph,
|
...data.graph,
|
||||||
metrics: data.metrics || [''],
|
|
||||||
metricTypes: data.metricTypes || [''],
|
|
||||||
i: data.i,
|
i: data.i,
|
||||||
id: data.id,
|
id: data.id,
|
||||||
metricConfig: data.metricConfig || [],
|
metricConfig: data.metricConfig || [],
|
||||||
filters: data.filters || {},
|
filters: data.filters || {},
|
||||||
relatedTrace: data.relatedTrace || {},
|
relatedTrace: data.relatedTrace || {},
|
||||||
associate: data.associate || [],
|
associate: data.associate || [],
|
||||||
metricMode: data.metricMode,
|
|
||||||
expressions: data.expressions || [],
|
expressions: data.expressions || [],
|
||||||
typesOfMQE: typesOfMQE || [],
|
typesOfMQE: typesOfMQE || [],
|
||||||
subExpressions: data.subExpressions || [],
|
subExpressions: data.subExpressions || [],
|
||||||
@@ -78,21 +75,22 @@ limitations under the License. -->
|
|||||||
import type { LayoutConfig } from "@/types/dashboard";
|
import type { LayoutConfig } from "@/types/dashboard";
|
||||||
import { useDashboardStore } from "@/store/modules/dashboard";
|
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||||
import { useAppStoreWithOut } from "@/store/modules/app";
|
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||||
import { useSelectorStore } from "@/store/modules/selectors";
|
|
||||||
import graphs from "../graphs";
|
import graphs from "../graphs";
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
import { useQueryProcessor, useSourceProcessor } from "@/hooks/useMetricsProcessor";
|
import { useDashboardQueryProcessor } from "@/hooks/useExpressionsProcessor";
|
||||||
import { useExpressionsQueryProcessor } from "@/hooks/useExpressionsProcessor";
|
import { ListChartTypes } from "../data";
|
||||||
import { EntityType, ListChartTypes } from "../data";
|
|
||||||
import type { EventParams } from "@/types/dashboard";
|
import type { EventParams } from "@/types/dashboard";
|
||||||
import getDashboard from "@/hooks/useDashboardsSession";
|
import getDashboard from "@/hooks/useDashboardsSession";
|
||||||
import { MetricModes } from "../data";
|
|
||||||
|
|
||||||
const props = {
|
const props = {
|
||||||
data: {
|
data: {
|
||||||
type: Object as PropType<LayoutConfig>,
|
type: Object as PropType<LayoutConfig>,
|
||||||
default: () => ({ widget: {}, graph: {} }),
|
default: () => ({ widget: {}, graph: {} }),
|
||||||
},
|
},
|
||||||
|
metricsValues: {
|
||||||
|
type: Object as PropType<{ [key: string]: { source: { [key: string]: unknown }; typesOfMQE: string[] } }>,
|
||||||
|
default: () => ({}),
|
||||||
|
},
|
||||||
activeIndex: { type: String, default: "" },
|
activeIndex: { type: String, default: "" },
|
||||||
needQuery: { type: Boolean, default: false },
|
needQuery: { type: Boolean, default: false },
|
||||||
};
|
};
|
||||||
@@ -110,49 +108,23 @@ limitations under the License. -->
|
|||||||
const { data } = toRefs(props);
|
const { data } = toRefs(props);
|
||||||
const appStore = useAppStoreWithOut();
|
const appStore = useAppStoreWithOut();
|
||||||
const dashboardStore = useDashboardStore();
|
const dashboardStore = useDashboardStore();
|
||||||
const selectorStore = useSelectorStore();
|
|
||||||
const graph = computed(() => props.data.graph || {});
|
const graph = computed(() => props.data.graph || {});
|
||||||
const widget = computed(() => props.data.widget || {});
|
const widget = computed(() => props.data.widget || {});
|
||||||
const isList = computed(() => ListChartTypes.includes((props.data.graph && props.data.graph.type) || ""));
|
|
||||||
const typesOfMQE = ref<string[]>([]);
|
const typesOfMQE = ref<string[]>([]);
|
||||||
|
|
||||||
if ((props.needQuery || !dashboardStore.currentDashboard.id) && !isList.value) {
|
|
||||||
queryMetrics();
|
|
||||||
}
|
|
||||||
|
|
||||||
async function queryMetrics() {
|
async function queryMetrics() {
|
||||||
const isExpression = props.data.metricMode === MetricModes.Expression;
|
|
||||||
|
|
||||||
if (isExpression) {
|
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
const e = {
|
const config = {
|
||||||
metrics: props.data.expressions || [],
|
metrics: props.data.expressions || [],
|
||||||
metricConfig: props.data.metricConfig || [],
|
metricConfig: props.data.metricConfig || [],
|
||||||
|
id: props.data.i,
|
||||||
};
|
};
|
||||||
const params = (await useExpressionsQueryProcessor(e)) || {};
|
const metrics: { [key: string]: { source: { [key: string]: unknown }; typesOfMQE: string[] } } =
|
||||||
|
(await useDashboardQueryProcessor([config])) || {};
|
||||||
|
const params = metrics[data.value.i];
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
state.source = params.source || {};
|
state.source = params.source || {};
|
||||||
typesOfMQE.value = params.typesOfMQE;
|
typesOfMQE.value = params.typesOfMQE;
|
||||||
return;
|
|
||||||
}
|
|
||||||
const params = await useQueryProcessor({ ...props.data });
|
|
||||||
|
|
||||||
if (!params) {
|
|
||||||
state.source = {};
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
loading.value = true;
|
|
||||||
const json = await dashboardStore.fetchMetricValue(params);
|
|
||||||
loading.value = false;
|
|
||||||
if (!json) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const d = {
|
|
||||||
metrics: props.data.metrics || [],
|
|
||||||
metricTypes: props.data.metricTypes || [],
|
|
||||||
metricConfig: props.data.metricConfig || [],
|
|
||||||
};
|
|
||||||
state.source = await useSourceProcessor(json, d);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function removeWidget() {
|
function removeWidget() {
|
||||||
@@ -188,7 +160,7 @@ limitations under the License. -->
|
|||||||
dashboardStore.selectWidget(props.data);
|
dashboardStore.selectWidget(props.data);
|
||||||
}
|
}
|
||||||
watch(
|
watch(
|
||||||
() => [props.data.metricTypes, props.data.metrics, props.data.expressions],
|
() => props.data,
|
||||||
() => {
|
() => {
|
||||||
if (!dashboardStore.selectedGrid) {
|
if (!dashboardStore.selectedGrid) {
|
||||||
return;
|
return;
|
||||||
@@ -197,54 +169,19 @@ limitations under the License. -->
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const chart = dashboardStore.selectedGrid.graph || {};
|
const chart = dashboardStore.selectedGrid.graph || {};
|
||||||
if (ListChartTypes.includes(chart.type) || isList.value) {
|
if (ListChartTypes.includes(chart.type)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
queryMetrics();
|
queryMetrics();
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
watch(
|
watch(
|
||||||
() => [selectorStore.currentService, selectorStore.currentDestService],
|
() => props.metricsValues,
|
||||||
() => {
|
() => {
|
||||||
if (isList.value) {
|
const params = props.metricsValues[data.value.i];
|
||||||
return;
|
if (params) {
|
||||||
}
|
state.source = params.source || {};
|
||||||
if ([EntityType[0].value, EntityType[4].value].includes(dashboardStore.entity)) {
|
typesOfMQE.value = params.typesOfMQE;
|
||||||
queryMetrics();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
|
||||||
watch(
|
|
||||||
() => [selectorStore.currentPod, selectorStore.currentDestPod],
|
|
||||||
() => {
|
|
||||||
if ([EntityType[0].value, EntityType[7].value, EntityType[8].value].includes(dashboardStore.entity)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (isList.value) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
queryMetrics();
|
|
||||||
},
|
|
||||||
);
|
|
||||||
watch(
|
|
||||||
() => [selectorStore.currentProcess, selectorStore.currentDestProcess],
|
|
||||||
() => {
|
|
||||||
if (isList.value) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if ([EntityType[7].value, EntityType[8].value].includes(dashboardStore.entity)) {
|
|
||||||
queryMetrics();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
|
||||||
watch(
|
|
||||||
() => appStore.durationTime,
|
|
||||||
() => {
|
|
||||||
if (isList.value) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (dashboardStore.entity === EntityType[1].value) {
|
|
||||||
queryMetrics();
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
@@ -34,29 +34,6 @@ export const ChartTypes = [
|
|||||||
{ label: "Endpoint List", value: "EndpointList" },
|
{ label: "Endpoint List", value: "EndpointList" },
|
||||||
{ label: "Instance List", value: "InstanceList" },
|
{ label: "Instance List", value: "InstanceList" },
|
||||||
];
|
];
|
||||||
export const MetricChartType: any = {
|
|
||||||
readMetricsValue: [{ label: "Card", value: "Card" }],
|
|
||||||
readMetricsValues: [
|
|
||||||
{ label: "Bar", value: "Bar" },
|
|
||||||
{ label: "Line", value: "Line" },
|
|
||||||
{ label: "Area", value: "Area" },
|
|
||||||
],
|
|
||||||
sortMetrics: [{ label: "Top List", value: "TopList" }],
|
|
||||||
readLabeledMetricsValues: [{ label: "Line", value: "Line" }],
|
|
||||||
readHeatMap: [{ label: "Heat Map", value: "HeatMap" }],
|
|
||||||
readSampledRecords: [{ label: "Top List", value: "TopList" }],
|
|
||||||
readRecords: [{ label: "Top List", value: "TopList" }],
|
|
||||||
};
|
|
||||||
export enum ProtocolTypes {
|
|
||||||
ReadRecords = "readRecords",
|
|
||||||
ReadSampledRecords = "readSampledRecords",
|
|
||||||
SortMetrics = "sortMetrics",
|
|
||||||
ReadLabeledMetricsValues = "readLabeledMetricsValues",
|
|
||||||
ReadHeatMap = "readHeatMap",
|
|
||||||
ReadMetricsValues = "readMetricsValues",
|
|
||||||
ReadMetricsValue = "readMetricsValue",
|
|
||||||
}
|
|
||||||
|
|
||||||
export enum ExpressionResultType {
|
export enum ExpressionResultType {
|
||||||
UNKNOWN = "UNKNOWN",
|
UNKNOWN = "UNKNOWN",
|
||||||
SINGLE_VALUE = "SINGLE_VALUE",
|
SINGLE_VALUE = "SINGLE_VALUE",
|
||||||
@@ -93,7 +70,6 @@ export const DefaultGraphConfig: { [key: string]: any } = {
|
|||||||
Table: {
|
Table: {
|
||||||
type: "Table",
|
type: "Table",
|
||||||
showTableValues: true,
|
showTableValues: true,
|
||||||
tableHeaderCol1: "",
|
|
||||||
tableHeaderCol2: "",
|
tableHeaderCol2: "",
|
||||||
},
|
},
|
||||||
TopList: {
|
TopList: {
|
||||||
@@ -125,34 +101,6 @@ export const DefaultGraphConfig: { [key: string]: any } = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export enum MetricsType {
|
|
||||||
UNKNOWN = "UNKNOWN",
|
|
||||||
REGULAR_VALUE = "REGULAR_VALUE",
|
|
||||||
LABELED_VALUE = "LABELED_VALUE",
|
|
||||||
HEATMAP = "HEATMAP",
|
|
||||||
SAMPLED_RECORD = "SAMPLED_RECORD",
|
|
||||||
}
|
|
||||||
export const MetricTypes: {
|
|
||||||
[key: string]: Array<{ label: string; value: string }>;
|
|
||||||
} = {
|
|
||||||
REGULAR_VALUE: [
|
|
||||||
{ label: "read all values in the duration", value: "readMetricsValues" },
|
|
||||||
{
|
|
||||||
label: "read the single value in the duration",
|
|
||||||
value: "readMetricsValue",
|
|
||||||
},
|
|
||||||
{ label: "get sorted top N values", value: "sortMetrics" },
|
|
||||||
],
|
|
||||||
LABELED_VALUE: [
|
|
||||||
{
|
|
||||||
label: "read all values of labels in the duration",
|
|
||||||
value: "readLabeledMetricsValues",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
HEATMAP: [{ label: "read heatmap values in the duration", value: "readHeatMap" }],
|
|
||||||
SAMPLED_RECORD: [{ label: "get sorted topN values", value: "readRecords" }],
|
|
||||||
};
|
|
||||||
|
|
||||||
export enum MetricCatalog {
|
export enum MetricCatalog {
|
||||||
SERVICE = "Service",
|
SERVICE = "Service",
|
||||||
SERVICE_INSTANCE = "ServiceInstance",
|
SERVICE_INSTANCE = "ServiceInstance",
|
||||||
@@ -188,87 +136,104 @@ export const SortOrder = [
|
|||||||
{ label: "DES", value: "DES" },
|
{ label: "DES", value: "DES" },
|
||||||
{ label: "ASC", value: "ASC" },
|
{ label: "ASC", value: "ASC" },
|
||||||
];
|
];
|
||||||
|
export enum WidgetType {
|
||||||
|
Widget = "Widget",
|
||||||
|
Topology = "Topology",
|
||||||
|
Tab = "Tab",
|
||||||
|
Text = "Text",
|
||||||
|
TimeRange = "TimeRange",
|
||||||
|
Trace = "Trace",
|
||||||
|
Log = "Log",
|
||||||
|
Profile = "Profile",
|
||||||
|
Ebpf = "Ebpf",
|
||||||
|
DemandLog = "DemandLog",
|
||||||
|
Event = "Event",
|
||||||
|
NetworkProfiling = "NetworkProfiling",
|
||||||
|
ContinuousProfiling = "ContinuousProfiling",
|
||||||
|
ThirdPartyApp = "ThirdPartyApp",
|
||||||
|
TaskTimeline = "TaskTimeline",
|
||||||
|
}
|
||||||
export const AllTools = [
|
export const AllTools = [
|
||||||
{ name: "playlist_add", content: "Add Widget", id: "addWidget" },
|
{ name: "playlist_add", content: "Add Widget", id: WidgetType.Widget },
|
||||||
{ name: "all_inbox", content: "Add Tabs", id: "addTab" },
|
{ name: "all_inbox", content: "Add Tabs", id: WidgetType.Tab },
|
||||||
{ name: "library_books", content: "Add Text", id: "addText" },
|
{ name: "library_books", content: "Add Text", id: WidgetType.Text },
|
||||||
{ name: "device_hub", content: "Add Topology", id: "addTopology" },
|
{ name: "device_hub", content: "Add Topology", id: WidgetType.Topology },
|
||||||
{ name: "merge", content: "Add Trace", id: "addTrace" },
|
{ name: "merge", content: "Add Trace", id: WidgetType.Trace },
|
||||||
{ name: "assignment", content: "Add Log", id: "addLog" },
|
{ name: "assignment", content: "Add Log", id: WidgetType.Log },
|
||||||
{ name: "add_iframe", content: "Add Iframe", id: "addIframe" },
|
{ name: "add_iframe", content: "Add Iframe", id: WidgetType.ThirdPartyApp },
|
||||||
];
|
];
|
||||||
export const ServiceTools = [
|
export const ServiceTools = [
|
||||||
{ name: "playlist_add", content: "Add Widget", id: "addWidget" },
|
{ name: "playlist_add", content: "Add Widget", id: WidgetType.Widget },
|
||||||
{ name: "all_inbox", content: "Add Tabs", id: "addTab" },
|
{ name: "all_inbox", content: "Add Tabs", id: WidgetType.Tab },
|
||||||
{ name: "library_books", content: "Add Text", id: "addText" },
|
{ name: "library_books", content: "Add Text", id: WidgetType.Text },
|
||||||
{ name: "device_hub", content: "Add Topology", id: "addTopology" },
|
{ name: "device_hub", content: "Add Topology", id: WidgetType.Topology },
|
||||||
{ name: "merge", content: "Add Trace", id: "addTrace" },
|
{ name: "merge", content: "Add Trace", id: WidgetType.Trace },
|
||||||
{ name: "timeline", content: "Add Trace Profiling", id: "addProfile" },
|
{ name: "timeline", content: "Add Trace Profiling", id: WidgetType.Profile },
|
||||||
{ name: "insert_chart", content: "Add eBPF Profiling", id: "addEbpf" },
|
{ name: "insert_chart", content: "Add eBPF Profiling", id: WidgetType.Ebpf },
|
||||||
{ name: "continuous_profiling", content: "Add Continuous Profiling", id: "addContinuousProfiling" },
|
{ name: "continuous_profiling", content: "Add Continuous Profiling", id: WidgetType.ContinuousProfiling },
|
||||||
{ name: "assignment", content: "Add Log", id: "addLog" },
|
{ name: "assignment", content: "Add Log", id: WidgetType.Log },
|
||||||
{ name: "demand", content: "Add On Demand Log", id: "addDemandLog" },
|
{ name: "demand", content: "Add On Demand Log", id: WidgetType.DemandLog },
|
||||||
{ name: "event", content: "Add Event", id: "addEvent" },
|
{ name: "event", content: "Add Event", id: WidgetType.Event },
|
||||||
{ name: "add_iframe", content: "Add Iframe", id: "addIframe" },
|
{ name: "add_iframe", content: "Add Iframe", id: WidgetType.ThirdPartyApp },
|
||||||
];
|
];
|
||||||
export const InstanceTools = [
|
export const InstanceTools = [
|
||||||
{ name: "playlist_add", content: "Add Widget", id: "addWidget" },
|
{ name: "playlist_add", content: "Add Widget", id: WidgetType.Widget },
|
||||||
{ name: "all_inbox", content: "Add Tabs", id: "addTab" },
|
{ name: "all_inbox", content: "Add Tabs", id: WidgetType.Tab },
|
||||||
{ name: "library_books", content: "Add Text", id: "addText" },
|
{ name: "library_books", content: "Add Text", id: WidgetType.Text },
|
||||||
{ name: "merge", content: "Add Trace", id: "addTrace" },
|
{ name: "merge", content: "Add Trace", id: WidgetType.Trace },
|
||||||
{ name: "assignment", content: "Add Log", id: "addLog" },
|
{ name: "assignment", content: "Add Log", id: WidgetType.Log },
|
||||||
{ name: "demand", content: "Add On Demand Log", id: "addDemandLog" },
|
{ name: "demand", content: "Add On Demand Log", id: WidgetType.DemandLog },
|
||||||
{ name: "event", content: "Add Event", id: "addEvent" },
|
{ name: "event", content: "Add Event", id: WidgetType.Event },
|
||||||
{ name: "add_iframe", content: "Add Iframe", id: "addIframe" },
|
{ name: "add_iframe", content: "Add Iframe", id: WidgetType.ThirdPartyApp },
|
||||||
{
|
{
|
||||||
name: "timeline",
|
name: "timeline",
|
||||||
content: "Add Network Profiling",
|
content: "Add Network Profiling",
|
||||||
id: "addNetworkProfiling",
|
id: WidgetType.NetworkProfiling,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
export const EndpointTools = [
|
export const EndpointTools = [
|
||||||
{ name: "playlist_add", content: "Add Widget", id: "addWidget" },
|
{ name: "playlist_add", content: "Add Widget", id: WidgetType.Widget },
|
||||||
{ name: "all_inbox", content: "Add Tabs", id: "addTab" },
|
{ name: "all_inbox", content: "Add Tabs", id: WidgetType.Tab },
|
||||||
{ name: "library_books", content: "Add Text", id: "addText" },
|
{ name: "library_books", content: "Add Text", id: WidgetType.Text },
|
||||||
{ name: "device_hub", content: "Add Topology", id: "addTopology" },
|
{ name: "device_hub", content: "Add Topology", id: WidgetType.Topology },
|
||||||
{ name: "merge", content: "Add Trace", id: "addTrace" },
|
{ name: "merge", content: "Add Trace", id: WidgetType.Trace },
|
||||||
{ name: "assignment", content: "Add Log", id: "addLog" },
|
{ name: "assignment", content: "Add Log", id: WidgetType.Log },
|
||||||
{ name: "event", content: "Add Event", id: "c" },
|
{ name: "event", content: "Add Event", id: WidgetType.Event },
|
||||||
{ name: "add_iframe", content: "Add Iframe", id: "addIframe" },
|
{ name: "add_iframe", content: "Add Iframe", id: WidgetType.ThirdPartyApp },
|
||||||
];
|
];
|
||||||
export const ProcessTools = [
|
export const ProcessTools = [
|
||||||
{ name: "playlist_add", content: "Add Widget", id: "addWidget" },
|
{ name: "playlist_add", content: "Add Widget", id: WidgetType.Widget },
|
||||||
{ name: "all_inbox", content: "Add Tabs", id: "addTab" },
|
{ name: "all_inbox", content: "Add Tabs", id: WidgetType.Tab },
|
||||||
{ name: "task_timeline", content: "Add Task Timeline", id: "addTaskTimeline" },
|
{ name: "task_timeline", content: "Add Task Timeline", id: WidgetType.TaskTimeline },
|
||||||
{ name: "library_books", content: "Add Text", id: "addText" },
|
{ name: "library_books", content: "Add Text", id: WidgetType.Text },
|
||||||
{ name: "add_iframe", content: "Add Iframe", id: "addIframe" },
|
{ name: "add_iframe", content: "Add Iframe", id: WidgetType.ThirdPartyApp },
|
||||||
];
|
];
|
||||||
export const ProcessRelationTools = [
|
export const ProcessRelationTools = [
|
||||||
{ name: "playlist_add", content: "Add Widget", id: "addWidget" },
|
{ name: "playlist_add", content: "Add Widget", id: WidgetType.Widget },
|
||||||
{ name: "all_inbox", content: "Add Tabs", id: "addTab" },
|
{ name: "all_inbox", content: "Add Tabs", id: WidgetType.Tab },
|
||||||
{ name: "library_books", content: "Add Text", id: "addText" },
|
{ name: "library_books", content: "Add Text", id: WidgetType.Text },
|
||||||
{ name: "add_iframe", content: "Add Iframe", id: "addIframe" },
|
{ name: "add_iframe", content: "Add Iframe", id: WidgetType.ThirdPartyApp },
|
||||||
];
|
];
|
||||||
export const ServiceRelationTools = [
|
export const ServiceRelationTools = [
|
||||||
{ name: "playlist_add", content: "Add Widget", id: "addWidget" },
|
{ name: "playlist_add", content: "Add Widget", id: WidgetType.Widget },
|
||||||
{ name: "all_inbox", content: "Add Tabs", id: "addTab" },
|
{ name: "all_inbox", content: "Add Tabs", id: WidgetType.Tab },
|
||||||
{ name: "library_books", content: "Add Text", id: "addText" },
|
{ name: "library_books", content: "Add Text", id: WidgetType.Text },
|
||||||
{ name: "device_hub", content: "Add Topology", id: "addTopology" },
|
{ name: "device_hub", content: "Add Topology", id: WidgetType.Topology },
|
||||||
{ name: "add_iframe", content: "Add Iframe", id: "addIframe" },
|
{ name: "add_iframe", content: "Add Iframe", id: WidgetType.ThirdPartyApp },
|
||||||
];
|
];
|
||||||
|
|
||||||
export const EndpointRelationTools = [
|
export const EndpointRelationTools = [
|
||||||
{ name: "playlist_add", content: "Add Widget", id: "addWidget" },
|
{ name: "playlist_add", content: "Add Widget", id: WidgetType.Widget },
|
||||||
{ name: "all_inbox", content: "Add Tabs", id: "addTab" },
|
{ name: "all_inbox", content: "Add Tabs", id: WidgetType.Tab },
|
||||||
{ name: "library_books", content: "Add Text", id: "addText" },
|
{ name: "library_books", content: "Add Text", id: WidgetType.Text },
|
||||||
{ name: "add_iframe", content: "Add Iframe", id: "addIframe" },
|
{ name: "add_iframe", content: "Add Iframe", id: WidgetType.ThirdPartyApp },
|
||||||
];
|
];
|
||||||
export const InstanceRelationTools = [
|
export const InstanceRelationTools = [
|
||||||
{ name: "playlist_add", content: "Add Widget", id: "addWidget" },
|
{ name: "playlist_add", content: "Add Widget", id: WidgetType.Widget },
|
||||||
{ name: "all_inbox", content: "Add Tabs", id: "addTab" },
|
{ name: "all_inbox", content: "Add Tabs", id: WidgetType.Tab },
|
||||||
{ name: "library_books", content: "Add Text", id: "addText" },
|
{ name: "library_books", content: "Add Text", id: WidgetType.Text },
|
||||||
{ name: "device_hub", content: "Add Topology", id: "addTopology" },
|
{ name: "device_hub", content: "Add Topology", id: WidgetType.Topology },
|
||||||
{ name: "add_iframe", content: "Add Iframe", id: "addIframe" },
|
{ name: "add_iframe", content: "Add Iframe", id: WidgetType.ThirdPartyApp },
|
||||||
];
|
];
|
||||||
|
|
||||||
export const ScopeType = [
|
export const ScopeType = [
|
||||||
@@ -276,19 +241,6 @@ export const ScopeType = [
|
|||||||
{ value: "Endpoint", label: "Endpoint", key: 3 },
|
{ value: "Endpoint", label: "Endpoint", key: 3 },
|
||||||
{ value: "ServiceInstance", label: "Service Instance", key: 3 },
|
{ value: "ServiceInstance", label: "Service Instance", key: 3 },
|
||||||
];
|
];
|
||||||
export const LegendConditions = [
|
|
||||||
{ label: "&&", value: "and" },
|
|
||||||
{ label: "||", value: "or" },
|
|
||||||
];
|
|
||||||
export const MetricConditions = [
|
|
||||||
{ label: ">", value: ">" },
|
|
||||||
{ label: "<", value: "<" },
|
|
||||||
];
|
|
||||||
export enum LegendOpt {
|
|
||||||
NAME = "name",
|
|
||||||
VALUE = "value",
|
|
||||||
CONDITION = "condition",
|
|
||||||
}
|
|
||||||
export const DepthList = [1, 2, 3, 4, 5].map((item: number) => ({
|
export const DepthList = [1, 2, 3, 4, 5].map((item: number) => ({
|
||||||
value: item,
|
value: item,
|
||||||
label: String(item),
|
label: String(item),
|
||||||
@@ -313,24 +265,6 @@ export const TextColors: { [key: string]: string } = {
|
|||||||
purple: "#bf99f8",
|
purple: "#bf99f8",
|
||||||
};
|
};
|
||||||
|
|
||||||
export const CalculationOpts = [
|
|
||||||
{ label: "Percentage", value: "percentage" },
|
|
||||||
{ label: "Apdex", value: "apdex" },
|
|
||||||
{ label: "Avg-preview", value: "average" },
|
|
||||||
{ label: "Percentage + Avg-preview", value: "percentageAvg" },
|
|
||||||
{ label: "Apdex + Avg-preview", value: "apdexAvg" },
|
|
||||||
{ label: "Byte to KB", value: "byteToKB" },
|
|
||||||
{ label: "Byte to MB", value: "byteToMB" },
|
|
||||||
{ label: "Byte to GB", value: "byteToGB" },
|
|
||||||
{
|
|
||||||
label: "Milliseconds to YYYY-MM-DD HH:mm:ss",
|
|
||||||
value: "convertMilliseconds",
|
|
||||||
},
|
|
||||||
{ label: "Seconds to YYYY-MM-DD HH:mm:ss", value: "convertSeconds" },
|
|
||||||
{ label: "Milliseconds to seconds", value: "msTos" },
|
|
||||||
{ label: "Seconds to days", value: "secondToDay" },
|
|
||||||
{ label: "Nanoseconds to milliseconds", value: "nanosecondToMillisecond" },
|
|
||||||
];
|
|
||||||
export const RefIdTypes = [
|
export const RefIdTypes = [
|
||||||
{ label: "Trace ID", value: "traceId" },
|
{ label: "Trace ID", value: "traceId" },
|
||||||
{ label: "None", value: "none" },
|
{ label: "None", value: "none" },
|
||||||
@@ -341,11 +275,11 @@ export const RefreshOptions = [
|
|||||||
{ label: "Last 7 days", value: "7", step: "DAY" },
|
{ label: "Last 7 days", value: "7", step: "DAY" },
|
||||||
];
|
];
|
||||||
|
|
||||||
export enum MetricModes {
|
|
||||||
Expression = "Expression",
|
|
||||||
General = "General",
|
|
||||||
}
|
|
||||||
export enum CallTypes {
|
export enum CallTypes {
|
||||||
Server = "SERVER",
|
Server = "SERVER",
|
||||||
Client = "CLIENT",
|
Client = "CLIENT",
|
||||||
}
|
}
|
||||||
|
export enum ConfigFieldTypes {
|
||||||
|
ISDEFAULT = "ISDEFAULT",
|
||||||
|
NAME = "NAME",
|
||||||
|
}
|
||||||
|
@@ -40,8 +40,7 @@ limitations under the License. -->
|
|||||||
:config="{
|
:config="{
|
||||||
...config,
|
...config,
|
||||||
metricConfig,
|
metricConfig,
|
||||||
metricTypes,
|
typesOfMQE,
|
||||||
metricMode,
|
|
||||||
}"
|
}"
|
||||||
v-if="colMetrics.length"
|
v-if="colMetrics.length"
|
||||||
/>
|
/>
|
||||||
@@ -58,9 +57,8 @@ limitations under the License. -->
|
|||||||
import type { EndpointListConfig } from "@/types/dashboard";
|
import type { EndpointListConfig } from "@/types/dashboard";
|
||||||
import type { Endpoint } from "@/types/selector";
|
import type { Endpoint } from "@/types/selector";
|
||||||
import { useDashboardStore } from "@/store/modules/dashboard";
|
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||||
import { useQueryPodsMetrics, usePodsSource } from "@/hooks/useMetricsProcessor";
|
|
||||||
import { useExpressionsQueryPodsMetrics } from "@/hooks/useExpressionsProcessor";
|
import { useExpressionsQueryPodsMetrics } from "@/hooks/useExpressionsProcessor";
|
||||||
import { EntityType, MetricModes } from "../data";
|
import { EntityType } from "../data";
|
||||||
import router from "@/router";
|
import router from "@/router";
|
||||||
import getDashboard from "@/hooks/useDashboardsSession";
|
import getDashboard from "@/hooks/useDashboardsSession";
|
||||||
import type { MetricConfigOpt } from "@/types/dashboard";
|
import type { MetricConfigOpt } from "@/types/dashboard";
|
||||||
@@ -75,9 +73,6 @@ limitations under the License. -->
|
|||||||
type: Object as PropType<
|
type: Object as PropType<
|
||||||
EndpointListConfig & {
|
EndpointListConfig & {
|
||||||
i: string;
|
i: string;
|
||||||
metrics: string[];
|
|
||||||
metricTypes: string[];
|
|
||||||
metricMode: string;
|
|
||||||
expressions: string[];
|
expressions: string[];
|
||||||
typesOfMQE: string[];
|
typesOfMQE: string[];
|
||||||
subExpressions: string[];
|
subExpressions: string[];
|
||||||
@@ -85,8 +80,6 @@ limitations under the License. -->
|
|||||||
} & { metricConfig: MetricConfigOpt[] }
|
} & { metricConfig: MetricConfigOpt[] }
|
||||||
>,
|
>,
|
||||||
default: () => ({
|
default: () => ({
|
||||||
metrics: [],
|
|
||||||
metricTypes: [],
|
|
||||||
dashboardName: "",
|
dashboardName: "",
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
i: "",
|
i: "",
|
||||||
@@ -106,8 +99,7 @@ limitations under the License. -->
|
|||||||
const colMetrics = ref<string[]>([]);
|
const colMetrics = ref<string[]>([]);
|
||||||
const colSubMetrics = ref<string[]>([]);
|
const colSubMetrics = ref<string[]>([]);
|
||||||
const metricConfig = ref<MetricConfigOpt[]>(props.config.metricConfig || []);
|
const metricConfig = ref<MetricConfigOpt[]>(props.config.metricConfig || []);
|
||||||
const metricTypes = ref<string[]>(props.config.metricTypes || []);
|
const typesOfMQE = ref<string[]>(props.config.typesOfMQE || []);
|
||||||
const metricMode = ref<string>(props.config.metricMode);
|
|
||||||
|
|
||||||
if (props.needQuery) {
|
if (props.needQuery) {
|
||||||
queryEndpoints();
|
queryEndpoints();
|
||||||
@@ -138,34 +130,7 @@ limitations under the License. -->
|
|||||||
merge: d.merge,
|
merge: d.merge,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
if (props.config.metricMode === MetricModes.Expression) {
|
|
||||||
queryEndpointExpressions(currentPods);
|
queryEndpointExpressions(currentPods);
|
||||||
return;
|
|
||||||
}
|
|
||||||
const metrics = props.config.metrics || [];
|
|
||||||
const types = props.config.metricTypes || [];
|
|
||||||
if (metrics.length && metrics[0] && types.length && types[0]) {
|
|
||||||
const params = await useQueryPodsMetrics(currentPods, props.config, EntityType[2].value);
|
|
||||||
const json = await dashboardStore.fetchMetricValue(params);
|
|
||||||
|
|
||||||
if (json.errors) {
|
|
||||||
ElMessage.error(json.errors);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const { data, names, metricConfigArr, metricTypesArr } = usePodsSource(currentPods, json, {
|
|
||||||
...props.config,
|
|
||||||
metricConfig: metricConfig.value,
|
|
||||||
});
|
|
||||||
endpoints.value = data;
|
|
||||||
colMetrics.value = names;
|
|
||||||
metricTypes.value = metricTypesArr;
|
|
||||||
metricConfig.value = metricConfigArr;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
endpoints.value = currentPods;
|
|
||||||
colMetrics.value = [];
|
|
||||||
metricTypes.value = [];
|
|
||||||
metricConfig.value = [];
|
|
||||||
}
|
}
|
||||||
async function queryEndpointExpressions(currentPods: Endpoint[]) {
|
async function queryEndpointExpressions(currentPods: Endpoint[]) {
|
||||||
const expressions = props.config.expressions || [];
|
const expressions = props.config.expressions || [];
|
||||||
@@ -180,8 +145,8 @@ limitations under the License. -->
|
|||||||
endpoints.value = params.data;
|
endpoints.value = params.data;
|
||||||
colMetrics.value = params.names;
|
colMetrics.value = params.names;
|
||||||
colSubMetrics.value = params.subNames;
|
colSubMetrics.value = params.subNames;
|
||||||
metricTypes.value = params.metricTypesArr;
|
|
||||||
metricConfig.value = params.metricConfigArr;
|
metricConfig.value = params.metricConfigArr;
|
||||||
|
typesOfMQE.value = params.metricTypesArr;
|
||||||
emit("expressionTips", { tips: params.expressionsTips, subTips: params.subExpressionsTips });
|
emit("expressionTips", { tips: params.expressionsTips, subTips: params.subExpressionsTips });
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@@ -189,8 +154,8 @@ limitations under the License. -->
|
|||||||
endpoints.value = currentPods;
|
endpoints.value = currentPods;
|
||||||
colMetrics.value = [];
|
colMetrics.value = [];
|
||||||
colSubMetrics.value = [];
|
colSubMetrics.value = [];
|
||||||
metricTypes.value = [];
|
|
||||||
metricConfig.value = [];
|
metricConfig.value = [];
|
||||||
|
typesOfMQE.value = [];
|
||||||
emit("expressionTips", [], []);
|
emit("expressionTips", [], []);
|
||||||
}
|
}
|
||||||
function clickEndpoint(scope: any) {
|
function clickEndpoint(scope: any) {
|
||||||
@@ -212,19 +177,15 @@ limitations under the License. -->
|
|||||||
}
|
}
|
||||||
watch(
|
watch(
|
||||||
() => [
|
() => [
|
||||||
...(props.config.metricTypes || []),
|
|
||||||
...(props.config.metrics || []),
|
|
||||||
...(props.config.metricConfig || []),
|
...(props.config.metricConfig || []),
|
||||||
...(props.config.expressions || []),
|
...(props.config.expressions || []),
|
||||||
...(props.config.subExpressions || []),
|
...(props.config.subExpressions || []),
|
||||||
props.config.metricMode,
|
|
||||||
],
|
],
|
||||||
(data, old) => {
|
(data, old) => {
|
||||||
if (JSON.stringify(data) === JSON.stringify(old)) {
|
if (JSON.stringify(data) === JSON.stringify(old)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
metricConfig.value = props.config.metricConfig;
|
metricConfig.value = props.config.metricConfig;
|
||||||
metricMode.value = props.config.metricMode;
|
|
||||||
queryEndpointMetrics(endpoints.value);
|
queryEndpointMetrics(endpoints.value);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
@@ -39,8 +39,7 @@ limitations under the License. -->
|
|||||||
:config="{
|
:config="{
|
||||||
...config,
|
...config,
|
||||||
metricConfig,
|
metricConfig,
|
||||||
metricTypes,
|
typesOfMQE,
|
||||||
metricMode,
|
|
||||||
}"
|
}"
|
||||||
v-if="colMetrics.length"
|
v-if="colMetrics.length"
|
||||||
/>
|
/>
|
||||||
@@ -68,9 +67,10 @@ limitations under the License. -->
|
|||||||
<el-pagination
|
<el-pagination
|
||||||
class="pagination flex-h"
|
class="pagination flex-h"
|
||||||
layout="prev, pager, next"
|
layout="prev, pager, next"
|
||||||
|
:current-page="currentPage"
|
||||||
:page-size="pageSize"
|
:page-size="pageSize"
|
||||||
:total="pods.length"
|
:total="searchText ? pods.filter((d: any) => d.label.includes(searchText)).length : pods.length"
|
||||||
@current-change="changePage"
|
@current-change="handleCurrentChange"
|
||||||
@prev-click="changePage"
|
@prev-click="changePage"
|
||||||
@next-click="changePage"
|
@next-click="changePage"
|
||||||
/>
|
/>
|
||||||
@@ -85,9 +85,8 @@ limitations under the License. -->
|
|||||||
import { useDashboardStore } from "@/store/modules/dashboard";
|
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||||
import type { InstanceListConfig } from "@/types/dashboard";
|
import type { InstanceListConfig } from "@/types/dashboard";
|
||||||
import type { Instance } from "@/types/selector";
|
import type { Instance } from "@/types/selector";
|
||||||
import { useQueryPodsMetrics, usePodsSource } from "@/hooks/useMetricsProcessor";
|
|
||||||
import { useExpressionsQueryPodsMetrics } from "@/hooks/useExpressionsProcessor";
|
import { useExpressionsQueryPodsMetrics } from "@/hooks/useExpressionsProcessor";
|
||||||
import { EntityType, MetricModes } from "../data";
|
import { EntityType } from "../data";
|
||||||
import router from "@/router";
|
import router from "@/router";
|
||||||
import getDashboard from "@/hooks/useDashboardsSession";
|
import getDashboard from "@/hooks/useDashboardsSession";
|
||||||
import type { MetricConfigOpt } from "@/types/dashboard";
|
import type { MetricConfigOpt } from "@/types/dashboard";
|
||||||
@@ -100,9 +99,7 @@ limitations under the License. -->
|
|||||||
InstanceListConfig & {
|
InstanceListConfig & {
|
||||||
i: string;
|
i: string;
|
||||||
metrics: string[];
|
metrics: string[];
|
||||||
metricTypes: string[];
|
|
||||||
isEdit: boolean;
|
isEdit: boolean;
|
||||||
metricMode: string;
|
|
||||||
expressions: string[];
|
expressions: string[];
|
||||||
typesOfMQE: string[];
|
typesOfMQE: string[];
|
||||||
subExpressions: string[];
|
subExpressions: string[];
|
||||||
@@ -114,7 +111,7 @@ limitations under the License. -->
|
|||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
i: "",
|
i: "",
|
||||||
metrics: [],
|
metrics: [],
|
||||||
metricTypes: [],
|
typesOfMQE: [],
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
intervalTime: { type: Array as PropType<string[]>, default: () => [] },
|
intervalTime: { type: Array as PropType<string[]>, default: () => [] },
|
||||||
@@ -126,14 +123,15 @@ limitations under the License. -->
|
|||||||
const dashboardStore = useDashboardStore();
|
const dashboardStore = useDashboardStore();
|
||||||
const chartLoading = ref<boolean>(false);
|
const chartLoading = ref<boolean>(false);
|
||||||
const instances = ref<Instance[]>([]); // current instances
|
const instances = ref<Instance[]>([]); // current instances
|
||||||
|
const currentPage = ref<number>(1);
|
||||||
const pageSize = 10;
|
const pageSize = 10;
|
||||||
const searchText = ref<string>("");
|
const searchText = ref<string>("");
|
||||||
const colMetrics = ref<string[]>([]);
|
const colMetrics = ref<string[]>([]);
|
||||||
const colSubMetrics = ref<string[]>([]);
|
const colSubMetrics = ref<string[]>([]);
|
||||||
const metricConfig = ref<MetricConfigOpt[]>(props.config.metricConfig || []);
|
const metricConfig = ref<MetricConfigOpt[]>(props.config.metricConfig || []);
|
||||||
const metricTypes = ref<string[]>(props.config.metricTypes || []);
|
|
||||||
const pods = ref<Instance[]>([]); // all instances
|
const pods = ref<Instance[]>([]); // all instances
|
||||||
const metricMode = ref<string>(props.config.metricMode);
|
const typesOfMQE = ref<string[]>(props.config.typesOfMQE || []);
|
||||||
|
|
||||||
if (props.needQuery) {
|
if (props.needQuery) {
|
||||||
queryInstance();
|
queryInstance();
|
||||||
}
|
}
|
||||||
@@ -169,36 +167,7 @@ limitations under the License. -->
|
|||||||
attributes: d.attributes,
|
attributes: d.attributes,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
if (props.config.metricMode === MetricModes.Expression) {
|
|
||||||
queryInstanceExpressions(currentInstances);
|
queryInstanceExpressions(currentInstances);
|
||||||
return;
|
|
||||||
}
|
|
||||||
const metrics = props.config.metrics || [];
|
|
||||||
const types = props.config.metricTypes || [];
|
|
||||||
|
|
||||||
if (metrics.length && metrics[0] && types.length && types[0]) {
|
|
||||||
const params = await useQueryPodsMetrics(currentInstances, props.config, EntityType[3].value);
|
|
||||||
const json = await dashboardStore.fetchMetricValue(params);
|
|
||||||
|
|
||||||
if (json.errors) {
|
|
||||||
ElMessage.error(json.errors);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const { data, names, metricConfigArr, metricTypesArr } = usePodsSource(currentInstances, json, {
|
|
||||||
...props.config,
|
|
||||||
metricConfig: metricConfig.value,
|
|
||||||
});
|
|
||||||
instances.value = data;
|
|
||||||
colMetrics.value = names;
|
|
||||||
metricTypes.value = metricTypesArr;
|
|
||||||
metricConfig.value = metricConfigArr;
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
instances.value = currentInstances;
|
|
||||||
colMetrics.value = [];
|
|
||||||
metricTypes.value = [];
|
|
||||||
metricConfig.value = [];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function queryInstanceExpressions(currentInstances: Instance[]) {
|
async function queryInstanceExpressions(currentInstances: Instance[]) {
|
||||||
@@ -214,7 +183,7 @@ limitations under the License. -->
|
|||||||
instances.value = params.data;
|
instances.value = params.data;
|
||||||
colMetrics.value = params.names;
|
colMetrics.value = params.names;
|
||||||
colSubMetrics.value = params.subNames;
|
colSubMetrics.value = params.subNames;
|
||||||
metricTypes.value = params.metricTypesArr;
|
typesOfMQE.value = params.metricTypesArr;
|
||||||
metricConfig.value = params.metricConfigArr;
|
metricConfig.value = params.metricConfigArr;
|
||||||
emit("expressionTips", { tips: params.expressionsTips, subTips: params.subExpressionsTips });
|
emit("expressionTips", { tips: params.expressionsTips, subTips: params.subExpressionsTips });
|
||||||
|
|
||||||
@@ -223,7 +192,7 @@ limitations under the License. -->
|
|||||||
instances.value = currentInstances;
|
instances.value = currentInstances;
|
||||||
colSubMetrics.value = [];
|
colSubMetrics.value = [];
|
||||||
colMetrics.value = [];
|
colMetrics.value = [];
|
||||||
metricTypes.value = [];
|
typesOfMQE.value = [];
|
||||||
metricConfig.value = [];
|
metricConfig.value = [];
|
||||||
emit("expressionTips", [], []);
|
emit("expressionTips", [], []);
|
||||||
}
|
}
|
||||||
@@ -245,36 +214,40 @@ limitations under the License. -->
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function changePage(pageIndex: number) {
|
function changePage() {
|
||||||
instances.value = pods.value.filter((d: unknown, index: number) => {
|
let podList = pods.value;
|
||||||
if (index >= (pageIndex - 1) * pageSize && index < pageIndex * pageSize) {
|
if (searchText.value) {
|
||||||
return d;
|
podList = pods.value.filter((d: { label: string }) => d.label.includes(searchText.value));
|
||||||
}
|
}
|
||||||
});
|
instances.value = podList.filter(
|
||||||
|
(_, index: number) => index >= (currentPage.value - 1) * pageSize && index < currentPage.value * pageSize,
|
||||||
|
);
|
||||||
queryInstanceMetrics(instances.value);
|
queryInstanceMetrics(instances.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleCurrentChange(val: number) {
|
||||||
|
currentPage.value = val;
|
||||||
|
changePage();
|
||||||
|
}
|
||||||
|
|
||||||
function searchList() {
|
function searchList() {
|
||||||
const searchInstances = pods.value.filter((d: { label: string }) => d.label.includes(searchText.value));
|
const searchInstances = pods.value.filter((d: { label: string }) => d.label.includes(searchText.value));
|
||||||
instances.value = searchInstances.filter((d: unknown, index: number) => index < pageSize);
|
instances.value = searchInstances.filter((_, index: number) => index < pageSize);
|
||||||
queryInstanceMetrics(instances.value);
|
queryInstanceMetrics(instances.value);
|
||||||
|
currentPage.value = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => [
|
() => [
|
||||||
...(props.config.metricTypes || []),
|
|
||||||
...(props.config.metrics || []),
|
|
||||||
...(props.config.metricConfig || []),
|
...(props.config.metricConfig || []),
|
||||||
...(props.config.expressions || []),
|
...(props.config.expressions || []),
|
||||||
...(props.config.subExpressions || []),
|
...(props.config.subExpressions || []),
|
||||||
props.config.metricMode,
|
|
||||||
],
|
],
|
||||||
(data, old) => {
|
(data, old) => {
|
||||||
if (JSON.stringify(data) === JSON.stringify(old)) {
|
if (JSON.stringify(data) === JSON.stringify(old)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
metricConfig.value = props.config.metricConfig;
|
metricConfig.value = props.config.metricConfig;
|
||||||
metricMode.value = props.config.metricMode;
|
|
||||||
queryInstanceMetrics(instances.value);
|
queryInstanceMetrics(instances.value);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
@@ -51,8 +51,7 @@ limitations under the License. -->
|
|||||||
:config="{
|
:config="{
|
||||||
...config,
|
...config,
|
||||||
metricConfig,
|
metricConfig,
|
||||||
metricTypes,
|
typesOfMQE,
|
||||||
metricMode,
|
|
||||||
}"
|
}"
|
||||||
v-if="colMetrics.length"
|
v-if="colMetrics.length"
|
||||||
/>
|
/>
|
||||||
@@ -61,9 +60,10 @@ limitations under the License. -->
|
|||||||
<el-pagination
|
<el-pagination
|
||||||
class="pagination flex-h"
|
class="pagination flex-h"
|
||||||
layout="prev, pager, next"
|
layout="prev, pager, next"
|
||||||
|
:current-page="currentPage"
|
||||||
:page-size="pageSize"
|
:page-size="pageSize"
|
||||||
:total="selectorStore.services.length"
|
:total="searchText ? sortServices.filter((d: any) => d.label.includes(searchText)).length : sortServices.length"
|
||||||
@current-change="changePage"
|
@current-change="handleCurrentChange"
|
||||||
@prev-click="changePage"
|
@prev-click="changePage"
|
||||||
@next-click="changePage"
|
@next-click="changePage"
|
||||||
/>
|
/>
|
||||||
@@ -78,9 +78,8 @@ limitations under the License. -->
|
|||||||
import { useDashboardStore } from "@/store/modules/dashboard";
|
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||||
import { useAppStoreWithOut } from "@/store/modules/app";
|
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||||
import type { Service } from "@/types/selector";
|
import type { Service } from "@/types/selector";
|
||||||
import { useQueryPodsMetrics, usePodsSource } from "@/hooks/useMetricsProcessor";
|
|
||||||
import { useExpressionsQueryPodsMetrics } from "@/hooks/useExpressionsProcessor";
|
import { useExpressionsQueryPodsMetrics } from "@/hooks/useExpressionsProcessor";
|
||||||
import { EntityType, MetricModes } from "../data";
|
import { EntityType } from "../data";
|
||||||
import router from "@/router";
|
import router from "@/router";
|
||||||
import getDashboard from "@/hooks/useDashboardsSession";
|
import getDashboard from "@/hooks/useDashboardsSession";
|
||||||
import type { MetricConfigOpt } from "@/types/dashboard";
|
import type { MetricConfigOpt } from "@/types/dashboard";
|
||||||
@@ -95,12 +94,9 @@ limitations under the License. -->
|
|||||||
type: Object as PropType<
|
type: Object as PropType<
|
||||||
ServiceListConfig & {
|
ServiceListConfig & {
|
||||||
i: string;
|
i: string;
|
||||||
metrics: string[];
|
|
||||||
metricTypes: string[];
|
|
||||||
isEdit: boolean;
|
isEdit: boolean;
|
||||||
names: string[];
|
names: string[];
|
||||||
metricConfig: MetricConfigOpt[];
|
metricConfig: MetricConfigOpt[];
|
||||||
metricMode: string;
|
|
||||||
expressions: string[];
|
expressions: string[];
|
||||||
typesOfMQE: string[];
|
typesOfMQE: string[];
|
||||||
subExpressions: string[];
|
subExpressions: string[];
|
||||||
@@ -117,6 +113,7 @@ limitations under the License. -->
|
|||||||
const dashboardStore = useDashboardStore();
|
const dashboardStore = useDashboardStore();
|
||||||
const appStore = useAppStoreWithOut();
|
const appStore = useAppStoreWithOut();
|
||||||
const chartLoading = ref<boolean>(false);
|
const chartLoading = ref<boolean>(false);
|
||||||
|
const currentPage = ref<number>(1);
|
||||||
const pageSize = 10;
|
const pageSize = 10;
|
||||||
const services = ref<Service[]>([]);
|
const services = ref<Service[]>([]);
|
||||||
const colMetrics = ref<string[]>([]);
|
const colMetrics = ref<string[]>([]);
|
||||||
@@ -125,8 +122,7 @@ limitations under the License. -->
|
|||||||
const groups = ref<any>({});
|
const groups = ref<any>({});
|
||||||
const sortServices = ref<(Service & { merge: boolean })[]>([]);
|
const sortServices = ref<(Service & { merge: boolean })[]>([]);
|
||||||
const metricConfig = ref<MetricConfigOpt[]>(props.config.metricConfig || []);
|
const metricConfig = ref<MetricConfigOpt[]>(props.config.metricConfig || []);
|
||||||
const metricTypes = ref<string[]>(props.config.metricTypes || []);
|
const typesOfMQE = ref<string[]>(props.config.typesOfMQE || []);
|
||||||
const metricMode = ref<string>(props.config.metricMode);
|
|
||||||
|
|
||||||
queryServices();
|
queryServices();
|
||||||
|
|
||||||
@@ -211,43 +207,7 @@ limitations under the License. -->
|
|||||||
shortName: d.shortName,
|
shortName: d.shortName,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
if (props.config.metricMode === MetricModes.Expression) {
|
|
||||||
queryServiceExpressions(currentServices);
|
queryServiceExpressions(currentServices);
|
||||||
return;
|
|
||||||
}
|
|
||||||
const metrics = props.config.metrics || [];
|
|
||||||
const types = props.config.metricTypes || [];
|
|
||||||
|
|
||||||
if (metrics.length && metrics[0] && types.length && types[0]) {
|
|
||||||
const params = await useQueryPodsMetrics(
|
|
||||||
currentServices,
|
|
||||||
{ ...props.config, metricConfig: metricConfig.value || [] },
|
|
||||||
EntityType[0].value,
|
|
||||||
);
|
|
||||||
const json = await dashboardStore.fetchMetricValue(params);
|
|
||||||
|
|
||||||
if (json.errors) {
|
|
||||||
ElMessage.error(json.errors);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const { data, names, metricConfigArr, metricTypesArr } = usePodsSource(currentServices, json, {
|
|
||||||
...props.config,
|
|
||||||
metricConfig: metricConfig.value || [],
|
|
||||||
});
|
|
||||||
|
|
||||||
services.value = data;
|
|
||||||
colMetrics.value = names;
|
|
||||||
metricTypes.value = metricTypesArr;
|
|
||||||
metricConfig.value = metricConfigArr;
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
services.value = currentServices;
|
|
||||||
colMetrics.value = [];
|
|
||||||
colMetrics.value = [];
|
|
||||||
metricTypes.value = [];
|
|
||||||
metricConfig.value = [];
|
|
||||||
}
|
}
|
||||||
async function queryServiceExpressions(currentServices: Service[]) {
|
async function queryServiceExpressions(currentServices: Service[]) {
|
||||||
const expressions = props.config.expressions || [];
|
const expressions = props.config.expressions || [];
|
||||||
@@ -262,16 +222,16 @@ limitations under the License. -->
|
|||||||
services.value = params.data;
|
services.value = params.data;
|
||||||
colMetrics.value = params.names;
|
colMetrics.value = params.names;
|
||||||
colSubMetrics.value = params.subNames;
|
colSubMetrics.value = params.subNames;
|
||||||
metricTypes.value = params.metricTypesArr;
|
|
||||||
metricConfig.value = params.metricConfigArr;
|
metricConfig.value = params.metricConfigArr;
|
||||||
|
typesOfMQE.value = params.metricTypesArr;
|
||||||
emit("expressionTips", { tips: params.expressionsTips, subTips: params.subExpressionsTips });
|
emit("expressionTips", { tips: params.expressionsTips, subTips: params.subExpressionsTips });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
services.value = currentServices;
|
services.value = currentServices;
|
||||||
colMetrics.value = [];
|
colMetrics.value = [];
|
||||||
colSubMetrics.value = [];
|
colSubMetrics.value = [];
|
||||||
metricTypes.value = [];
|
|
||||||
metricConfig.value = [];
|
metricConfig.value = [];
|
||||||
|
typesOfMQE.value = [];
|
||||||
emit("expressionTips", [], []);
|
emit("expressionTips", [], []);
|
||||||
}
|
}
|
||||||
function objectSpanMethod(param: any): any {
|
function objectSpanMethod(param: any): any {
|
||||||
@@ -289,36 +249,41 @@ limitations under the License. -->
|
|||||||
}
|
}
|
||||||
return { rowspan: groups.value[param.row.group], colspan: 1 };
|
return { rowspan: groups.value[param.row.group], colspan: 1 };
|
||||||
}
|
}
|
||||||
function changePage(pageIndex: number) {
|
function changePage() {
|
||||||
const arr = sortServices.value.filter((d: Service, index: number) => {
|
let services = sortServices.value;
|
||||||
if (index >= (pageIndex - 1) * pageSize && index < pageSize * pageIndex) {
|
if (searchText.value) {
|
||||||
|
services = sortServices.value.filter((d: { label: string }) => d.label.includes(searchText.value));
|
||||||
|
}
|
||||||
|
const arr = services.filter((d: Service, index: number) => {
|
||||||
|
if (index >= (currentPage.value - 1) * pageSize && index < pageSize * currentPage.value) {
|
||||||
return d;
|
return d;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
setServices(arr);
|
setServices(arr);
|
||||||
}
|
}
|
||||||
|
function handleCurrentChange(val: number) {
|
||||||
|
currentPage.value = val;
|
||||||
|
changePage();
|
||||||
|
}
|
||||||
function searchList() {
|
function searchList() {
|
||||||
const searchServices = sortServices.value.filter((d: { label: string }) => d.label.includes(searchText.value));
|
const searchServices = sortServices.value.filter((d: { label: string }) => d.label.includes(searchText.value));
|
||||||
const services = searchServices.filter((d: unknown, index: number) => index < pageSize);
|
const services = searchServices.filter((_, index: number) => index < pageSize);
|
||||||
setServices(services);
|
setServices(services);
|
||||||
|
currentPage.value = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => [
|
() => [
|
||||||
...(props.config.metricTypes || []),
|
|
||||||
...(props.config.metrics || []),
|
|
||||||
...(props.config.metricConfig || []),
|
...(props.config.metricConfig || []),
|
||||||
...(props.config.expressions || []),
|
...(props.config.expressions || []),
|
||||||
...(props.config.subExpressions || []),
|
...(props.config.subExpressions || []),
|
||||||
props.config.metricMode,
|
|
||||||
],
|
],
|
||||||
(data, old) => {
|
(data, old) => {
|
||||||
if (JSON.stringify(data) === JSON.stringify(old)) {
|
if (JSON.stringify(data) === JSON.stringify(old)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
metricConfig.value = props.config.metricConfig;
|
metricConfig.value = props.config.metricConfig;
|
||||||
metricMode.value = props.config.metricMode;
|
|
||||||
queryServiceMetrics(services.value);
|
queryServiceMetrics(services.value);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
@@ -14,22 +14,34 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License. -->
|
limitations under the License. -->
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="chart-table">
|
<div class="chart-table" v-if="dataKeys.length">
|
||||||
<div class="row header flex-h">
|
<div class="row header flex-h">
|
||||||
<div class="name" :style="`width: ${nameWidth}`">
|
<div
|
||||||
{{ config.tableHeaderCol1 || t("name") }}
|
v-for="key in dataKeys[0]"
|
||||||
|
:key="key"
|
||||||
|
class="name"
|
||||||
|
:style="`width: ${dataKeys[0].length > 1 ? (nameWidth as number) / (dataKeys[0].length || 1) : nameWidth}%`"
|
||||||
|
>
|
||||||
|
{{ key.split("=")[0] || t("name") }}
|
||||||
</div>
|
</div>
|
||||||
<div class="value-col" v-if="config.showTableValues">
|
<div class="value-col" v-if="config.showTableValues">
|
||||||
{{ config.tableHeaderCol2 || t("value") }}
|
{{ config.tableHeaderCol2 || t("value") }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row flex-h" v-for="key in dataKeys" :key="key">
|
<div class="row flex-h" v-for="(keys, index) in dataKeys" :key="index">
|
||||||
<div class="name" :style="`width: ${nameWidth}`">{{ key }}</div>
|
<div
|
||||||
|
v-for="k in keys"
|
||||||
|
class="name"
|
||||||
|
:style="`width: ${keys.length > 1 ? (nameWidth as number) / (keys.length || 1) : nameWidth}%`"
|
||||||
|
:key="k"
|
||||||
|
>{{ k.split("=")[1] }}</div
|
||||||
|
>
|
||||||
<div class="value-col" v-if="config.showTableValues">
|
<div class="value-col" v-if="config.showTableValues">
|
||||||
{{ config.metricTypes[0] === "readMetricsValue" ? data[key] : data[key][data[key].length - 1 || 0] }}
|
{{ data[(keys as string[]).join(",")][data[(keys as string[]).join(",")].length - 1 || 0] }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="table-no-data" v-else>No Data</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed } from "vue";
|
import { computed } from "vue";
|
||||||
@@ -45,24 +57,21 @@ limitations under the License. -->
|
|||||||
type: Object as PropType<{
|
type: Object as PropType<{
|
||||||
showTableValues: boolean;
|
showTableValues: boolean;
|
||||||
tableHeaderCol2: string;
|
tableHeaderCol2: string;
|
||||||
tableHeaderCol1: string;
|
typesOfMQE: string[];
|
||||||
metricTypes: string[];
|
|
||||||
}>,
|
}>,
|
||||||
default: () => ({ showTableValues: true }),
|
default: () => ({ showTableValues: true }),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const nameWidth = computed(() => (props.config.showTableValues ? "80%" : "100%"));
|
const nameWidth = computed(() => (props.config.showTableValues ? 80 : 100));
|
||||||
const dataKeys = computed(() => {
|
const dataKeys = computed(() => {
|
||||||
if (props.config.metricTypes[0] === "readMetricsValue") {
|
|
||||||
const keys = Object.keys(props.data || {});
|
|
||||||
return keys;
|
|
||||||
}
|
|
||||||
const keys = Object.keys(props.data || {}).filter(
|
const keys = Object.keys(props.data || {}).filter(
|
||||||
(i: string) => Array.isArray(props.data[i]) && props.data[i].length,
|
(i: string) => Array.isArray(props.data[i]) && props.data[i].length,
|
||||||
);
|
);
|
||||||
return keys;
|
const list = keys.map((d: string) => d.split(","));
|
||||||
|
|
||||||
|
return list;
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@@ -94,6 +103,10 @@ limitations under the License. -->
|
|||||||
border-bottom: 1px solid $disabled-color;
|
border-bottom: 1px solid $disabled-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
div:first-child {
|
||||||
|
border-bottom: 1px solid $disabled-color;
|
||||||
|
}
|
||||||
|
|
||||||
div:nth-last-child(2) {
|
div:nth-last-child(2) {
|
||||||
border-bottom: 1px solid $disabled-color;
|
border-bottom: 1px solid $disabled-color;
|
||||||
}
|
}
|
||||||
@@ -119,4 +132,13 @@ limitations under the License. -->
|
|||||||
width: 50%;
|
width: 50%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.table-no-data {
|
||||||
|
font-size: $font-size-smaller;
|
||||||
|
height: 100%;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
display: flex;
|
||||||
|
color: var(--text-color-placeholder);
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@@ -64,7 +64,7 @@ limitations under the License. -->
|
|||||||
import copy from "@/utils/copy";
|
import copy from "@/utils/copy";
|
||||||
import { TextColors } from "@/views/dashboard/data";
|
import { TextColors } from "@/views/dashboard/data";
|
||||||
import Trace from "@/views/dashboard/related/trace/Index.vue";
|
import Trace from "@/views/dashboard/related/trace/Index.vue";
|
||||||
import { QueryOrders, Status, RefIdTypes, ProtocolTypes, ExpressionResultType } from "../data";
|
import { WidgetType, QueryOrders, Status, RefIdTypes, ExpressionResultType } from "@/views/dashboard/data";
|
||||||
|
|
||||||
/*global defineProps */
|
/*global defineProps */
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
@@ -76,10 +76,8 @@ limitations under the License. -->
|
|||||||
},
|
},
|
||||||
config: {
|
config: {
|
||||||
type: Object as PropType<{
|
type: Object as PropType<{
|
||||||
metricMode: string;
|
|
||||||
color: string;
|
color: string;
|
||||||
metrics: string[];
|
expressions: string[];
|
||||||
metricTypes: string[];
|
|
||||||
typesOfMQE: string[];
|
typesOfMQE: string[];
|
||||||
relatedTrace: any;
|
relatedTrace: any;
|
||||||
}>,
|
}>,
|
||||||
@@ -90,7 +88,7 @@ limitations under the License. -->
|
|||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const showTrace = ref<boolean>(false);
|
const showTrace = ref<boolean>(false);
|
||||||
const traceOptions = ref<{ type: string; filters?: unknown }>({
|
const traceOptions = ref<{ type: string; filters?: unknown }>({
|
||||||
type: "Trace",
|
type: WidgetType.Trace,
|
||||||
});
|
});
|
||||||
const refIdType = computed(
|
const refIdType = computed(
|
||||||
() => (props.config.relatedTrace && props.config.relatedTrace.refIdType) || RefIdTypes[0].value,
|
() => (props.config.relatedTrace && props.config.relatedTrace.refIdType) || RefIdTypes[0].value,
|
||||||
@@ -115,11 +113,8 @@ limitations under the License. -->
|
|||||||
queryOrder: QueryOrders[1].value,
|
queryOrder: QueryOrders[1].value,
|
||||||
status: Status[2].value,
|
status: Status[2].value,
|
||||||
id: item.refId,
|
id: item.refId,
|
||||||
metricValue: [{ label: props.config.metrics[0], data: item.value, value: item.name }],
|
metricValue: [{ label: props.config.expressions[0], data: item.value, value: item.name }],
|
||||||
isReadRecords:
|
isReadRecords: props.config.typesOfMQE.includes(ExpressionResultType.RECORD_LIST) || undefined,
|
||||||
props.config.typesOfMQE.includes(ExpressionResultType.RECORD_LIST) ||
|
|
||||||
props.config.metricTypes.includes(ProtocolTypes.ReadRecords) ||
|
|
||||||
undefined,
|
|
||||||
};
|
};
|
||||||
traceOptions.value = {
|
traceOptions.value = {
|
||||||
...traceOptions.value,
|
...traceOptions.value,
|
||||||
|
@@ -22,23 +22,7 @@ limitations under the License. -->
|
|||||||
>
|
>
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<div class="chart">
|
<div class="chart">
|
||||||
<Line
|
<span class="item flex-h">
|
||||||
v-if="useListConfig(config, index).isLinear && config.metricMode !== MetricModes.Expression"
|
|
||||||
:data="{
|
|
||||||
[metric]: scope.row[metric] && scope.row[metric].values,
|
|
||||||
}"
|
|
||||||
:intervalTime="intervalTime"
|
|
||||||
:config="{
|
|
||||||
showXAxis: false,
|
|
||||||
showYAxis: false,
|
|
||||||
smallTips: true,
|
|
||||||
showlabels: false,
|
|
||||||
}"
|
|
||||||
/>
|
|
||||||
<span
|
|
||||||
class="item flex-h"
|
|
||||||
v-else-if="useListConfig(config, index).isAvg || config.metricMode === MetricModes.Expression"
|
|
||||||
>
|
|
||||||
<el-popover placement="left" :width="400" trigger="click">
|
<el-popover placement="left" :width="400" trigger="click">
|
||||||
<template #reference>
|
<template #reference>
|
||||||
<span class="trend">
|
<span class="trend">
|
||||||
@@ -70,7 +54,6 @@ limitations under the License. -->
|
|||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
<Card v-else :data="{ [metric]: scope.row[metric] }" :config="{ textAlign: 'left' }" />
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
@@ -79,11 +62,9 @@ limitations under the License. -->
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import type { PropType } from "vue";
|
import type { PropType } from "vue";
|
||||||
import type { MetricConfigOpt } from "@/types/dashboard";
|
import type { MetricConfigOpt } from "@/types/dashboard";
|
||||||
import { useListConfig } from "@/hooks/useListConfig";
|
|
||||||
import Line from "../Line.vue";
|
import Line from "../Line.vue";
|
||||||
import Card from "../Card.vue";
|
import Card from "../Card.vue";
|
||||||
import { MetricQueryTypes } from "@/hooks/data";
|
import { ExpressionResultType } from "@/views/dashboard/data";
|
||||||
import { ExpressionResultType, MetricModes } from "@/views/dashboard/data";
|
|
||||||
|
|
||||||
/*global defineProps */
|
/*global defineProps */
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
@@ -92,9 +73,8 @@ limitations under the License. -->
|
|||||||
config: {
|
config: {
|
||||||
type: Object as PropType<{
|
type: Object as PropType<{
|
||||||
i: string;
|
i: string;
|
||||||
metricTypes: string[];
|
typesOfMQE: string[];
|
||||||
metricConfig: MetricConfigOpt[];
|
metricConfig: MetricConfigOpt[];
|
||||||
metricMode: string;
|
|
||||||
}>,
|
}>,
|
||||||
default: () => ({}),
|
default: () => ({}),
|
||||||
},
|
},
|
||||||
@@ -120,13 +100,9 @@ limitations under the License. -->
|
|||||||
}
|
}
|
||||||
if (label) {
|
if (label) {
|
||||||
if (
|
if (
|
||||||
(
|
([ExpressionResultType.TIME_SERIES_VALUES, ExpressionResultType.SINGLE_VALUE] as string[]).includes(
|
||||||
[
|
props.config.typesOfMQE[i],
|
||||||
MetricQueryTypes.ReadLabeledMetricsValues,
|
)
|
||||||
ExpressionResultType.TIME_SERIES_VALUES,
|
|
||||||
ExpressionResultType.SINGLE_VALUE,
|
|
||||||
] as string[]
|
|
||||||
).includes(props.config.metricTypes[i])
|
|
||||||
) {
|
) {
|
||||||
const name = (label || "").split(",").map((item: string) => item.replace(/^\s*|\s*$/g, ""))[
|
const name = (label || "").split(",").map((item: string) => item.replace(/^\s*|\s*$/g, ""))[
|
||||||
props.config.metricConfig[i].index || 0
|
props.config.metricConfig[i].index || 0
|
||||||
|
@@ -14,12 +14,15 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License. -->
|
limitations under the License. -->
|
||||||
<template>
|
<template>
|
||||||
<grid-layout
|
<grid-layout
|
||||||
|
v-if="dashboardStore.layout.length"
|
||||||
v-model:layout="dashboardStore.layout"
|
v-model:layout="dashboardStore.layout"
|
||||||
:col-num="24"
|
:col-num="24"
|
||||||
:row-height="10"
|
:row-height="10"
|
||||||
:is-draggable="dashboardStore.editMode"
|
:is-draggable="dashboardStore.editMode"
|
||||||
:is-resizable="dashboardStore.editMode"
|
:is-resizable="dashboardStore.editMode"
|
||||||
v-if="dashboardStore.layout.length"
|
v-loading.fullscreen.lock="loading"
|
||||||
|
element-loading-text="Loading..."
|
||||||
|
element-loading-background="rgba(122, 122, 122, 0.8)"
|
||||||
>
|
>
|
||||||
<grid-item
|
<grid-item
|
||||||
v-for="item in dashboardStore.layout"
|
v-for="item in dashboardStore.layout"
|
||||||
@@ -33,35 +36,87 @@ limitations under the License. -->
|
|||||||
:class="{ active: dashboardStore.activedGridItem === item.i }"
|
:class="{ active: dashboardStore.activedGridItem === item.i }"
|
||||||
:drag-ignore-from="dragIgnoreFrom"
|
:drag-ignore-from="dragIgnoreFrom"
|
||||||
>
|
>
|
||||||
<component :is="item.type" :data="item" />
|
<component :is="item.type" :data="item" :metricsValues="metricsValues" />
|
||||||
</grid-item>
|
</grid-item>
|
||||||
</grid-layout>
|
</grid-layout>
|
||||||
<div class="no-data-tips" v-else>{{ t("noWidget") }}</div>
|
<div class="no-data-tips" v-else>{{ t("noWidget") }}</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent, onBeforeUnmount } from "vue";
|
import { defineComponent, onBeforeUnmount, watch, ref } from "vue";
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
|
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||||
import { useDashboardStore } from "@/store/modules/dashboard";
|
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||||
import { useSelectorStore } from "@/store/modules/selectors";
|
import { useSelectorStore } from "@/store/modules/selectors";
|
||||||
import type { LayoutConfig } from "@/types/dashboard";
|
import type { LayoutConfig } from "@/types/dashboard";
|
||||||
import controls from "../controls/index";
|
import controls from "../controls/index";
|
||||||
import { dragIgnoreFrom } from "../data";
|
import { dragIgnoreFrom, ListChartTypes, WidgetType } from "../data";
|
||||||
|
import { useDashboardQueryProcessor } from "@/hooks/useExpressionsProcessor";
|
||||||
|
import { EntityType } from "../data";
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: "Layout",
|
name: "Layout",
|
||||||
components: { ...controls },
|
components: { ...controls },
|
||||||
setup() {
|
setup() {
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
const appStore = useAppStoreWithOut();
|
||||||
const dashboardStore = useDashboardStore();
|
const dashboardStore = useDashboardStore();
|
||||||
const selectorStore = useSelectorStore();
|
const selectorStore = useSelectorStore();
|
||||||
|
const metricsValues = ref();
|
||||||
|
const loading = ref<boolean>(false);
|
||||||
|
|
||||||
function clickGrid(item: LayoutConfig, event: Event) {
|
function clickGrid(item: LayoutConfig, event: Event) {
|
||||||
dashboardStore.activeGridItem(item.i);
|
dashboardStore.activeGridItem(item.i);
|
||||||
dashboardStore.selectWidget(item);
|
dashboardStore.selectWidget(item);
|
||||||
if (item.type === "Tab" && (event.target as HTMLDivElement)?.className !== "tab-layout") {
|
if (
|
||||||
|
item.type === WidgetType.Tab &&
|
||||||
|
!["operations", "tab-layout"].includes((event.target as HTMLDivElement)?.className) &&
|
||||||
|
(event.target as HTMLDivElement)?.classList[2] !== "icon-tool" &&
|
||||||
|
(event.target as HTMLDivElement)?.nodeName !== "use"
|
||||||
|
) {
|
||||||
dashboardStore.setActiveTabIndex(0);
|
dashboardStore.setActiveTabIndex(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
async function queryMetrics() {
|
||||||
|
const widgets = [];
|
||||||
|
|
||||||
|
for (const item of dashboardStore.layout) {
|
||||||
|
const isList = ListChartTypes.includes(item.type || "");
|
||||||
|
if (item.type === WidgetType.Widget && !isList) {
|
||||||
|
widgets.push(item);
|
||||||
|
}
|
||||||
|
if (item.type === WidgetType.Tab) {
|
||||||
|
const index = isNaN(item.activedTabIndex) ? 0 : item.activedTabIndex;
|
||||||
|
widgets.push(...item.children[index].children);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const configList = widgets.map((d: LayoutConfig) => ({
|
||||||
|
metrics: d.expressions || [],
|
||||||
|
metricConfig: d.metricConfig || [],
|
||||||
|
id: d.i,
|
||||||
|
}));
|
||||||
|
if (!widgets.length) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
loading.value = true;
|
||||||
|
metricsValues.value = (await useDashboardQueryProcessor(configList)) || {};
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
|
async function queryTabsMetrics() {
|
||||||
|
const configList = dashboardStore.currentTabItems
|
||||||
|
.filter((item: LayoutConfig) => item.type === WidgetType.Widget && !ListChartTypes.includes(item.type || ""))
|
||||||
|
.map((d: LayoutConfig) => ({
|
||||||
|
metrics: d.expressions || [],
|
||||||
|
metricConfig: d.metricConfig || [],
|
||||||
|
id: d.i,
|
||||||
|
}));
|
||||||
|
if (!configList.length) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
loading.value = true;
|
||||||
|
metricsValues.value = (await useDashboardQueryProcessor(configList)) || {};
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
|
|
||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
dashboardStore.setLayout([]);
|
dashboardStore.setLayout([]);
|
||||||
selectorStore.setCurrentService(null);
|
selectorStore.setCurrentService(null);
|
||||||
@@ -69,11 +124,53 @@ limitations under the License. -->
|
|||||||
dashboardStore.setEntity("");
|
dashboardStore.setEntity("");
|
||||||
dashboardStore.setConfigPanel(false);
|
dashboardStore.setConfigPanel(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => [selectorStore.currentService, selectorStore.currentDestService],
|
||||||
|
() => {
|
||||||
|
if ([EntityType[0].value, EntityType[4].value].includes(dashboardStore.entity)) {
|
||||||
|
queryMetrics();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
watch(
|
||||||
|
() => [selectorStore.currentPod, selectorStore.currentDestPod],
|
||||||
|
() => {
|
||||||
|
if ([EntityType[0].value, EntityType[7].value, EntityType[8].value].includes(dashboardStore.entity)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
queryMetrics();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
watch(
|
||||||
|
() => [selectorStore.currentProcess, selectorStore.currentDestProcess],
|
||||||
|
() => {
|
||||||
|
if ([EntityType[7].value, EntityType[8].value].includes(dashboardStore.entity)) {
|
||||||
|
queryMetrics();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
watch(
|
||||||
|
() => appStore.durationTime,
|
||||||
|
() => {
|
||||||
|
if (dashboardStore.entity === EntityType[1].value) {
|
||||||
|
queryMetrics();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
watch(
|
||||||
|
() => dashboardStore.currentTabItems,
|
||||||
|
() => {
|
||||||
|
queryTabsMetrics();
|
||||||
|
},
|
||||||
|
);
|
||||||
return {
|
return {
|
||||||
dashboardStore,
|
dashboardStore,
|
||||||
clickGrid,
|
clickGrid,
|
||||||
t,
|
t,
|
||||||
dragIgnoreFrom,
|
dragIgnoreFrom,
|
||||||
|
metricsValues,
|
||||||
|
loading,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@@ -26,6 +26,9 @@ limitations under the License. -->
|
|||||||
@change="changeService"
|
@change="changeService"
|
||||||
class="selectors"
|
class="selectors"
|
||||||
/>
|
/>
|
||||||
|
<span class="ml-5 cp hierarchy-btn" v-if="dashboardStore.entity === 'Service'" @click="viewTopology">
|
||||||
|
<Icon size="small" iconName="hierarchy_topology" />
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="selectors-item" v-if="key === 3 || key === 4 || key === 5 || key === 6">
|
<div class="selectors-item" v-if="key === 3 || key === 4 || key === 5 || key === 6">
|
||||||
<span class="label">
|
<span class="label">
|
||||||
@@ -41,6 +44,13 @@ limitations under the License. -->
|
|||||||
class="selectorPod"
|
class="selectorPod"
|
||||||
:isRemote="['EndpointRelation', 'Endpoint'].includes(dashboardStore.entity)"
|
:isRemote="['EndpointRelation', 'Endpoint'].includes(dashboardStore.entity)"
|
||||||
/>
|
/>
|
||||||
|
<span
|
||||||
|
class="ml-5 cp hierarchy-btn"
|
||||||
|
v-if="dashboardStore.entity === 'ServiceInstance'"
|
||||||
|
@click="showHierarchy = true"
|
||||||
|
>
|
||||||
|
<Icon size="small" iconName="hierarchy_topology" />
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="selectors-item" v-if="key === 5 || key === 6">
|
<div class="selectors-item" v-if="key === 5 || key === 6">
|
||||||
<span class="label"> $Process </span>
|
<span class="label"> $Process </span>
|
||||||
@@ -126,10 +136,17 @@ limitations under the License. -->
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<el-dialog v-model="showHierarchy" :destroy-on-close="true" @closed="showHierarchy = false" width="640px">
|
||||||
|
<div class="hierarchy-related">
|
||||||
|
<instance-map v-if="dashboardStore.entity === 'ServiceInstance'" />
|
||||||
|
<hierarchy-map v-else />
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { reactive, ref, computed, watch } from "vue";
|
import { reactive, ref, computed, watch } from "vue";
|
||||||
import { useRoute } from "vue-router";
|
import { useRoute } from "vue-router";
|
||||||
|
import { useI18n } from "vue-i18n";
|
||||||
import { useDashboardStore } from "@/store/modules/dashboard";
|
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||||
import { useAppStoreWithOut } from "@/store/modules/app";
|
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||||
import {
|
import {
|
||||||
@@ -143,19 +160,24 @@ limitations under the License. -->
|
|||||||
ServiceRelationTools,
|
ServiceRelationTools,
|
||||||
ProcessTools,
|
ProcessTools,
|
||||||
ProcessRelationTools,
|
ProcessRelationTools,
|
||||||
} from "../data";
|
WidgetType,
|
||||||
|
} from "@/views/dashboard/data";
|
||||||
import { useSelectorStore } from "@/store/modules/selectors";
|
import { useSelectorStore } from "@/store/modules/selectors";
|
||||||
|
import { useTopologyStore } from "@/store/modules/topology";
|
||||||
import { ElMessage } from "element-plus";
|
import { ElMessage } from "element-plus";
|
||||||
import type { Option } from "@/types/app";
|
import type { Option } from "@/types/app";
|
||||||
import { useI18n } from "vue-i18n";
|
import InstanceMap from "@/views/dashboard/related/topology/pod/InstanceMap.vue";
|
||||||
|
import HierarchyMap from "@/views/dashboard/related/topology/service/HierarchyMap.vue";
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const dashboardStore = useDashboardStore();
|
const dashboardStore = useDashboardStore();
|
||||||
const selectorStore = useSelectorStore();
|
const selectorStore = useSelectorStore();
|
||||||
|
const topologyStore = useTopologyStore();
|
||||||
const appStore = useAppStoreWithOut();
|
const appStore = useAppStoreWithOut();
|
||||||
const params = useRoute().params;
|
const params = useRoute().params;
|
||||||
const toolIcons = ref<{ name: string; content: string; id: string }[]>(AllTools);
|
const toolIcons = ref<{ name: string; content: string; id: WidgetType }[]>(AllTools);
|
||||||
const loading = ref<boolean>(false);
|
const loading = ref<boolean>(false);
|
||||||
|
const showHierarchy = ref<boolean>(false);
|
||||||
const states = reactive<{
|
const states = reactive<{
|
||||||
destService: string;
|
destService: string;
|
||||||
destPod: string;
|
destPod: string;
|
||||||
@@ -397,7 +419,7 @@ limitations under the License. -->
|
|||||||
loading.value = false;
|
loading.value = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function clickIcons(t: { id: string; content: string; name: string }) {
|
async function clickIcons(t: { id: WidgetType; content: string; name: string }) {
|
||||||
if (dashboardStore.selectedGrid && dashboardStore.selectedGrid.type === "Tab") {
|
if (dashboardStore.selectedGrid && dashboardStore.selectedGrid.type === "Tab") {
|
||||||
setTabControls(t.id);
|
setTabControls(t.id);
|
||||||
return;
|
return;
|
||||||
@@ -409,106 +431,20 @@ limitations under the License. -->
|
|||||||
setControls(t.id);
|
setControls(t.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
function setTabControls(id: string) {
|
function setTabControls(id: WidgetType) {
|
||||||
switch (id) {
|
if (!WidgetType[id]) {
|
||||||
case "addWidget":
|
|
||||||
dashboardStore.addTabControls("Widget");
|
|
||||||
break;
|
|
||||||
case "addTrace":
|
|
||||||
dashboardStore.addTabControls("Trace");
|
|
||||||
break;
|
|
||||||
case "addLog":
|
|
||||||
dashboardStore.addTabControls("Log");
|
|
||||||
break;
|
|
||||||
case "addProfile":
|
|
||||||
dashboardStore.addTabControls("Profile");
|
|
||||||
break;
|
|
||||||
case "addEbpf":
|
|
||||||
dashboardStore.addTabControls("Ebpf");
|
|
||||||
break;
|
|
||||||
case "addTopology":
|
|
||||||
dashboardStore.addTabControls("Topology");
|
|
||||||
break;
|
|
||||||
case "addText":
|
|
||||||
dashboardStore.addTabControls("Text");
|
|
||||||
break;
|
|
||||||
case "addDemandLog":
|
|
||||||
dashboardStore.addTabControls("DemandLog");
|
|
||||||
break;
|
|
||||||
case "addEvent":
|
|
||||||
dashboardStore.addTabControls("Event");
|
|
||||||
break;
|
|
||||||
case "addNetworkProfiling":
|
|
||||||
dashboardStore.addTabControls("NetworkProfiling");
|
|
||||||
break;
|
|
||||||
case "addContinuousProfiling":
|
|
||||||
dashboardStore.addTabControls("ContinuousProfiling");
|
|
||||||
break;
|
|
||||||
case "addTimeRange":
|
|
||||||
dashboardStore.addTabControls("TimeRange");
|
|
||||||
break;
|
|
||||||
case "addIframe":
|
|
||||||
dashboardStore.addTabControls("ThirdPartyApp");
|
|
||||||
break;
|
|
||||||
case "addTaskTimeline":
|
|
||||||
dashboardStore.addTabControls("TaskTimeline");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
ElMessage.info("Don't support this control");
|
ElMessage.info("Don't support this control");
|
||||||
break;
|
return;
|
||||||
}
|
}
|
||||||
|
dashboardStore.addTabControls(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
function setControls(id: string) {
|
function setControls(id: WidgetType) {
|
||||||
switch (id) {
|
if (!WidgetType[id]) {
|
||||||
case "addWidget":
|
ElMessage.info("Don't support this control");
|
||||||
dashboardStore.addControl("Widget");
|
return;
|
||||||
break;
|
|
||||||
case "addTab":
|
|
||||||
dashboardStore.addControl("Tab");
|
|
||||||
break;
|
|
||||||
case "addTrace":
|
|
||||||
dashboardStore.addControl("Trace");
|
|
||||||
break;
|
|
||||||
case "addProfile":
|
|
||||||
dashboardStore.addControl("Profile");
|
|
||||||
break;
|
|
||||||
case "addEbpf":
|
|
||||||
dashboardStore.addControl("Ebpf");
|
|
||||||
break;
|
|
||||||
case "addLog":
|
|
||||||
dashboardStore.addControl("Log");
|
|
||||||
break;
|
|
||||||
case "addTopology":
|
|
||||||
dashboardStore.addControl("Topology");
|
|
||||||
break;
|
|
||||||
case "addText":
|
|
||||||
dashboardStore.addControl("Text");
|
|
||||||
break;
|
|
||||||
case "addDemandLog":
|
|
||||||
dashboardStore.addControl("DemandLog");
|
|
||||||
break;
|
|
||||||
case "addEvent":
|
|
||||||
dashboardStore.addControl("Event");
|
|
||||||
break;
|
|
||||||
case "addNetworkProfiling":
|
|
||||||
dashboardStore.addControl("NetworkProfiling");
|
|
||||||
break;
|
|
||||||
case "addContinuousProfiling":
|
|
||||||
dashboardStore.addControl("ContinuousProfiling");
|
|
||||||
break;
|
|
||||||
case "addTimeRange":
|
|
||||||
dashboardStore.addControl("TimeRange");
|
|
||||||
break;
|
|
||||||
case "addIframe":
|
|
||||||
dashboardStore.addControl("ThirdPartyApp");
|
|
||||||
break;
|
|
||||||
case "addTaskTimeline":
|
|
||||||
dashboardStore.addControl("TaskTimeline");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
dashboardStore.addControl("Widget");
|
|
||||||
}
|
}
|
||||||
|
dashboardStore.addControl(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function fetchPods(type: string, serviceId: string, setPod: boolean, param?: { keyword?: string }) {
|
async function fetchPods(type: string, serviceId: string, setPod: boolean, param?: { keyword?: string }) {
|
||||||
@@ -584,7 +520,7 @@ limitations under the License. -->
|
|||||||
instanceId: selectorStore.currentPod.id,
|
instanceId: selectorStore.currentPod.id,
|
||||||
});
|
});
|
||||||
if (setPod) {
|
if (setPod) {
|
||||||
const process = params.processId || selectorStore.processes[0].id;
|
const process = selectorStore.currentProcess?.id || params.processId || selectorStore.processes[0].id;
|
||||||
const currentProcess = selectorStore.processes.find((d: { id: string }) => d.id === process);
|
const currentProcess = selectorStore.processes.find((d: { id: string }) => d.id === process);
|
||||||
if (currentProcess) {
|
if (currentProcess) {
|
||||||
selectorStore.setCurrentProcess(currentProcess);
|
selectorStore.setCurrentProcess(currentProcess);
|
||||||
@@ -602,7 +538,8 @@ limitations under the License. -->
|
|||||||
isRelation: true,
|
isRelation: true,
|
||||||
});
|
});
|
||||||
if (setPod) {
|
if (setPod) {
|
||||||
const destProcess = params.destProcessId || selectorStore.destProcesses[0].id;
|
const destProcess =
|
||||||
|
selectorStore.currentDestProcess?.id || params.destProcessId || selectorStore.destProcesses[0].id;
|
||||||
const currentDestProcess = selectorStore.destProcesses.find((d: { id: string }) => d.id === destProcess);
|
const currentDestProcess = selectorStore.destProcesses.find((d: { id: string }) => d.id === destProcess);
|
||||||
if (!currentDestProcess) {
|
if (!currentDestProcess) {
|
||||||
states.currentDestProcess = "";
|
states.currentDestProcess = "";
|
||||||
@@ -634,7 +571,7 @@ limitations under the License. -->
|
|||||||
states.currentDestPod = "";
|
states.currentDestPod = "";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const destPod = params.destPodId || selectorStore.destPods[0].id;
|
const destPod = selectorStore.currentDestPod?.id || params.destPodId || selectorStore.destPods[0].id;
|
||||||
const currentDestPod = selectorStore.destPods.find((d: { id: string }) => d.id === destPod);
|
const currentDestPod = selectorStore.destPods.find((d: { id: string }) => d.id === destPod);
|
||||||
if (!currentDestPod) {
|
if (!currentDestPod) {
|
||||||
states.currentDestPod = "";
|
states.currentDestPod = "";
|
||||||
@@ -666,7 +603,7 @@ limitations under the License. -->
|
|||||||
states.currentPod = "";
|
states.currentPod = "";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const pod = params.podId || selectorStore.pods[0].id;
|
const pod = selectorStore.currentPod?.id || params.podId || selectorStore.pods[0].id;
|
||||||
const currentPod = selectorStore.pods.find((d: { id: string }) => d.id === pod);
|
const currentPod = selectorStore.pods.find((d: { id: string }) => d.id === pod);
|
||||||
if (!currentPod) {
|
if (!currentPod) {
|
||||||
selectorStore.setCurrentPod(null);
|
selectorStore.setCurrentPod(null);
|
||||||
@@ -722,6 +659,10 @@ limitations under the License. -->
|
|||||||
};
|
};
|
||||||
fetchPods(EntityType[6].value, selectorStore.currentDestService.id, false, param);
|
fetchPods(EntityType[6].value, selectorStore.currentDestService.id, false, param);
|
||||||
}
|
}
|
||||||
|
function viewTopology() {
|
||||||
|
showHierarchy.value = true;
|
||||||
|
topologyStore.setNode(null);
|
||||||
|
}
|
||||||
watch(
|
watch(
|
||||||
() => dashboardStore.entity,
|
() => dashboardStore.entity,
|
||||||
(newVal, oldVal) => {
|
(newVal, oldVal) => {
|
||||||
@@ -790,4 +731,19 @@ limitations under the License. -->
|
|||||||
.relation {
|
.relation {
|
||||||
margin-top: 5px;
|
margin-top: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.hierarchy-btn {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 0 2px 2px;
|
||||||
|
border: 1px solid #666;
|
||||||
|
border-radius: 4px;
|
||||||
|
text-align: center;
|
||||||
|
color: #aaa;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hierarchy-related {
|
||||||
|
height: 600px;
|
||||||
|
width: 600px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@@ -25,11 +25,14 @@ limitations under the License. -->
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onMounted, ref, onUnmounted, watch, toRaw } from "vue";
|
import { onMounted, ref, onUnmounted, watch, toRaw } from "vue";
|
||||||
import { useDemandLogStore } from "@/store/modules/demand-log";
|
import { useDemandLogStore } from "@/store/modules/demand-log";
|
||||||
|
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||||
|
import { Themes } from "@/constants/data";
|
||||||
|
|
||||||
/*global Nullable */
|
/*global Nullable */
|
||||||
const demandLogStore = useDemandLogStore();
|
const demandLogStore = useDemandLogStore();
|
||||||
const monacoInstance = ref();
|
const monacoInstance = ref();
|
||||||
const logContent = ref<Nullable<HTMLDivElement>>(null);
|
const logContent = ref<Nullable<HTMLDivElement>>(null);
|
||||||
|
const appStore = useAppStoreWithOut();
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
init();
|
init();
|
||||||
@@ -50,6 +53,7 @@ limitations under the License. -->
|
|||||||
wordWrap: true,
|
wordWrap: true,
|
||||||
minimap: { enabled: false },
|
minimap: { enabled: false },
|
||||||
readonly: true,
|
readonly: true,
|
||||||
|
theme: getTheme(),
|
||||||
});
|
});
|
||||||
toRaw(monacoInstance.value).updateOptions({ readOnly: true });
|
toRaw(monacoInstance.value).updateOptions({ readOnly: true });
|
||||||
editorLayout();
|
editorLayout();
|
||||||
@@ -64,6 +68,9 @@ limitations under the License. -->
|
|||||||
width: width,
|
width: width,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
function getTheme() {
|
||||||
|
return appStore.theme === Themes.Dark ? "vs-dark" : "vs";
|
||||||
|
}
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
if (!toRaw(monacoInstance.value)) {
|
if (!toRaw(monacoInstance.value)) {
|
||||||
return;
|
return;
|
||||||
@@ -72,6 +79,12 @@ limitations under the License. -->
|
|||||||
monacoInstance.value = null;
|
monacoInstance.value = null;
|
||||||
demandLogStore.setLogs("");
|
demandLogStore.setLogs("");
|
||||||
});
|
});
|
||||||
|
watch(
|
||||||
|
() => appStore.theme,
|
||||||
|
() => {
|
||||||
|
toRaw(monacoInstance.value).updateOptions({ theme: getTheme() });
|
||||||
|
},
|
||||||
|
);
|
||||||
watch(
|
watch(
|
||||||
() => demandLogStore.logs,
|
() => demandLogStore.logs,
|
||||||
() => {
|
() => {
|
||||||
|
@@ -28,6 +28,7 @@ limitations under the License. -->
|
|||||||
import type { StackElement } from "@/types/ebpf";
|
import type { StackElement } from "@/types/ebpf";
|
||||||
import { AggregateTypes } from "./data";
|
import { AggregateTypes } from "./data";
|
||||||
import "d3-flame-graph/dist/d3-flamegraph.css";
|
import "d3-flame-graph/dist/d3-flamegraph.css";
|
||||||
|
import { treeForeach } from "@/utils/flameGraph";
|
||||||
|
|
||||||
/*global Nullable, defineProps*/
|
/*global Nullable, defineProps*/
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
@@ -180,14 +181,6 @@ limitations under the License. -->
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
function treeForeach(tree: StackElement[], func: (node: StackElement) => void) {
|
|
||||||
for (const data of tree) {
|
|
||||||
data.children && treeForeach(data.children, func);
|
|
||||||
func(data);
|
|
||||||
}
|
|
||||||
return tree;
|
|
||||||
}
|
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => ebpfStore.analyzeTrees,
|
() => ebpfStore.analyzeTrees,
|
||||||
() => {
|
() => {
|
||||||
|