Compare commits
41 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
6c4991bc56 | ||
![]() |
77c1694383 | ||
![]() |
7fe3257c32 | ||
![]() |
8c9c339417 | ||
![]() |
62a82590c9 | ||
![]() |
22db68646c | ||
![]() |
7738695601 | ||
![]() |
9b1a5f7a74 | ||
![]() |
54997794b4 | ||
![]() |
372aee2eb6 | ||
![]() |
d662a0fb54 | ||
![]() |
b293f4ddb5 | ||
![]() |
279ec60915 | ||
![]() |
05688f0888 | ||
![]() |
15cd839480 | ||
![]() |
dc22f8da6e | ||
![]() |
ec67b4148c | ||
![]() |
986fe8b90e | ||
![]() |
fe28fae27d | ||
![]() |
359197a1c5 | ||
![]() |
903cf8e9bd | ||
![]() |
921c961dc1 | ||
![]() |
d129c75c8c | ||
![]() |
a4a2c4fefc | ||
![]() |
7dde4820de | ||
![]() |
7257858921 | ||
![]() |
ce585d6e08 | ||
![]() |
3f178f89f8 | ||
![]() |
ceae10cbfa | ||
![]() |
49a5481fb0 | ||
![]() |
8bb45bb453 | ||
![]() |
8077043c7e | ||
![]() |
0e15c023cc | ||
![]() |
55e4828adc | ||
![]() |
68eea52e88 | ||
![]() |
5973632f0f | ||
![]() |
1d189e82a7 | ||
![]() |
2491ab7176 | ||
![]() |
449dccdf36 | ||
![]() |
8031c1b463 | ||
![]() |
1c905aeb06 |
1
.github/workflows/nodejs.yml
vendored
@@ -49,6 +49,7 @@ jobs:
|
|||||||
npm ci
|
npm ci
|
||||||
npm run lint
|
npm run lint
|
||||||
npm run build --if-present
|
npm run build --if-present
|
||||||
|
npm run check-components-types
|
||||||
npm run test:unit
|
npm run test:unit
|
||||||
env:
|
env:
|
||||||
CI: true
|
CI: true
|
||||||
|
963
package-lock.json
generated
16
package.json
@@ -14,7 +14,8 @@
|
|||||||
"lint:prettier": "prettier --write \"src/**/*.{js,json,tsx,css,less,scss,vue,html,md}\"",
|
"lint:prettier": "prettier --write \"src/**/*.{js,json,tsx,css,less,scss,vue,html,md}\"",
|
||||||
"lint:stylelint": "stylelint --cache --fix \"**/*.{vue,less,postcss,css,scss}\" --cache --cache-location node_modules/.cache/stylelint/",
|
"lint:stylelint": "stylelint --cache --fix \"**/*.{vue,less,postcss,css,scss}\" --cache --cache-location node_modules/.cache/stylelint/",
|
||||||
"lint:lint-staged": "lint-staged",
|
"lint:lint-staged": "lint-staged",
|
||||||
"prepare": "husky install"
|
"prepare": "husky install",
|
||||||
|
"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": "^0.24.0",
|
"axios": "^0.24.0",
|
||||||
@@ -22,7 +23,7 @@
|
|||||||
"d3-flame-graph": "^4.1.3",
|
"d3-flame-graph": "^4.1.3",
|
||||||
"d3-tip": "^0.9.1",
|
"d3-tip": "^0.9.1",
|
||||||
"echarts": "^5.2.2",
|
"echarts": "^5.2.2",
|
||||||
"element-plus": "^2.0.2",
|
"element-plus": "^2.1.0",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"monaco-editor": "^0.34.1",
|
"monaco-editor": "^0.34.1",
|
||||||
"pinia": "^2.0.28",
|
"pinia": "^2.0.28",
|
||||||
@@ -57,7 +58,8 @@
|
|||||||
"eslint-plugin-vue": "^9.3.0",
|
"eslint-plugin-vue": "^9.3.0",
|
||||||
"husky": "^8.0.2",
|
"husky": "^8.0.2",
|
||||||
"jsdom": "^20.0.3",
|
"jsdom": "^20.0.3",
|
||||||
"lint-staged": "^12.1.3",
|
"lint-staged": "^13.2.1",
|
||||||
|
"mockjs": "^1.1.0",
|
||||||
"node-sass": "^8.0.0",
|
"node-sass": "^8.0.0",
|
||||||
"npm-run-all": "^4.1.5",
|
"npm-run-all": "^4.1.5",
|
||||||
"postcss-html": "^1.3.0",
|
"postcss-html": "^1.3.0",
|
||||||
@@ -65,15 +67,15 @@
|
|||||||
"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": "^1.15.2",
|
||||||
"stylelint": "^14.1.0",
|
"stylelint": "^15.6.0",
|
||||||
"stylelint-config-html": "^1.0.0",
|
"stylelint-config-html": "^1.0.0",
|
||||||
"stylelint-config-prettier": "^9.0.3",
|
"stylelint-config-prettier": "^9.0.3",
|
||||||
"stylelint-config-standard": "^24.0.0",
|
"stylelint-config-standard": "^33.0.0",
|
||||||
"stylelint-order": "^5.0.0",
|
"stylelint-order": "^6.0.3",
|
||||||
"typescript": "~4.7.4",
|
"typescript": "~4.7.4",
|
||||||
"unplugin-auto-import": "^0.7.0",
|
"unplugin-auto-import": "^0.7.0",
|
||||||
"unplugin-vue-components": "^0.19.2",
|
"unplugin-vue-components": "^0.19.2",
|
||||||
"vite": "^4.0.0",
|
"vite": "^4.0.5",
|
||||||
"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",
|
||||||
|
@@ -12,6 +12,6 @@ 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 version="1.1" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
|
<svg t="1684376918107" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7954">
|
||||||
<path d="M15 15.984h6v3q0 0.797-0.609 1.406t-1.406 0.609h-13.969q-0.797 0-1.406-0.609t-0.609-1.406v-3h6q0 1.219 0.891 2.109t2.109 0.891 2.109-0.891 0.891-2.109zM18.984 9v-3.984h-13.969v3.984h3.984q0 1.219 0.891 2.109t2.109 0.891 2.109-0.891 0.891-2.109h3.984zM18.984 3q0.797 0 1.406 0.609t0.609 1.406v6.984q0 0.797-0.609 1.406t-1.406 0.609h-13.969q-0.797 0-1.406-0.609t-0.609-1.406v-6.984q0-0.797 0.609-1.406t1.406-0.609h13.969z"></path>
|
<path d="M243.921917 780.038686l357.445972 0L601.367889 422.592714 243.921917 422.592714 243.921917 780.038686zM288.679283 467.350081l268.036639 0 0 268.035616L288.679283 735.385696 288.679283 467.350081zM779.993149 65.25112 243.921917 65.25112c-98.640578 0-178.6314 79.990822-178.6314 178.716334L65.290517 780.038686c0 98.640578 79.990822 178.710194 178.6314 178.710194l536.071232 0c98.725512 0 178.716334-80.069617 178.716334-178.710194L958.709483 243.967454C958.709483 145.242965 878.717637 65.25112 779.993149 65.25112zM869.404528 735.385696c0 73.992201-60.07319 133.972271-134.084834 133.972271L288.679283 869.357967c-74.096579 0-134.063345-59.98007-134.063345-133.972271L154.615938 288.61328c0-73.984015 59.966767-134.057205 134.063345-134.057205l446.639386 0c74.011644 0 134.084834 60.07319 134.084834 134.057205L869.403504 735.385696zM511.957533 243.967454l268.035616 0 0 89.319282 0 268.035616-89.326445 0-44.645826 0 0-44.673455 89.298815 0L735.319693 288.61328l-268.014126 0 0 89.326445-44.652989 0 0-133.971247L511.957533 243.968477z" p-id="7955"></path>
|
||||||
</svg>
|
</svg>
|
||||||
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.9 KiB |
17
src/assets/icons/continuous_profiling.svg
Normal 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="1684390612367" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="12207">
|
||||||
|
<path d="M202.66008 885.33784A10.66632 10.66632 0 0 0 213.3264 874.67152v-85.33056a42.66528 42.66528 0 0 0-42.66528-42.66528H85.33056a42.66528 42.66528 0 0 0-42.66528 42.66528v85.33056a10.66632 10.66632 0 0 0 10.66632 10.66632zM458.65176 885.33784a10.66632 10.66632 0 0 0 10.66632-10.66632v-298.65696a42.66528 42.66528 0 0 0-42.66528-42.665281H341.32224a42.66528 42.66528 0 0 0-42.66528 42.665281v298.65696a10.66632 10.66632 0 0 0 10.66632 10.66632zM714.643441 885.33784a10.66632 10.66632 0 0 0 10.66632-10.66632v-213.3264a42.66528 42.66528 0 0 0-42.66528-42.66528h-85.33056a42.66528 42.66528 0 0 0-42.66528 42.66528v213.3264a10.66632 10.66632 0 0 0 10.66632 10.66632zM970.635121 885.33784a10.66632 10.66632 0 0 0 10.66632-10.66632v-511.983361a42.66528 42.66528 0 0 0-42.66528-42.66528h-85.33056a42.66528 42.66528 0 0 0-42.66528 42.66528v511.983361a10.66632 10.66632 0 0 0 10.66632 10.66632z" p-id="12208"></path><path d="M149.32848 576.01456a85.33056 85.33056 0 0 0 85.33056-85.330561 84.51992 84.51992 0 0 0-4.266528-25.599168l135.120942-112.636339a83.410622 83.410622 0 0 0 104.273945-19.626029l106.6632 35.582844A85.33056 85.33056 0 0 0 746.642401 362.688159a83.79461 83.79461 0 0 0-9.85568-38.910735l140.240776-163.621349A85.074568 85.074568 0 1 0 831.972961 85.363839a83.709279 83.709279 0 0 0 3.967871 24.361875L688.190967 282.136111a82.429321 82.429321 0 0 0-91.346364 25.300511l-106.663201-35.540179A85.117234 85.117234 0 1 0 324.256128 302.956767L189.263182 415.763768A84.263928 84.263928 0 0 0 149.32848 405.353439a85.33056 85.33056 0 0 0 0 170.661121zM981.301441 938.66944H42.66528a43.347925 43.347925 0 0 0-42.66528 42.66528 42.66528 42.66528 0 0 0 42.66528 42.66528h938.636161a42.66528 42.66528 0 0 0 42.66528-42.66528 43.305259 43.305259 0 0 0-42.66528-42.66528z" p-id="12209"></path>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 2.6 KiB |
15
src/assets/icons/cross.svg
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
<!-- 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="1680101648371" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="15649" width="48" height="48"><path d="M832 272c0-62.4-51-112.9-113.6-112-60.7 0.9-110 50.6-110.4 111.3-0.3 52.6 35.6 96.8 84.2 109.2 14 3.6 23.8 16 24.1 30.4 0.5 27.3-4.4 57.4-22.3 82.5-28.7 40.3-80.7 54.9-126.6 67.8-29 8.1-50.1 10.2-68.7 12-26.4 2.6-51.4 5.1-82.6 23-6.6 3.8-13.1 8-19.2 12.6-5.3 4-12.8 0.2-12.8-6.4V241.3c0-12.2 6.8-23.5 17.7-28.9 37.1-18.4 62.6-56.8 62.3-101.1-0.5-62.8-53.2-113.4-116-111.2C288.1 2.1 240 51.4 240 112c0 44 25.4 82.1 62.3 100.4 10.9 5.4 17.7 16.5 17.7 28.6v541.7c0 12.2-6.8 23.5-17.7 28.9-37.1 18.4-62.6 56.8-62.3 101.1 0.4 62.8 53.1 113.3 115.9 111.2C416 1021.9 464 972.5 464 912c0-44-25.4-82.1-62.3-100.4-10.9-5.4-17.7-16.5-17.7-28.6v-19.2c0-42 19.9-81.8 54.3-105.9 3.1-2.2 6.4-4.3 9.7-6.2 19.3-11.1 33.5-12.5 57-14.8 20.2-2 45.3-4.5 79.7-14.1 50.5-14.2 119.6-33.5 161.4-92.3 24-33.7 35.4-75 34.1-123-0.2-6.9-0.7-13.8-1.4-20.9-1.1-10.7 3.5-21 11.8-27.8 25.3-20.4 41.4-51.7 41.4-86.8zM304 112c0-26.5 21.5-48 48-48s48 21.5 48 48-21.5 48-48 48-48-21.5-48-48z m96 800c0 26.5-21.5 48-48 48s-48-21.5-48-48 21.5-48 48-48 48 21.5 48 48z m320-592c-26.5 0-48-21.5-48-48s21.5-48 48-48 48 21.5 48 48-21.5 48-48 48z" p-id="15650"></path></svg>
|
After Width: | Height: | Size: 2.0 KiB |
17
src/assets/icons/edit.svg
Normal 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="1684722897341" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2408">
|
||||||
|
<path d="M853.333333 501.333333c-17.066667 0-32 14.933333-32 32v320c0 6.4-4.266667 10.666667-10.666666 10.666667H170.666667c-6.4 0-10.666667-4.266667-10.666667-10.666667V213.333333c0-6.4 4.266667-10.666667 10.666667-10.666666h320c17.066667 0 32-14.933333 32-32s-14.933333-32-32-32H170.666667c-40.533333 0-74.666667 34.133333-74.666667 74.666666v640c0 40.533333 34.133333 74.666667 74.666667 74.666667h640c40.533333 0 74.666667-34.133333 74.666666-74.666667V533.333333c0-17.066667-14.933333-32-32-32z" fill="#666666" p-id="2409"></path><path d="M405.333333 484.266667l-32 125.866666c-2.133333 10.666667 0 23.466667 8.533334 29.866667 6.4 6.4 14.933333 8.533333 23.466666 8.533333h8.533334l125.866666-32c6.4-2.133333 10.666667-4.266667 14.933334-8.533333l300.8-300.8c38.4-38.4 38.4-102.4 0-140.8-38.4-38.4-102.4-38.4-140.8 0L413.866667 469.333333c-4.266667 4.266667-6.4 8.533333-8.533334 14.933334z m59.733334 23.466666L761.6 213.333333c12.8-12.8 36.266667-12.8 49.066667 0 12.8 12.8 12.8 36.266667 0 49.066667L516.266667 558.933333l-66.133334 17.066667 14.933334-68.266667z" p-id="2410"></path>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.9 KiB |
15
src/assets/icons/entry.svg
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
<!-- 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="1680083488716" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1096" width="48" height="48"><path d="M853.333333 512a42.666667 42.666667 0 0 0-42.666666-42.666667h-323.84l98.133333-97.706666a42.666667 42.666667 0 1 0-60.586667-60.586667l-170.666666 170.666667a42.666667 42.666667 0 0 0-8.96 14.08 42.666667 42.666667 0 0 0 0 32.426666 42.666667 42.666667 0 0 0 8.96 14.08l170.666666 170.666667a42.666667 42.666667 0 0 0 60.586667 0 42.666667 42.666667 0 0 0 0-60.586667L486.826667 554.666667H810.666667a42.666667 42.666667 0 0 0 42.666666-42.666667zM725.333333 85.333333H298.666667a128 128 0 0 0-128 128v597.333334a128 128 0 0 0 128 128h426.666666a128 128 0 0 0 128-128v-128a42.666667 42.666667 0 0 0-85.333333 0v128a42.666667 42.666667 0 0 1-42.666667 42.666666H298.666667a42.666667 42.666667 0 0 1-42.666667-42.666666V213.333333a42.666667 42.666667 0 0 1 42.666667-42.666666h426.666666a42.666667 42.666667 0 0 1 42.666667 42.666666v128a42.666667 42.666667 0 0 0 85.333333 0V213.333333a128 128 0 0 0-128-128z" p-id="1097"></path></svg>
|
After Width: | Height: | Size: 1.8 KiB |
15
src/assets/icons/exit.svg
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
<!-- 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="1680104481890" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7991" width="16" height="16"><path d="M918.4 489.6l-160-160c-12.8-12.8-32-12.8-44.8 0-12.8 12.8-12.8 32 0 44.8l105.6 105.6L512 480c-19.2 0-32 12.8-32 32s12.8 32 32 32l307.2 0-105.6 105.6c-12.8 12.8-12.8 32 0 44.8 6.4 6.4 12.8 9.6 22.4 9.6 9.6 0 16-3.2 22.4-9.6l160-163.2c0 0 0-3.2 3.2-3.2C931.2 518.4 931.2 499.2 918.4 489.6zM832 736c-19.2 0-32 12.8-32 32l0 64c0 19.2-12.8 32-32 32L224 864c-19.2 0-32-12.8-32-32L192 192c0-19.2 12.8-32 32-32l544 0c19.2 0 32 12.8 32 32l0 64c0 19.2 12.8 32 32 32s32-12.8 32-32L864 192c0-54.4-41.6-96-96-96L224 96C169.6 96 128 137.6 128 192l0 640c0 54.4 41.6 96 96 96l544 0c54.4 0 96-41.6 96-96l0-64C864 748.8 851.2 736 832 736z" p-id="7992"></path></svg>
|
After Width: | Height: | Size: 1.5 KiB |
16
src/assets/icons/mq.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 class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M750.08 657.92c-16.384 0-30.208 2.56-44.032 8.192l-44.032-52.224c33.28-38.4 55.296-90.624 55.296-145.92s-19.456-101.888-52.224-140.288l27.648-24.576c16.384 8.192 33.28 13.824 52.224 13.824 63.488 0 115.712-52.224 115.712-115.712s-52.224-115.712-115.712-115.712c-63.488 0-115.712 52.224-115.712 115.712 0 13.824 2.56 30.208 8.192 41.472l-35.84 30.208c-34.304-19.968-73.216-30.208-112.64-30.208-44.032 0-85.504 13.824-121.344 32.768l-41.472-52.224c0-5.632 2.56-13.824 2.56-19.456 0-40.96-32.768-74.24-73.728-74.24h-0.512c-40.96 0-74.24 32.768-74.24 73.728v0.512c0 40.96 32.768 74.24 73.728 74.24H262.656L306.688 332.8c-27.648 38.4-46.592 85.504-46.592 134.656 0 35.84 8.192 71.68 24.576 101.888l-35.84 30.208c-8.192-5.632-19.456-5.632-30.208-5.632-49.664 0-90.624 41.472-90.624 90.624 0 49.664 41.472 90.624 90.624 90.624s90.624-41.472 90.624-90.624c0-8.192 0-16.384-2.56-24.576l30.208-27.648c41.472 35.84 93.696 57.856 154.112 57.856 33.28 0 63.488-5.632 90.624-19.456l46.592 57.856c-11.264 19.456-19.456 44.032-19.456 68.608 0 77.312 63.488 140.288 143.36 140.288s143.36-63.488 143.36-140.288c0.512-75.776-65.536-139.264-145.408-139.264z m-261.632-11.264c-99.328 0-181.76-79.872-181.76-178.688C306.688 368.64 389.12 289.28 488.448 289.28s181.76 79.872 181.76 178.688c0 99.328-82.432 178.688-181.76 178.688zM430.592 465.408c0.512 18.432-13.824 33.28-32.256 33.792-18.432 0.512-33.28-13.824-33.792-32.256v-1.536c0-18.432 14.848-32.768 33.28-32.768 18.432-0.512 32.768 14.336 32.768 32.768z m88.064 0c0 18.432-14.848 33.28-32.768 33.28-18.432 0-33.28-14.848-33.28-32.768 0-18.432 14.848-32.768 33.28-32.768s32.768 13.824 32.768 32.256z m91.136 0c0 18.432-14.848 33.28-32.768 33.28s-33.28-14.848-33.28-32.768c0-18.432 14.848-32.768 33.28-32.768 17.92-1.024 32.768 13.824 32.768 32.256z"></path></svg>
|
After Width: | Height: | Size: 2.6 KiB |
@@ -12,6 +12,6 @@ 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 version="1.1" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
|
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||||
<path d="M12 15.516q1.453 0 2.484-1.031t1.031-2.484-1.031-2.484-2.484-1.031-2.484 1.031-1.031 2.484 1.031 2.484 2.484 1.031zM19.453 12.984l2.109 1.641q0.328 0.234 0.094 0.656l-2.016 3.469q-0.188 0.328-0.609 0.188l-2.484-0.984q-0.984 0.703-1.688 0.984l-0.375 2.625q-0.094 0.422-0.469 0.422h-4.031q-0.375 0-0.469-0.422l-0.375-2.625q-0.891-0.375-1.688-0.984l-2.484 0.984q-0.422 0.141-0.609-0.188l-2.016-3.469q-0.234-0.422 0.094-0.656l2.109-1.641q-0.047-0.328-0.047-0.984t0.047-0.984l-2.109-1.641q-0.328-0.234-0.094-0.656l2.016-3.469q0.188-0.328 0.609-0.188l2.484 0.984q0.984-0.703 1.688-0.984l0.375-2.625q0.094-0.422 0.469-0.422h4.031q0.375 0 0.469 0.422l0.375 2.625q0.891 0.375 1.688 0.984l2.484-0.984q0.422-0.141 0.609 0.188l2.016 3.469q0.234 0.422-0.094 0.656l-2.109 1.641q0.047 0.328 0.047 0.984t-0.047 0.984z"></path>
|
<path d="M12 15.516q1.453 0 2.484-1.031t1.031-2.484-1.031-2.484-2.484-1.031-2.484 1.031-1.031 2.484 1.031 2.484 2.484 1.031zM19.453 12.984l2.109 1.641q0.328 0.234 0.094 0.656l-2.016 3.469q-0.188 0.328-0.609 0.188l-2.484-0.984q-0.984 0.703-1.688 0.984l-0.375 2.625q-0.094 0.422-0.469 0.422h-4.031q-0.375 0-0.469-0.422l-0.375-2.625q-0.891-0.375-1.688-0.984l-2.484 0.984q-0.422 0.141-0.609-0.188l-2.016-3.469q-0.234-0.422 0.094-0.656l2.109-1.641q-0.047-0.328-0.047-0.984t0.047-0.984l-2.109-1.641q-0.328-0.234-0.094-0.656l2.016-3.469q0.188-0.328 0.609-0.188l2.484 0.984q0.984-0.703 1.688-0.984l0.375-2.625q0.094-0.422 0.469-0.422h4.031q0.375 0 0.469 0.422l0.375 2.625q0.891 0.375 1.688 0.984l2.484-0.984q0.422-0.141 0.609 0.188l2.016 3.469q0.234 0.422-0.094 0.656l-2.109 1.641q0.047 0.328 0.047 0.984t-0.047 0.984z"></path>
|
||||||
</svg>
|
</svg>
|
||||||
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.6 KiB |
17
src/assets/icons/task_timeline.svg
Normal 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="1685973573331" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2708">
|
||||||
|
<path d="M138 573.8V450.2c48.2-12.1 84-55.8 84-107.7 0-51.9-35.8-95.6-84-107.7V68.1c0-14.9-12.1-27-27-27s-27 12.1-27 27v166.7C35.8 246.9 0 290.6 0 342.5c0 51.9 35.8 95.6 84 107.7v123.7c-48.2 12-84 55.7-84 107.6s35.8 95.6 84 107.7v166.7c0 14.9 12.1 27 27 27s27-12.1 27-27V789.2c48.2-12.1 84-55.8 84-107.7s-35.8-95.6-84-107.7zM60 342.5c0-28.1 22.9-51 51-51s51 22.9 51 51-22.9 51-51 51-51-22.9-51-51z m51 390c-28.1 0-51-22.9-51-51s22.9-51 51-51 51 22.9 51 51-22.9 51-51 51zM942 283H352c-16.6 0-30-13.4-30-30s13.4-30 30-30h590c16.6 0 30 13.4 30 30s-13.4 30-30 30zM771.4 457H347.6c-14.2 0-25.6-11.5-25.6-25.6v-8.7c0-14.2 11.5-25.6 25.6-25.6h423.7c14.2 0 25.6 11.5 25.6 25.6v8.7c0.1 14.1-11.4 25.6-25.5 25.6z" p-id="2709"></path><path d="M942 625H352c-16.6 0-30-13.4-30-30s13.4-30 30-30h590c16.6 0 30 13.4 30 30s-13.4 30-30 30zM771.4 799H347.6c-14.2 0-25.6-11.5-25.6-25.6v-8.7c0-14.2 11.5-25.6 25.6-25.6h423.7c14.2 0 25.6 11.5 25.6 25.6v8.7c0.1 14.1-11.4 25.6-25.5 25.6z" p-id="2710"></path>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.8 KiB |
@@ -30,13 +30,13 @@ function validateFileName(str: string): string | undefined {
|
|||||||
Object.keys(requireComponent).forEach((filePath: string) => {
|
Object.keys(requireComponent).forEach((filePath: string) => {
|
||||||
const fileName = validateFileName(filePath);
|
const fileName = validateFileName(filePath);
|
||||||
if (fileName) {
|
if (fileName) {
|
||||||
result[fileName] = (requireComponent as { [key: string]: any })[filePath].default;
|
result[fileName] = (requireComponent as Indexable)[filePath].default;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
Object.keys(requireTool).forEach((filePath: string) => {
|
Object.keys(requireTool).forEach((filePath: string) => {
|
||||||
const fileName = validateFileName(filePath);
|
const fileName = validateFileName(filePath);
|
||||||
if (fileName) {
|
if (fileName) {
|
||||||
t[fileName] = (requireTool as { [key: string]: any })[filePath].default;
|
t[fileName] = (requireTool as Indexable)[filePath].default;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
BIN
src/assets/img/technologies/GRIZZLY.png
Normal file
After Width: | Height: | Size: 13 KiB |
BIN
src/assets/img/technologies/JERSEY.png
Normal file
After Width: | Height: | Size: 7.4 KiB |
BIN
src/assets/img/tools/ENTRY.png
Normal file
After Width: | Height: | Size: 262 B |
BIN
src/assets/img/tools/EXIT.png
Normal file
After Width: | Height: | Size: 269 B |
BIN
src/assets/img/tools/STREAM.png
Normal file
After Width: | Height: | Size: 373 B |
@@ -162,7 +162,7 @@ limitations under the License. -->
|
|||||||
import { computed, onMounted, watch, reactive } from "vue";
|
import { computed, onMounted, watch, reactive } from "vue";
|
||||||
import type { PropType } from "vue";
|
import type { PropType } from "vue";
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
/*global defineProps, defineEmits */
|
/*global defineProps, defineEmits, Indexable, Recordable*/
|
||||||
const emit = defineEmits(["input", "setDates", "ok"]);
|
const emit = defineEmits(["input", "setDates", "ok"]);
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
@@ -191,7 +191,7 @@ limitations under the License. -->
|
|||||||
minute: 0,
|
minute: 0,
|
||||||
second: 0,
|
second: 0,
|
||||||
});
|
});
|
||||||
const get = (time: Date): { [key: string]: any } => {
|
const get = (time: Date): Indexable => {
|
||||||
return {
|
return {
|
||||||
year: time.getFullYear(),
|
year: time.getFullYear(),
|
||||||
month: time.getMonth(),
|
month: time.getMonth(),
|
||||||
@@ -390,7 +390,7 @@ limitations under the License. -->
|
|||||||
state.year--;
|
state.year--;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const is = (e: any) => {
|
const is = (e: Recordable) => {
|
||||||
return e.target.className.indexOf(`${state.pre}-date-disabled`) === -1;
|
return e.target.className.indexOf(`${state.pre}-date-disabled`) === -1;
|
||||||
};
|
};
|
||||||
const ok = (info: any) => {
|
const ok = (info: any) => {
|
||||||
|
@@ -54,7 +54,7 @@ limitations under the License. -->
|
|||||||
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";
|
||||||
|
|
||||||
/*global Nullable, defineProps, defineEmits*/
|
/*global Nullable, defineProps, defineEmits, Indexable*/
|
||||||
const emits = defineEmits(["select"]);
|
const emits = defineEmits(["select"]);
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const chartRef = ref<Nullable<HTMLDivElement>>(null);
|
const chartRef = ref<Nullable<HTMLDivElement>>(null);
|
||||||
@@ -70,7 +70,7 @@ limitations under the License. -->
|
|||||||
height: { type: String, default: "100%" },
|
height: { type: String, default: "100%" },
|
||||||
width: { type: String, default: "100%" },
|
width: { type: String, default: "100%" },
|
||||||
option: {
|
option: {
|
||||||
type: Object as PropType<{ [key: string]: any }>,
|
type: Object as PropType<Indexable>,
|
||||||
default: () => ({}),
|
default: () => ({}),
|
||||||
},
|
},
|
||||||
filters: {
|
filters: {
|
||||||
|
@@ -76,7 +76,7 @@ limitations under the License. -->
|
|||||||
function handleClick() {
|
function handleClick() {
|
||||||
visible.value = false;
|
visible.value = false;
|
||||||
}
|
}
|
||||||
function setPopper(event: any) {
|
function setPopper(event: MouseEvent) {
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
visible.value = !visible.value;
|
visible.value = !visible.value;
|
||||||
}
|
}
|
||||||
|
@@ -27,7 +27,13 @@ limitations under the License. -->
|
|||||||
:remote-method="remoteMethod"
|
:remote-method="remoteMethod"
|
||||||
:filterable="filterable"
|
:filterable="filterable"
|
||||||
>
|
>
|
||||||
<el-option v-for="item in options" :key="item.value || ''" :label="item.label || ''" :value="item.value || ''">
|
<el-option
|
||||||
|
v-for="item in options"
|
||||||
|
:key="item.value || ''"
|
||||||
|
:label="item.label || ''"
|
||||||
|
:value="item.value || ''"
|
||||||
|
:disabled="item.disabled || false"
|
||||||
|
>
|
||||||
</el-option>
|
</el-option>
|
||||||
</el-select>
|
</el-select>
|
||||||
</template>
|
</template>
|
||||||
@@ -40,7 +46,7 @@ limitations under the License. -->
|
|||||||
// value: string | number;
|
// value: string | number;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
/*global defineProps, defineEmits*/
|
/*global defineProps, defineEmits, Indexable*/
|
||||||
const emit = defineEmits(["change", "query"]);
|
const emit = defineEmits(["change", "query"]);
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
options: {
|
options: {
|
||||||
@@ -71,7 +77,7 @@ limitations under the License. -->
|
|||||||
|
|
||||||
const selected = ref<string[] | string>(props.value);
|
const selected = ref<string[] | string>(props.value);
|
||||||
function changeSelected() {
|
function changeSelected() {
|
||||||
const options = props.options.filter((d: any) =>
|
const options = props.options.filter((d: Indexable) =>
|
||||||
props.multiple ? selected.value.includes(d.value) : selected.value === d.value,
|
props.multiple ? selected.value.includes(d.value) : selected.value === d.value,
|
||||||
);
|
);
|
||||||
emit("change", options);
|
emit("change", options);
|
||||||
|
@@ -241,7 +241,7 @@ limitations under the License. -->
|
|||||||
}
|
}
|
||||||
dates.value[0] = d;
|
dates.value[0] = d;
|
||||||
};
|
};
|
||||||
const dc = (e: any) => {
|
const dc = (e: MouseEvent) => {
|
||||||
show.value = (datepicker.value as any).contains(e.target) && !props.disabled;
|
show.value = (datepicker.value as any).contains(e.target) && !props.disabled;
|
||||||
};
|
};
|
||||||
const quickPick = (type: string) => {
|
const quickPick = (type: string) => {
|
||||||
|
@@ -23,7 +23,7 @@ import Radio from "./Radio.vue";
|
|||||||
import SelectSingle from "./SelectSingle.vue";
|
import SelectSingle from "./SelectSingle.vue";
|
||||||
import VueGridLayout from "vue-grid-layout";
|
import VueGridLayout from "vue-grid-layout";
|
||||||
|
|
||||||
const components: { [key: string]: any } = {
|
const components: Indexable = {
|
||||||
Icon,
|
Icon,
|
||||||
TimePicker,
|
TimePicker,
|
||||||
VueGridLayout,
|
VueGridLayout,
|
||||||
|
@@ -33,20 +33,37 @@ export const createEBPFTask = {
|
|||||||
}`,
|
}`,
|
||||||
};
|
};
|
||||||
export const queryEBPFTasks = {
|
export const queryEBPFTasks = {
|
||||||
variable: "$serviceId: ID, $serviceInstanceId: ID, $targets: [EBPFProfilingTargetType!]",
|
variable:
|
||||||
|
"$serviceId: ID, $serviceInstanceId: ID, $targets: [EBPFProfilingTargetType!], $triggerType: EBPFProfilingTriggerType",
|
||||||
query: `
|
query: `
|
||||||
queryEBPFTasks: queryEBPFProfilingTasks(serviceId: $serviceId, serviceInstanceId: $serviceInstanceId, targets: $targets) {
|
queryEBPFTasks: queryEBPFProfilingTasks(serviceId: $serviceId, serviceInstanceId: $serviceInstanceId, targets: $targets, triggerType: $triggerType) {
|
||||||
taskId
|
taskId
|
||||||
serviceName
|
serviceName
|
||||||
serviceId
|
serviceId
|
||||||
serviceInstanceId
|
serviceInstanceId
|
||||||
serviceInstanceName
|
serviceInstanceName
|
||||||
processLabels
|
processLabels
|
||||||
|
processName
|
||||||
|
processId
|
||||||
taskStartTime
|
taskStartTime
|
||||||
triggerType
|
triggerType
|
||||||
fixedTriggerDuration
|
fixedTriggerDuration
|
||||||
targetType
|
targetType
|
||||||
createTime
|
createTime
|
||||||
|
continuousProfilingCauses {
|
||||||
|
type
|
||||||
|
singleValue {
|
||||||
|
threshold
|
||||||
|
current
|
||||||
|
}
|
||||||
|
uri {
|
||||||
|
uriRegex
|
||||||
|
uriPath
|
||||||
|
threshold
|
||||||
|
current
|
||||||
|
}
|
||||||
|
message
|
||||||
|
}
|
||||||
}`,
|
}`,
|
||||||
};
|
};
|
||||||
export const queryEBPFSchedules = {
|
export const queryEBPFSchedules = {
|
||||||
@@ -111,3 +128,26 @@ export const keepNetworkProfiling = {
|
|||||||
errorReason
|
errorReason
|
||||||
}`,
|
}`,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const monitoringInstances = {
|
||||||
|
variable: "$serviceId: ID!, $target: ContinuousProfilingTargetType!",
|
||||||
|
query: `
|
||||||
|
instances: queryContinuousProfilingMonitoringInstances(serviceId: $serviceId, target: $target) {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
attributes {
|
||||||
|
name
|
||||||
|
value
|
||||||
|
}
|
||||||
|
triggeredCount
|
||||||
|
lastTriggerTimestamp
|
||||||
|
processes {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
detectType
|
||||||
|
labels
|
||||||
|
lastTriggerTimestamp
|
||||||
|
triggeredCount
|
||||||
|
}
|
||||||
|
}`,
|
||||||
|
};
|
||||||
|
@@ -15,37 +15,6 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export const ProfileSegment = {
|
|
||||||
variable: "$segmentId: String",
|
|
||||||
query: `
|
|
||||||
segment: getProfiledSegment(segmentId: $segmentId) {
|
|
||||||
spans {
|
|
||||||
spanId
|
|
||||||
parentSpanId
|
|
||||||
serviceCode
|
|
||||||
startTime
|
|
||||||
endTime
|
|
||||||
endpointName
|
|
||||||
type
|
|
||||||
peer
|
|
||||||
component
|
|
||||||
isError
|
|
||||||
layer
|
|
||||||
tags {
|
|
||||||
key value
|
|
||||||
}
|
|
||||||
logs {
|
|
||||||
time
|
|
||||||
data {
|
|
||||||
key
|
|
||||||
value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
};
|
|
||||||
|
|
||||||
export const CreateProfileTask = {
|
export const CreateProfileTask = {
|
||||||
variable: "$creationRequest: ProfileTaskCreationRequest",
|
variable: "$creationRequest: ProfileTaskCreationRequest",
|
||||||
query: `
|
query: `
|
||||||
@@ -79,23 +48,55 @@ export const GetProfileTaskList = {
|
|||||||
`,
|
`,
|
||||||
};
|
};
|
||||||
export const GetProfileTaskSegmentList = {
|
export const GetProfileTaskSegmentList = {
|
||||||
variable: "$taskID: String",
|
variable: "$taskID: ID!",
|
||||||
query: `
|
query: `
|
||||||
segmentList: getProfileTaskSegmentList(taskID: $taskID) {
|
segmentList: getProfileTaskSegments(taskID: $taskID) {
|
||||||
segmentId
|
traceId
|
||||||
|
instanceId
|
||||||
|
instanceName
|
||||||
endpointNames
|
endpointNames
|
||||||
start
|
|
||||||
duration
|
duration
|
||||||
traceIds
|
start
|
||||||
|
spans {
|
||||||
|
spanId
|
||||||
|
parentSpanId
|
||||||
|
segmentId
|
||||||
|
refs {
|
||||||
|
traceId
|
||||||
|
parentSegmentId
|
||||||
|
parentSpanId
|
||||||
|
type
|
||||||
|
}
|
||||||
|
serviceCode
|
||||||
|
serviceInstanceName
|
||||||
|
startTime
|
||||||
|
endTime
|
||||||
|
endpointName
|
||||||
|
type
|
||||||
|
peer
|
||||||
|
component
|
||||||
isError
|
isError
|
||||||
|
layer
|
||||||
|
tags {
|
||||||
|
key value
|
||||||
|
}
|
||||||
|
logs {
|
||||||
|
time
|
||||||
|
data {
|
||||||
|
key
|
||||||
|
value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
profiled
|
||||||
|
}
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
};
|
};
|
||||||
|
|
||||||
export const GetProfileAnalyze = {
|
export const GetProfileAnalyze = {
|
||||||
variable: "$segmentId: String!, $timeRanges: [ProfileAnalyzeTimeRange!]!",
|
variable: "$queries: [SegmentProfileAnalyzeQuery!]!",
|
||||||
query: `
|
query: `
|
||||||
analyze: getProfileAnalyze(segmentId: $segmentId, timeRanges: $timeRanges) {
|
analyze: getSegmentsProfileAnalyze(queries: $queries) {
|
||||||
tip
|
tip
|
||||||
trees {
|
trees {
|
||||||
elements {
|
elements {
|
||||||
@@ -122,3 +123,29 @@ export const GetProfileTaskLogs = {
|
|||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
};
|
};
|
||||||
|
export const GetStrategyList = {
|
||||||
|
variable: "$serviceId: ID!",
|
||||||
|
query: `
|
||||||
|
strategyList: queryContinuousProfilingServiceTargets(serviceId: $serviceId) {
|
||||||
|
type
|
||||||
|
checkItems {
|
||||||
|
type
|
||||||
|
threshold
|
||||||
|
period
|
||||||
|
count
|
||||||
|
uriList
|
||||||
|
uriRegex
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const EditStrategy = {
|
||||||
|
variable: "$request: ContinuousProfilingPolicyCreation!",
|
||||||
|
query: `
|
||||||
|
strategy: setContinuousProfilingPolicy(request: $request) {
|
||||||
|
errorReason
|
||||||
|
status
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
};
|
||||||
|
@@ -23,6 +23,7 @@ import {
|
|||||||
analysisEBPFResult,
|
analysisEBPFResult,
|
||||||
createNetworkProfiling,
|
createNetworkProfiling,
|
||||||
keepNetworkProfiling,
|
keepNetworkProfiling,
|
||||||
|
monitoringInstances,
|
||||||
} from "../fragments/ebpf";
|
} from "../fragments/ebpf";
|
||||||
|
|
||||||
export const getCreateTaskData = `query queryCreateTaskData(${queryCreateTaskData.variable}) {${queryCreateTaskData.query}}`;
|
export const getCreateTaskData = `query queryCreateTaskData(${queryCreateTaskData.variable}) {${queryCreateTaskData.query}}`;
|
||||||
@@ -38,3 +39,5 @@ export const getEBPFResult = `query analysisEBPFResult(${analysisEBPFResult.vari
|
|||||||
export const newNetworkProfiling = `mutation createNetworkProfiling(${createNetworkProfiling.variable}) {${createNetworkProfiling.query}}`;
|
export const newNetworkProfiling = `mutation createNetworkProfiling(${createNetworkProfiling.variable}) {${createNetworkProfiling.query}}`;
|
||||||
|
|
||||||
export const aliveNetworkProfiling = `mutation keepNetworkProfiling(${keepNetworkProfiling.variable}) {${keepNetworkProfiling.query}}`;
|
export const aliveNetworkProfiling = `mutation keepNetworkProfiling(${keepNetworkProfiling.variable}) {${keepNetworkProfiling.query}}`;
|
||||||
|
|
||||||
|
export const getMonitoringInstances = `query continuousProfilingMonitoringInstances(${monitoringInstances.variable}) {${monitoringInstances.query}}`;
|
||||||
|
@@ -16,16 +16,15 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import {
|
import {
|
||||||
ProfileSegment,
|
|
||||||
CreateProfileTask,
|
CreateProfileTask,
|
||||||
GetProfileTaskList,
|
GetProfileTaskList,
|
||||||
GetProfileTaskSegmentList,
|
GetProfileTaskSegmentList,
|
||||||
GetProfileAnalyze,
|
GetProfileAnalyze,
|
||||||
GetProfileTaskLogs,
|
GetProfileTaskLogs,
|
||||||
|
GetStrategyList,
|
||||||
|
EditStrategy,
|
||||||
} from "../fragments/profile";
|
} from "../fragments/profile";
|
||||||
|
|
||||||
export const queryProfileSegment = `query queryProfileSegment(${ProfileSegment.variable}) {${ProfileSegment.query}}`;
|
|
||||||
|
|
||||||
export const saveProfileTask = `mutation createProfileTask(${CreateProfileTask.variable}) {${CreateProfileTask.query}}`;
|
export const saveProfileTask = `mutation createProfileTask(${CreateProfileTask.variable}) {${CreateProfileTask.query}}`;
|
||||||
|
|
||||||
export const getProfileTaskList = `query getProfileTaskList(${GetProfileTaskList.variable}) {
|
export const getProfileTaskList = `query getProfileTaskList(${GetProfileTaskList.variable}) {
|
||||||
@@ -37,3 +36,7 @@ export const getProfileTaskSegmentList = `query getProfileTaskSegmentList(${GetP
|
|||||||
export const getProfileAnalyze = `query getProfileAnalyze(${GetProfileAnalyze.variable}) {${GetProfileAnalyze.query}}`;
|
export const getProfileAnalyze = `query getProfileAnalyze(${GetProfileAnalyze.variable}) {${GetProfileAnalyze.query}}`;
|
||||||
|
|
||||||
export const getProfileTaskLogs = `query profileTaskLogs(${GetProfileTaskLogs.variable}) {${GetProfileTaskLogs.query}}`;
|
export const getProfileTaskLogs = `query profileTaskLogs(${GetProfileTaskLogs.variable}) {${GetProfileTaskLogs.query}}`;
|
||||||
|
|
||||||
|
export const getStrategyList = `query getStrategyList(${GetStrategyList.variable}) {${GetStrategyList.query}}`;
|
||||||
|
|
||||||
|
export const editStrategy = `mutation editStrategy(${EditStrategy.variable}) {${EditStrategy.query}}`;
|
||||||
|
@@ -22,6 +22,7 @@ export enum MetricQueryTypes {
|
|||||||
READHEATMAP = "readHeatMap",
|
READHEATMAP = "readHeatMap",
|
||||||
ReadSampledRecords = "readSampledRecords",
|
ReadSampledRecords = "readSampledRecords",
|
||||||
ReadRecords = "readRecords",
|
ReadRecords = "readRecords",
|
||||||
|
ReadNullableMetricsValue = "readNullableMetricsValue",
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum Calculations {
|
export enum Calculations {
|
||||||
@@ -38,8 +39,6 @@ export enum Calculations {
|
|||||||
ApdexAvg = "apdexAvg",
|
ApdexAvg = "apdexAvg",
|
||||||
SecondToDay = "secondToDay",
|
SecondToDay = "secondToDay",
|
||||||
NanosecondToMillisecond = "nanosecondToMillisecond",
|
NanosecondToMillisecond = "nanosecondToMillisecond",
|
||||||
CPM5D = "cpm5d",
|
|
||||||
CPM5DAvg = "cpm5dAvg",
|
|
||||||
}
|
}
|
||||||
export enum sizeEnum {
|
export enum sizeEnum {
|
||||||
XS = "XS",
|
XS = "XS",
|
||||||
@@ -68,14 +67,18 @@ screenMap.set(sizeEnum.LG, screenEnum.LG);
|
|||||||
screenMap.set(sizeEnum.XL, screenEnum.XL);
|
screenMap.set(sizeEnum.XL, screenEnum.XL);
|
||||||
screenMap.set(sizeEnum.XXL, screenEnum.XXL);
|
screenMap.set(sizeEnum.XXL, screenEnum.XXL);
|
||||||
|
|
||||||
export const RespFields: { [key: string]: string } = {
|
export const RespFields: Indexable = {
|
||||||
readMetricsValues: `{
|
readMetricsValues: `{
|
||||||
label
|
label
|
||||||
values {
|
values {
|
||||||
values {value}
|
values {value isEmptyValue}
|
||||||
}
|
}
|
||||||
}`,
|
}`,
|
||||||
readMetricsValue: "",
|
readMetricsValue: ``,
|
||||||
|
readNullableMetricsValue: `{
|
||||||
|
value
|
||||||
|
isEmptyValue
|
||||||
|
}`,
|
||||||
sortMetrics: `{
|
sortMetrics: `{
|
||||||
name
|
name
|
||||||
id
|
id
|
||||||
@@ -85,7 +88,7 @@ export const RespFields: { [key: string]: string } = {
|
|||||||
readLabeledMetricsValues: `{
|
readLabeledMetricsValues: `{
|
||||||
label
|
label
|
||||||
values {
|
values {
|
||||||
values {value}
|
values {value isEmptyValue}
|
||||||
}
|
}
|
||||||
}`,
|
}`,
|
||||||
readHeatMap: `{
|
readHeatMap: `{
|
||||||
@@ -109,4 +112,21 @@ export const RespFields: { [key: string]: string } = {
|
|||||||
value
|
value
|
||||||
refId
|
refId
|
||||||
}`,
|
}`,
|
||||||
|
execExpression: `{
|
||||||
|
type
|
||||||
|
results {
|
||||||
|
metric {
|
||||||
|
labels {
|
||||||
|
key
|
||||||
|
value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
values {
|
||||||
|
name: id
|
||||||
|
value
|
||||||
|
refId: traceID
|
||||||
|
}
|
||||||
|
}
|
||||||
|
error
|
||||||
|
}`,
|
||||||
};
|
};
|
||||||
|
@@ -19,7 +19,7 @@ import dateFormatStep from "@/utils/dateFormat";
|
|||||||
import getLocalTime from "@/utils/localtime";
|
import getLocalTime from "@/utils/localtime";
|
||||||
import type { EventParams } from "@/types/app";
|
import type { EventParams } from "@/types/app";
|
||||||
|
|
||||||
export default function associateProcessor(props: any) {
|
export default function associateProcessor(props: Indexable) {
|
||||||
function eventAssociate() {
|
function eventAssociate() {
|
||||||
if (!props.filters) {
|
if (!props.filters) {
|
||||||
return;
|
return;
|
||||||
@@ -85,7 +85,7 @@ export default function associateProcessor(props: any) {
|
|||||||
const queryOrder = relatedTrace.queryOrder;
|
const queryOrder = relatedTrace.queryOrder;
|
||||||
const latency = relatedTrace.latency;
|
const latency = relatedTrace.latency;
|
||||||
const series = props.option.series || [];
|
const series = props.option.series || [];
|
||||||
const item: any = {
|
const item: Indexable = {
|
||||||
duration,
|
duration,
|
||||||
queryOrder,
|
queryOrder,
|
||||||
status,
|
status,
|
||||||
|
@@ -32,7 +32,7 @@ export interface CreateCallbackParams {
|
|||||||
sizeEnum: typeof sizeEnum;
|
sizeEnum: typeof sizeEnum;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useBreakpoint(): any {
|
export function useBreakpoint(): Indexable {
|
||||||
return {
|
return {
|
||||||
screenRef: computed(() => unref(globalScreenRef)),
|
screenRef: computed(() => unref(globalScreenRef)),
|
||||||
widthRef: globalWidthRef,
|
widthRef: globalWidthRef,
|
||||||
@@ -41,7 +41,7 @@ export function useBreakpoint(): any {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createBreakpointListen(fn?: (opt: CreateCallbackParams) => void): any {
|
export function createBreakpointListen(fn?: (opt: CreateCallbackParams) => void): Indexable {
|
||||||
const screenRef = ref<sizeEnum>(sizeEnum.XL || "");
|
const screenRef = ref<sizeEnum>(sizeEnum.XL || "");
|
||||||
const realWidthRef = ref(window.innerWidth);
|
const realWidthRef = ref(window.innerWidth);
|
||||||
|
|
||||||
|
@@ -59,7 +59,7 @@ export default function getDashboard(param?: { name: string; layer: string; enti
|
|||||||
if (targetTabIndex[1] === undefined) {
|
if (targetTabIndex[1] === undefined) {
|
||||||
container = document.querySelector(".ds-main");
|
container = document.querySelector(".ds-main");
|
||||||
} else {
|
} else {
|
||||||
const w = widgets.find((d: any) => d.id === targetTabIndex[0]);
|
const w = widgets.find((d: Indexable) => d.id === targetTabIndex[0]);
|
||||||
container = document.querySelector(".tab-layout");
|
container = document.querySelector(".tab-layout");
|
||||||
const layout: Nullable<Element> = document.querySelector(".ds-main");
|
const layout: Nullable<Element> = document.querySelector(".ds-main");
|
||||||
if (w && layout) {
|
if (w && layout) {
|
||||||
|
@@ -43,7 +43,7 @@ export type ECOption = echarts.ComposeOption<
|
|||||||
| SankeySeriesOption
|
| SankeySeriesOption
|
||||||
>;
|
>;
|
||||||
|
|
||||||
export function useECharts(elRef: Ref<HTMLDivElement>, theme: "light" | "dark" | "default" = "default"): any {
|
export function useECharts(elRef: Ref<HTMLDivElement>, theme: "light" | "dark" | "default" = "default"): Indexable {
|
||||||
const getDarkMode = computed(() => {
|
const getDarkMode = computed(() => {
|
||||||
return theme === "default" ? "light" : theme;
|
return theme === "default" ? "light" : theme;
|
||||||
});
|
});
|
||||||
|
@@ -20,7 +20,7 @@ import { useThrottleFn, useDebounceFn } from "@vueuse/core";
|
|||||||
|
|
||||||
export type RemoveEventFn = () => void;
|
export type RemoveEventFn = () => void;
|
||||||
export interface UseEventParams {
|
export interface UseEventParams {
|
||||||
el?: Element | Ref<Element | undefined> | Window | any;
|
el?: Element | Ref<Element | undefined> | Window | Recordable;
|
||||||
name: string;
|
name: string;
|
||||||
listener: EventListener;
|
listener: EventListener;
|
||||||
options?: boolean | AddEventListenerOptions;
|
options?: boolean | AddEventListenerOptions;
|
||||||
|
313
src/hooks/useExpressionsProcessor.ts
Normal file
@@ -0,0 +1,313 @@
|
|||||||
|
/**
|
||||||
|
* 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 { RespFields } from "./data";
|
||||||
|
import { ExpressionResultType } from "@/views/dashboard/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 { MetricConfigOpt } from "@/types/dashboard";
|
||||||
|
import type { Instance, Endpoint, Service } from "@/types/selector";
|
||||||
|
|
||||||
|
export async function useExpressionsQueryProcessor(config: Indexable) {
|
||||||
|
function expressionsGraphqlPods() {
|
||||||
|
if (!(config.metrics && config.metrics[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) => {
|
||||||
|
variables.push(`$expression${index}: String!`, `$entity${index}: Entity!`);
|
||||||
|
conditions[`expression${index}`] = name;
|
||||||
|
const entity = {
|
||||||
|
serviceName: dashboardStore.entity === "All" ? undefined : selectorStore.currentService.value,
|
||||||
|
normal: dashboardStore.entity === "All" ? undefined : selectorStore.currentService.normal,
|
||||||
|
serviceInstanceName: ["ServiceInstance", "ServiceInstanceRelation", "ProcessRelation", "Process"].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,
|
||||||
|
};
|
||||||
|
conditions[`entity${index}`] = entity;
|
||||||
|
|
||||||
|
return `expression${index}: execExpression(expression: $expression${index}, entity: $entity${index}, duration: $duration)${RespFields.execExpression}`;
|
||||||
|
});
|
||||||
|
const queryStr = `query queryData(${variables}) {${fragment}}`;
|
||||||
|
|
||||||
|
return {
|
||||||
|
queryStr,
|
||||||
|
conditions,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function expressionsSource(resp: { errors: string; data: Indexable }) {
|
||||||
|
if (resp.errors) {
|
||||||
|
ElMessage.error(resp.errors);
|
||||||
|
return { source: {}, tips: [], typesOfMQE: [] };
|
||||||
|
}
|
||||||
|
if (!resp.data) {
|
||||||
|
ElMessage.error("The query is wrong");
|
||||||
|
return { source: {}, tips: [], typesOfMQE: [] };
|
||||||
|
}
|
||||||
|
const tips: string[] = [];
|
||||||
|
const source: { [key: string]: unknown } = {};
|
||||||
|
const keys = Object.keys(resp.data);
|
||||||
|
const typesOfMQE: string[] = [];
|
||||||
|
|
||||||
|
for (let i = 0; i < config.metrics.length; i++) {
|
||||||
|
const c: MetricConfigOpt = (config.metricConfig && config.metricConfig[i]) || {};
|
||||||
|
const obj = resp.data[keys[i]] || {};
|
||||||
|
const results = obj.results || [];
|
||||||
|
const name = config.metrics[i];
|
||||||
|
const type = obj.type;
|
||||||
|
|
||||||
|
tips.push(obj.error);
|
||||||
|
typesOfMQE.push(type);
|
||||||
|
if (!obj.error) {
|
||||||
|
if (type === ExpressionResultType.TIME_SERIES_VALUES) {
|
||||||
|
if (results.length === 1) {
|
||||||
|
source[c.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) {
|
||||||
|
const values = item.values.map((d: { value: unknown }) => d.value) || [];
|
||||||
|
const index = item.metric.labels[0].value;
|
||||||
|
const indexNum = labels.findIndex((_, i: number) => i === Number(index));
|
||||||
|
if (labels[indexNum] && indexNum > -1) {
|
||||||
|
source[labels[indexNum]] = values;
|
||||||
|
} else {
|
||||||
|
source[index] = 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)) {
|
||||||
|
source[name] = results[0].values;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return { source, tips, typesOfMQE };
|
||||||
|
}
|
||||||
|
const params = await expressionsGraphqlPods();
|
||||||
|
if (!params) {
|
||||||
|
return { source: {}, tips: [], typesOfMQE: [] };
|
||||||
|
}
|
||||||
|
|
||||||
|
const dashboardStore = useDashboardStore();
|
||||||
|
const json = await dashboardStore.fetchMetricValue(params);
|
||||||
|
if (json.errors) {
|
||||||
|
ElMessage.error(json.errors);
|
||||||
|
return { source: {}, tips: [], typesOfMQE: [] };
|
||||||
|
}
|
||||||
|
const data = expressionsSource(json);
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function useExpressionsQueryPodsMetrics(
|
||||||
|
pods: Array<(Instance | Endpoint | Service) & Indexable>,
|
||||||
|
config: {
|
||||||
|
expressions: string[];
|
||||||
|
subExpressions: string[];
|
||||||
|
metricConfig: MetricConfigOpt[];
|
||||||
|
},
|
||||||
|
scope: string,
|
||||||
|
) {
|
||||||
|
function expressionsGraphqlPods() {
|
||||||
|
const metrics: string[] = [];
|
||||||
|
const subMetrics: string[] = [];
|
||||||
|
config.expressions = config.expressions || [];
|
||||||
|
config.subExpressions = config.subExpressions || [];
|
||||||
|
|
||||||
|
for (let i = 0; i < config.expressions.length; i++) {
|
||||||
|
if (config.expressions[i]) {
|
||||||
|
metrics.push(config.expressions[i]);
|
||||||
|
subMetrics.push(config.subExpressions[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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 entity = {
|
||||||
|
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,
|
||||||
|
};
|
||||||
|
variables.push(`$entity${index}: Entity!`);
|
||||||
|
conditions[`entity${index}`] = entity;
|
||||||
|
const f = metrics.map((name: string, idx: number) => {
|
||||||
|
variables.push(`$expression${index}${idx}: String!`);
|
||||||
|
conditions[`expression${index}${idx}`] = name;
|
||||||
|
let str = "";
|
||||||
|
if (config.subExpressions[idx]) {
|
||||||
|
variables.push(`$subExpression${index}${idx}: String!`);
|
||||||
|
conditions[`subExpression${index}${idx}`] = config.subExpressions[idx];
|
||||||
|
str = `subexpression${index}${idx}: execExpression(expression: $subExpression${index}${idx}, entity: $entity${index}, duration: $duration)${RespFields.execExpression}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
str +
|
||||||
|
`expression${index}${idx}: execExpression(expression: $expression${index}${idx}, entity: $entity${index}, duration: $duration)${RespFields.execExpression}`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
return f;
|
||||||
|
});
|
||||||
|
const fragment = fragmentList.flat(1).join(" ");
|
||||||
|
const queryStr = `query queryData(${variables}) {${fragment}}`;
|
||||||
|
|
||||||
|
return { queryStr, conditions };
|
||||||
|
}
|
||||||
|
|
||||||
|
function expressionsPodsSource(resp: { errors: string; data: Indexable }): Indexable {
|
||||||
|
if (resp.errors) {
|
||||||
|
ElMessage.error(resp.errors);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
const names: string[] = [];
|
||||||
|
const subNames: string[] = [];
|
||||||
|
const metricConfigArr: MetricConfigOpt[] = [];
|
||||||
|
const metricTypesArr: string[] = [];
|
||||||
|
const expressionsTips: string[] = [];
|
||||||
|
const subExpressionsTips: string[] = [];
|
||||||
|
const data = pods.map((d: any, idx: number) => {
|
||||||
|
for (let index = 0; index < config.expressions.length; index++) {
|
||||||
|
const c: MetricConfigOpt = (config.metricConfig && config.metricConfig[index]) || {};
|
||||||
|
const k = "expression" + idx + index;
|
||||||
|
const sub = "subexpression" + idx + index;
|
||||||
|
const obj = resp.data[k] || {};
|
||||||
|
const results = obj.results || [];
|
||||||
|
const typesOfMQE = obj.type || "";
|
||||||
|
const subObj = resp.data[sub] || {};
|
||||||
|
const subResults = subObj.results || [];
|
||||||
|
|
||||||
|
expressionsTips.push(obj.error);
|
||||||
|
subExpressionsTips.push(subObj.error);
|
||||||
|
if (results.length > 1) {
|
||||||
|
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 < results.length; i++) {
|
||||||
|
let name = results[i].metric.labels[0].value || "";
|
||||||
|
const subValues = subResults[i] && subResults[i].values.map((d: { value: unknown }) => d.value);
|
||||||
|
const num = labelsIdx.findIndex((d: string) => d === results[i].metric.labels[0].value);
|
||||||
|
|
||||||
|
if (labels[num]) {
|
||||||
|
name = labels[num];
|
||||||
|
}
|
||||||
|
if (!d[name]) {
|
||||||
|
d[name] = {};
|
||||||
|
}
|
||||||
|
if (subValues) {
|
||||||
|
d[name]["values"] = subValues;
|
||||||
|
}
|
||||||
|
d[name]["avg"] = (results[i].values[0] || {}).value;
|
||||||
|
|
||||||
|
const j = names.find((d: string) => d === name);
|
||||||
|
|
||||||
|
if (!j) {
|
||||||
|
names.push(name);
|
||||||
|
metricConfigArr.push({ ...c, index: i });
|
||||||
|
metricTypesArr.push(typesOfMQE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!results[0]) {
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
const name = config.expressions[index] || "";
|
||||||
|
const subName = config.subExpressions[index] || "";
|
||||||
|
if (!d[name]) {
|
||||||
|
d[name] = {};
|
||||||
|
}
|
||||||
|
d[name]["avg"] = [(results[0].values[0] || {}).value];
|
||||||
|
if (subResults[0]) {
|
||||||
|
if (!d[subName]) {
|
||||||
|
d[subName] = {};
|
||||||
|
}
|
||||||
|
d[subName]["values"] = subResults[0].values.map((d: { value: number }) => d.value);
|
||||||
|
}
|
||||||
|
const j = names.find((d: string) => d === name);
|
||||||
|
if (!j) {
|
||||||
|
names.push(name);
|
||||||
|
subNames.push(subName);
|
||||||
|
metricConfigArr.push(c);
|
||||||
|
metricTypesArr.push(typesOfMQE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return d;
|
||||||
|
});
|
||||||
|
|
||||||
|
return { data, names, subNames, metricConfigArr, metricTypesArr, expressionsTips, subExpressionsTips };
|
||||||
|
}
|
||||||
|
const dashboardStore = useDashboardStore();
|
||||||
|
const params = await expressionsGraphqlPods();
|
||||||
|
const json = await dashboardStore.fetchMetricValue(params);
|
||||||
|
|
||||||
|
if (json.errors) {
|
||||||
|
ElMessage.error(json.errors);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
const expressionParams = expressionsPodsSource(json);
|
||||||
|
|
||||||
|
return expressionParams;
|
||||||
|
}
|
@@ -39,7 +39,7 @@ export default function useLegendProcess(legend?: LegendOptions) {
|
|||||||
}
|
}
|
||||||
function aggregations(data: { [key: string]: number[] }, intervalTime: string[]) {
|
function aggregations(data: { [key: string]: number[] }, intervalTime: string[]) {
|
||||||
const source: { [key: string]: unknown }[] = [];
|
const source: { [key: string]: unknown }[] = [];
|
||||||
const keys = Object.keys(data || {}).filter((i: any) => Array.isArray(data[i]) && data[i].length);
|
const keys = Object.keys(data || {}).filter((i: string) => Array.isArray(data[i]) && data[i].length);
|
||||||
const headers = [];
|
const headers = [];
|
||||||
|
|
||||||
for (const [key, value] of keys.entries()) {
|
for (const [key, value] of keys.entries()) {
|
||||||
|
@@ -15,9 +15,17 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
import { MetricQueryTypes, Calculations } from "./data";
|
import { MetricQueryTypes, Calculations } from "./data";
|
||||||
export function useListConfig(config: any, index: string) {
|
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 i = Number(index);
|
||||||
const types = [Calculations.Average, Calculations.ApdexAvg, Calculations.PercentageAvg, Calculations.CPM5DAvg];
|
const types = [Calculations.Average, Calculations.ApdexAvg, Calculations.PercentageAvg];
|
||||||
const calculation = config.metricConfig && config.metricConfig[i] && config.metricConfig[i].calculation;
|
const calculation = config.metricConfig && config.metricConfig[i] && config.metricConfig[i].calculation;
|
||||||
const isLinear =
|
const isLinear =
|
||||||
[MetricQueryTypes.ReadMetricsValues, MetricQueryTypes.ReadLabeledMetricsValues].includes(config.metricTypes[i]) &&
|
[MetricQueryTypes.ReadMetricsValues, MetricQueryTypes.ReadLabeledMetricsValues].includes(config.metricTypes[i]) &&
|
||||||
@@ -25,6 +33,7 @@ export function useListConfig(config: any, index: string) {
|
|||||||
const isAvg =
|
const isAvg =
|
||||||
[MetricQueryTypes.ReadMetricsValues, MetricQueryTypes.ReadLabeledMetricsValues].includes(config.metricTypes[i]) &&
|
[MetricQueryTypes.ReadMetricsValues, MetricQueryTypes.ReadLabeledMetricsValues].includes(config.metricTypes[i]) &&
|
||||||
types.includes(calculation);
|
types.includes(calculation);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
isLinear,
|
isLinear,
|
||||||
isAvg,
|
isAvg,
|
||||||
|
@@ -22,9 +22,8 @@ import { useSelectorStore } from "@/store/modules/selectors";
|
|||||||
import { useAppStoreWithOut } from "@/store/modules/app";
|
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||||
import type { Instance, Endpoint, Service } from "@/types/selector";
|
import type { Instance, Endpoint, Service } from "@/types/selector";
|
||||||
import type { MetricConfigOpt } from "@/types/dashboard";
|
import type { MetricConfigOpt } from "@/types/dashboard";
|
||||||
import { MetricCatalog } from "@/views/dashboard/data";
|
|
||||||
|
|
||||||
export function useQueryProcessor(config: any) {
|
export function useQueryProcessor(config: Indexable) {
|
||||||
if (!(config.metrics && config.metrics[0])) {
|
if (!(config.metrics && config.metrics[0])) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -38,7 +37,7 @@ export function useQueryProcessor(config: any) {
|
|||||||
if (!selectorStore.currentService && dashboardStore.entity !== "All") {
|
if (!selectorStore.currentService && dashboardStore.entity !== "All") {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const conditions: { [key: string]: unknown } = {
|
const conditions: Recordable = {
|
||||||
duration: appStore.durationTime,
|
duration: appStore.durationTime,
|
||||||
};
|
};
|
||||||
const variables: string[] = [`$duration: Duration!`];
|
const variables: string[] = [`$duration: Duration!`];
|
||||||
@@ -57,13 +56,11 @@ export function useQueryProcessor(config: any) {
|
|||||||
name,
|
name,
|
||||||
parentService: ["All"].includes(dashboardStore.entity) ? null : selectorStore.currentService.value,
|
parentService: ["All"].includes(dashboardStore.entity) ? null : selectorStore.currentService.value,
|
||||||
normal: selectorStore.currentService ? selectorStore.currentService.normal : true,
|
normal: selectorStore.currentService ? selectorStore.currentService.normal : true,
|
||||||
scope: config.catalog,
|
topN: Number(c.topN) || 10,
|
||||||
topN: c.topN || 10,
|
|
||||||
order: c.sortOrder || "DES",
|
order: c.sortOrder || "DES",
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
const entity = {
|
const entity = {
|
||||||
scope: config.catalog,
|
|
||||||
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,
|
||||||
serviceInstanceName: ["ServiceInstance", "ServiceInstanceRelation", "ProcessRelation"].includes(
|
serviceInstanceName: ["ServiceInstance", "ServiceInstanceRelation", "ProcessRelation"].includes(
|
||||||
@@ -95,11 +92,10 @@ export function useQueryProcessor(config: any) {
|
|||||||
conditions[`condition${index}`] = {
|
conditions[`condition${index}`] = {
|
||||||
name,
|
name,
|
||||||
parentEntity: entity,
|
parentEntity: entity,
|
||||||
topN: c.topN || 10,
|
topN: Number(c.topN) || 10,
|
||||||
order: c.sortOrder || "DES",
|
order: c.sortOrder || "DES",
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
entity.scope = dashboardStore.entity;
|
|
||||||
if (metricType === MetricQueryTypes.ReadLabeledMetricsValues) {
|
if (metricType === MetricQueryTypes.ReadLabeledMetricsValues) {
|
||||||
const labels = (c.labelsIndex || "").split(",").map((item: string) => item.replace(/^\s*|\s*$/g, ""));
|
const labels = (c.labelsIndex || "").split(",").map((item: string) => item.replace(/^\s*|\s*$/g, ""));
|
||||||
variables.push(`$labels${index}: [String!]!`);
|
variables.push(`$labels${index}: [String!]!`);
|
||||||
@@ -114,9 +110,10 @@ export function useQueryProcessor(config: any) {
|
|||||||
}
|
}
|
||||||
if (metricType === MetricQueryTypes.ReadLabeledMetricsValues) {
|
if (metricType === MetricQueryTypes.ReadLabeledMetricsValues) {
|
||||||
return `${name}${index}: ${metricType}(condition: $condition${index}, labels: $labels${index}, duration: $duration)${RespFields[metricType]}`;
|
return `${name}${index}: ${metricType}(condition: $condition${index}, labels: $labels${index}, duration: $duration)${RespFields[metricType]}`;
|
||||||
} else {
|
|
||||||
return `${name}${index}: ${metricType}(condition: $condition${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}}`;
|
const queryStr = `query queryData(${variables}) {${fragment}}`;
|
||||||
|
|
||||||
@@ -126,7 +123,7 @@ export function useQueryProcessor(config: any) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
export function useSourceProcessor(
|
export function useSourceProcessor(
|
||||||
resp: { errors: string; data: { [key: string]: any } },
|
resp: { errors: string; data: Indexable },
|
||||||
config: {
|
config: {
|
||||||
metrics: string[];
|
metrics: string[];
|
||||||
metricTypes: string[];
|
metricTypes: string[];
|
||||||
@@ -156,7 +153,9 @@ export function useSourceProcessor(
|
|||||||
const labels = (c.label || "").split(",").map((item: string) => item.replace(/^\s*|\s*$/g, ""));
|
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, ""));
|
const labelsIdx = (c.labelsIndex || "").split(",").map((item: string) => item.replace(/^\s*|\s*$/g, ""));
|
||||||
for (const item of resVal) {
|
for (const item of resVal) {
|
||||||
const values = item.values.values.map((d: { value: number }) => aggregation(Number(d.value), c));
|
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);
|
const indexNum = labelsIdx.findIndex((d: string) => d === item.label);
|
||||||
if (labels[indexNum] && indexNum > -1) {
|
if (labels[indexNum] && indexNum > -1) {
|
||||||
source[labels[indexNum]] = values;
|
source[labels[indexNum]] = values;
|
||||||
@@ -166,7 +165,8 @@ export function useSourceProcessor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (type === MetricQueryTypes.ReadMetricsValue) {
|
if (type === MetricQueryTypes.ReadMetricsValue) {
|
||||||
source[m] = aggregation(Number(Object.values(resp.data)[0]), c);
|
const v = Object.values(resp.data)[0] || {};
|
||||||
|
source[m] = v.isEmptyValue ? NaN : aggregation(Number(v.value), c);
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
(
|
(
|
||||||
@@ -181,7 +181,7 @@ export function useSourceProcessor(
|
|||||||
}
|
}
|
||||||
if (type === MetricQueryTypes.READHEATMAP) {
|
if (type === MetricQueryTypes.READHEATMAP) {
|
||||||
const resVal = Object.values(resp.data)[0] || {};
|
const resVal = Object.values(resp.data)[0] || {};
|
||||||
const nodes = [] as any;
|
const nodes = [] as Indexable[];
|
||||||
if (!(resVal && resVal.values)) {
|
if (!(resVal && resVal.values)) {
|
||||||
source[m] = { nodes: [] };
|
source[m] = { nodes: [] };
|
||||||
return;
|
return;
|
||||||
@@ -191,7 +191,7 @@ export function useSourceProcessor(
|
|||||||
|
|
||||||
nodes.push(...grids);
|
nodes.push(...grids);
|
||||||
});
|
});
|
||||||
let buckets = [] as any;
|
let buckets = [] as Indexable[];
|
||||||
if (resVal.buckets.length) {
|
if (resVal.buckets.length) {
|
||||||
buckets = [resVal.buckets[0].min, ...resVal.buckets.map((item: { min: string; max: string }) => item.max)];
|
buckets = [resVal.buckets[0].min, ...resVal.buckets.map((item: { min: string; max: string }) => item.max)];
|
||||||
}
|
}
|
||||||
@@ -204,7 +204,7 @@ export function useSourceProcessor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function useQueryPodsMetrics(
|
export function useQueryPodsMetrics(
|
||||||
pods: Array<Instance | Endpoint | Service | any>,
|
pods: Array<(Instance | Endpoint | Service) & Indexable>,
|
||||||
config: {
|
config: {
|
||||||
metrics: string[];
|
metrics: string[];
|
||||||
metricTypes: string[];
|
metricTypes: string[];
|
||||||
@@ -227,9 +227,8 @@ export function useQueryPodsMetrics(
|
|||||||
};
|
};
|
||||||
const variables: string[] = [`$duration: Duration!`];
|
const variables: string[] = [`$duration: Duration!`];
|
||||||
const currentService = selectorStore.currentService || {};
|
const currentService = selectorStore.currentService || {};
|
||||||
const fragmentList = pods.map((d: (Instance | Endpoint | Service) & { normal: boolean }, index: number) => {
|
const fragmentList = pods.map((d: (Instance | Endpoint | Service) & Indexable, index: number) => {
|
||||||
const param = {
|
const param = {
|
||||||
scope,
|
|
||||||
serviceName: scope === "Service" ? d.label : currentService.label,
|
serviceName: scope === "Service" ? d.label : currentService.label,
|
||||||
serviceInstanceName: scope === "ServiceInstance" ? d.label : undefined,
|
serviceInstanceName: scope === "ServiceInstance" ? d.label : undefined,
|
||||||
endpointName: scope === "Endpoint" ? d.label : undefined,
|
endpointName: scope === "Endpoint" ? d.label : undefined,
|
||||||
@@ -250,7 +249,9 @@ export function useQueryPodsMetrics(
|
|||||||
const labels = (c.labelsIndex || "").split(",").map((item: string) => item.replace(/^\s*|\s*$/g, ""));
|
const labels = (c.labelsIndex || "").split(",").map((item: string) => item.replace(/^\s*|\s*$/g, ""));
|
||||||
conditions[`labels${index}${idx}`] = labels;
|
conditions[`labels${index}${idx}`] = labels;
|
||||||
}
|
}
|
||||||
return `${name}${index}${idx}: ${metricType}(condition: $condition${index}${idx}, ${labelStr}duration: $duration)${RespFields[metricType]}`;
|
const t =
|
||||||
|
metricType === MetricQueryTypes.ReadMetricsValue ? MetricQueryTypes.ReadNullableMetricsValue : metricType;
|
||||||
|
return `${name}${index}${idx}: ${t}(condition: $condition${index}${idx}, ${labelStr}duration: $duration)${RespFields[t]}`;
|
||||||
});
|
});
|
||||||
return f;
|
return f;
|
||||||
});
|
});
|
||||||
@@ -262,13 +263,13 @@ export function useQueryPodsMetrics(
|
|||||||
|
|
||||||
export function usePodsSource(
|
export function usePodsSource(
|
||||||
pods: Array<Instance | Endpoint>,
|
pods: Array<Instance | Endpoint>,
|
||||||
resp: { errors: string; data: { [key: string]: any } },
|
resp: { errors: string; data: Indexable },
|
||||||
config: {
|
config: {
|
||||||
metrics: string[];
|
metrics: string[];
|
||||||
metricTypes: string[];
|
metricTypes: string[];
|
||||||
metricConfig: MetricConfigOpt[];
|
metricConfig: MetricConfigOpt[];
|
||||||
},
|
},
|
||||||
): any {
|
): Indexable {
|
||||||
if (resp.errors) {
|
if (resp.errors) {
|
||||||
ElMessage.error(resp.errors);
|
ElMessage.error(resp.errors);
|
||||||
return {};
|
return {};
|
||||||
@@ -276,12 +277,13 @@ export function usePodsSource(
|
|||||||
const names: string[] = [];
|
const names: string[] = [];
|
||||||
const metricConfigArr: MetricConfigOpt[] = [];
|
const metricConfigArr: MetricConfigOpt[] = [];
|
||||||
const metricTypesArr: string[] = [];
|
const metricTypesArr: string[] = [];
|
||||||
const data = pods.map((d: Instance | any, idx: number) => {
|
const data = pods.map((d: any, idx: number) => {
|
||||||
config.metrics.map((name: string, index: number) => {
|
config.metrics.map((name: string, index: number) => {
|
||||||
const c: any = (config.metricConfig && config.metricConfig[index]) || {};
|
const c: any = (config.metricConfig && config.metricConfig[index]) || {};
|
||||||
const key = name + idx + index;
|
const key = name + idx + index;
|
||||||
if (config.metricTypes[index] === MetricQueryTypes.ReadMetricsValue) {
|
if (config.metricTypes[index] === MetricQueryTypes.ReadMetricsValue) {
|
||||||
d[name] = aggregation(resp.data[key], c);
|
const v = resp.data[key];
|
||||||
|
d[name] = v.isEmptyValue ? NaN : aggregation(v.value, c);
|
||||||
if (idx === 0) {
|
if (idx === 0) {
|
||||||
names.push(name);
|
names.push(name);
|
||||||
metricConfigArr.push(c);
|
metricConfigArr.push(c);
|
||||||
@@ -290,14 +292,12 @@ export function usePodsSource(
|
|||||||
}
|
}
|
||||||
if (config.metricTypes[index] === MetricQueryTypes.ReadMetricsValues) {
|
if (config.metricTypes[index] === MetricQueryTypes.ReadMetricsValues) {
|
||||||
d[name] = {};
|
d[name] = {};
|
||||||
if (
|
if ([Calculations.Average, Calculations.ApdexAvg, Calculations.PercentageAvg].includes(c.calculation)) {
|
||||||
[Calculations.Average, Calculations.ApdexAvg, Calculations.PercentageAvg, Calculations.CPM5DAvg].includes(
|
|
||||||
c.calculation,
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
d[name]["avg"] = calculateExp(resp.data[key].values.values, c);
|
d[name]["avg"] = calculateExp(resp.data[key].values.values, c);
|
||||||
}
|
}
|
||||||
d[name]["values"] = resp.data[key].values.values.map((val: { value: number }) => aggregation(val.value, 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) {
|
if (idx === 0) {
|
||||||
names.push(name);
|
names.push(name);
|
||||||
metricConfigArr.push(c);
|
metricConfigArr.push(c);
|
||||||
@@ -310,7 +310,9 @@ export function usePodsSource(
|
|||||||
const labelsIdx = (c.labelsIndex || "").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++) {
|
for (let i = 0; i < resVal.length; i++) {
|
||||||
const item = resVal[i];
|
const item = resVal[i];
|
||||||
const values = item.values.values.map((d: { value: number }) => aggregation(Number(d.value), c));
|
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);
|
const indexNum = labelsIdx.findIndex((d: string) => d === item.label);
|
||||||
let key = item.label;
|
let key = item.label;
|
||||||
if (labels[indexNum] && indexNum > -1) {
|
if (labels[indexNum] && indexNum > -1) {
|
||||||
@@ -319,11 +321,7 @@ export function usePodsSource(
|
|||||||
if (!d[key]) {
|
if (!d[key]) {
|
||||||
d[key] = {};
|
d[key] = {};
|
||||||
}
|
}
|
||||||
if (
|
if ([Calculations.Average, Calculations.ApdexAvg, Calculations.PercentageAvg].includes(c.calculation)) {
|
||||||
[Calculations.Average, Calculations.ApdexAvg, Calculations.PercentageAvg, Calculations.CPM5DAvg].includes(
|
|
||||||
c.calculation,
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
d[key]["avg"] = calculateExp(item.values.values, c);
|
d[key]["avg"] = calculateExp(item.values.values, c);
|
||||||
}
|
}
|
||||||
d[key]["values"] = values;
|
d[key]["values"] = values;
|
||||||
@@ -364,8 +362,12 @@ export function useQueryTopologyMetrics(metrics: string[], ids: string[]) {
|
|||||||
|
|
||||||
return { queryStr, conditions };
|
return { queryStr, conditions };
|
||||||
}
|
}
|
||||||
function calculateExp(arr: { value: number }[], config: { calculation?: string }): (number | string)[] {
|
export function calculateExp(
|
||||||
const sum = arr.map((d: { value: number }) => d.value).reduce((a, b) => a + b);
|
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)[] = [];
|
let data: (number | string)[] = [];
|
||||||
switch (config.calculation) {
|
switch (config.calculation) {
|
||||||
case Calculations.Average:
|
case Calculations.Average:
|
||||||
@@ -377,15 +379,10 @@ function calculateExp(arr: { value: number }[], config: { calculation?: string }
|
|||||||
case Calculations.ApdexAvg:
|
case Calculations.ApdexAvg:
|
||||||
data = [(sum / arr.length / 10000).toFixed(2)];
|
data = [(sum / arr.length / 10000).toFixed(2)];
|
||||||
break;
|
break;
|
||||||
case Calculations.CPM5DAvg:
|
|
||||||
data = [
|
|
||||||
sum / arr.length / 100000 < 1 && sum / arr.length / 100000 !== 0
|
|
||||||
? (sum / arr.length / 100000).toFixed(5)
|
|
||||||
: (sum / arr.length / 100000).toFixed(2),
|
|
||||||
];
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
data = arr.map((d) => aggregation(d.value, config));
|
data = list.map((d: { value: number; isEmptyValue: boolean }) =>
|
||||||
|
d.isEmptyValue ? NaN : aggregation(d.value, config),
|
||||||
|
);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return data;
|
return data;
|
||||||
@@ -413,9 +410,6 @@ export function aggregation(val: number, config: { calculation?: string }): numb
|
|||||||
case Calculations.Apdex:
|
case Calculations.Apdex:
|
||||||
data = (val / 10000).toFixed(2);
|
data = (val / 10000).toFixed(2);
|
||||||
break;
|
break;
|
||||||
case Calculations.CPM5D:
|
|
||||||
data = val / 100000 < 1 && val / 100000 !== 0 ? (val / 100000).toFixed(5) : (val / 100000).toFixed(2);
|
|
||||||
break;
|
|
||||||
case Calculations.ConvertSeconds:
|
case Calculations.ConvertSeconds:
|
||||||
data = dayjs(val * 1000).format("YYYY-MM-DD HH:mm:ss");
|
data = dayjs(val * 1000).format("YYYY-MM-DD HH:mm:ss");
|
||||||
break;
|
break;
|
||||||
@@ -434,9 +428,6 @@ export function aggregation(val: number, config: { calculation?: string }): numb
|
|||||||
case Calculations.ApdexAvg:
|
case Calculations.ApdexAvg:
|
||||||
data = (val / 10000).toFixed(2);
|
data = (val / 10000).toFixed(2);
|
||||||
break;
|
break;
|
||||||
case Calculations.CPM5DAvg:
|
|
||||||
data = val / 100000 < 1 && val / 100000 !== 0 ? (val / 100000).toFixed(5) : (val / 100000).toFixed(2);
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
data;
|
data;
|
||||||
break;
|
break;
|
||||||
@@ -444,26 +435,3 @@ export function aggregation(val: number, config: { calculation?: string }): numb
|
|||||||
|
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function useGetMetricEntity(metric: string, metricType: any) {
|
|
||||||
if (!metric || !metricType) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let catalog = "";
|
|
||||||
const dashboardStore = useDashboardStore();
|
|
||||||
if (
|
|
||||||
[MetricQueryTypes.ReadSampledRecords, MetricQueryTypes.SortMetrics, MetricQueryTypes.ReadRecords].includes(
|
|
||||||
metricType,
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
const res = await dashboardStore.fetchMetricList(metric);
|
|
||||||
if (res.errors) {
|
|
||||||
ElMessage.error(res.errors);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const c: string = res.data.metrics[0].catalog;
|
|
||||||
catalog = (MetricCatalog as any)[c];
|
|
||||||
}
|
|
||||||
|
|
||||||
return catalog;
|
|
||||||
}
|
|
||||||
|
@@ -38,7 +38,7 @@ export function useTimeoutFn(handle: Fn<any>, wait: number, native = false): any
|
|||||||
return { readyRef, stop, start };
|
return { readyRef, stop, start };
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useTimeoutRef(wait: number): any {
|
export function useTimeoutRef(wait: number) {
|
||||||
const readyRef = ref(false);
|
const readyRef = ref(false);
|
||||||
|
|
||||||
let timer: TimeoutHandle;
|
let timer: TimeoutHandle;
|
||||||
|
@@ -47,6 +47,7 @@ limitations under the License. -->
|
|||||||
import { useAppStoreWithOut } from "@/store/modules/app";
|
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||||
import { ElMessage } from "element-plus";
|
import { ElMessage } from "element-plus";
|
||||||
|
|
||||||
|
/*global Indexable */
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const appStore = useAppStoreWithOut();
|
const appStore = useAppStoreWithOut();
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
@@ -65,7 +66,7 @@ limitations under the License. -->
|
|||||||
appStore.setDuration(timeFormat(dates));
|
appStore.setDuration(timeFormat(dates));
|
||||||
}
|
}
|
||||||
|
|
||||||
function changeTimeRange(val: Date[] | any) {
|
function changeTimeRange(val: Date[]) {
|
||||||
timeRange.value = val[1].getTime() - val[0].getTime() > 60 * 24 * 60 * 60 * 1000 ? 1 : 0;
|
timeRange.value = val[1].getTime() - val[0].getTime() > 60 * 24 * 60 * 60 * 1000 ? 1 : 0;
|
||||||
if (timeRange.value) {
|
if (timeRange.value) {
|
||||||
return;
|
return;
|
||||||
@@ -86,7 +87,7 @@ limitations under the License. -->
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
function resetDuration() {
|
function resetDuration() {
|
||||||
const { duration }: any = route.params;
|
const { duration }: Indexable = route.params;
|
||||||
if (duration) {
|
if (duration) {
|
||||||
const d = JSON.parse(duration);
|
const d = JSON.parse(duration);
|
||||||
|
|
||||||
|
@@ -74,6 +74,7 @@ limitations under the License. -->
|
|||||||
import Icon from "@/components/Icon.vue";
|
import Icon from "@/components/Icon.vue";
|
||||||
import { useAppStoreWithOut } from "@/store/modules/app";
|
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||||
|
|
||||||
|
/*global Recordable*/
|
||||||
const appStore = useAppStoreWithOut();
|
const appStore = useAppStoreWithOut();
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const name = ref<string>(String(useRouter().currentRoute.value.name));
|
const name = ref<string>(String(useRouter().currentRoute.value.name));
|
||||||
@@ -95,7 +96,7 @@ limitations under the License. -->
|
|||||||
const changePage = (menu: RouteRecordRaw) => {
|
const changePage = (menu: RouteRecordRaw) => {
|
||||||
theme.value = ["VirtualMachine", "Kubernetes"].includes(String(menu.name)) ? "light" : "black";
|
theme.value = ["VirtualMachine", "Kubernetes"].includes(String(menu.name)) ? "light" : "black";
|
||||||
};
|
};
|
||||||
const filterMenus = (menus: any[]) => {
|
const filterMenus = (menus: Recordable[]) => {
|
||||||
return menus.filter((d) => d.meta && !d.meta.notShow);
|
return menus.filter((d) => d.meta && !d.meta.notShow);
|
||||||
};
|
};
|
||||||
function setCollapse() {
|
function setCollapse() {
|
||||||
@@ -184,7 +185,7 @@ limitations under the License. -->
|
|||||||
|
|
||||||
.title {
|
.title {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
max-width: 110px;
|
max-width: 200px;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
@@ -323,6 +323,7 @@ const msg = {
|
|||||||
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",
|
||||||
serviceEvents: "Service Events",
|
serviceEvents: "Service Events",
|
||||||
select: "Select",
|
select: "Select",
|
||||||
eventID: "Event ID",
|
eventID: "Event ID",
|
||||||
@@ -382,5 +383,27 @@ const msg = {
|
|||||||
AWSCloudEKS: "EKS",
|
AWSCloudEKS: "EKS",
|
||||||
AWSCloudS3: "S3",
|
AWSCloudS3: "S3",
|
||||||
AWSCloudDynamoDB: "DynamoDB",
|
AWSCloudDynamoDB: "DynamoDB",
|
||||||
|
AWSGateway: "AWS API Gateway",
|
||||||
|
APIGateway: "API Gateway",
|
||||||
|
redis: "Redis",
|
||||||
|
elasticsearch: "Elasticsearch",
|
||||||
|
mq: "MQ",
|
||||||
|
rabbitMQ: "RabbitMQ",
|
||||||
|
save: "Save",
|
||||||
|
editStrategy: "Edit Policies",
|
||||||
|
policyList: "Policy List",
|
||||||
|
targetTypes: "Target Type",
|
||||||
|
monitorType: "Monitor Type",
|
||||||
|
count: "Count",
|
||||||
|
threshold: "Threshold",
|
||||||
|
uriRegex: "URI Regex",
|
||||||
|
uriList: "URI List",
|
||||||
|
processes: "Processes",
|
||||||
|
monitorInstances: "Monitor Instances",
|
||||||
|
processDashboards: "Process Dashboards",
|
||||||
|
instanceDashboards: "Instance Dashboards",
|
||||||
|
detailLabel: "Detail Label",
|
||||||
|
summary: "Summary",
|
||||||
|
detail: "Detail",
|
||||||
};
|
};
|
||||||
export default msg;
|
export default msg;
|
||||||
|
@@ -381,5 +381,28 @@ const msg = {
|
|||||||
AWSCloudEKS: "EKS",
|
AWSCloudEKS: "EKS",
|
||||||
AWSCloudS3: "S3",
|
AWSCloudS3: "S3",
|
||||||
AWSCloudDynamoDB: "DynamoDB",
|
AWSCloudDynamoDB: "DynamoDB",
|
||||||
|
AWSGateway: "AWS API Gateway",
|
||||||
|
APIGateway: "API Gateway",
|
||||||
|
redis: "Redis",
|
||||||
|
elasticsearch: "Elasticsearch",
|
||||||
|
mq: "MQ",
|
||||||
|
rabbitMQ: "RabbitMQ",
|
||||||
|
save: "Salvar",
|
||||||
|
editStrategy: "Estrategia editorial",
|
||||||
|
policyList: "Lista de políticas",
|
||||||
|
targetTypes: "Tipo de objetivo",
|
||||||
|
monitorType: "Tipo de Monitor",
|
||||||
|
count: "Contar",
|
||||||
|
threshold: "Umbral",
|
||||||
|
uriRegex: "Lista URI",
|
||||||
|
uriList: "Lista URI",
|
||||||
|
processes: "Proceso",
|
||||||
|
attributes: "Atributos",
|
||||||
|
monitorInstances: "Ejemplo de Monitor",
|
||||||
|
processDashboards: "Tablero de proceso",
|
||||||
|
instanceDashboards: "Tablero de ejemplo",
|
||||||
|
detailLabel: "Detail Label",
|
||||||
|
summary: "Summary",
|
||||||
|
detail: "Detail",
|
||||||
};
|
};
|
||||||
export default msg;
|
export default msg;
|
||||||
|
@@ -379,5 +379,28 @@ const msg = {
|
|||||||
AWSCloudEKS: "EKS",
|
AWSCloudEKS: "EKS",
|
||||||
AWSCloudS3: "S3",
|
AWSCloudS3: "S3",
|
||||||
AWSCloudDynamoDB: "DynamoDB",
|
AWSCloudDynamoDB: "DynamoDB",
|
||||||
|
AWSGateway: "AWS API Gateway",
|
||||||
|
APIGateway: "API Gateway",
|
||||||
|
redis: "Redis",
|
||||||
|
elasticsearch: "Elasticsearch",
|
||||||
|
mq: "消息队列",
|
||||||
|
rabbitMQ: "RabbitMQ",
|
||||||
|
save: "保存",
|
||||||
|
editStrategy: "编辑策略",
|
||||||
|
policyList: "策略列表",
|
||||||
|
targetTypes: "目标类型",
|
||||||
|
monitorType: "监视器类型",
|
||||||
|
count: "总数",
|
||||||
|
threshold: "阈值",
|
||||||
|
uriRegex: "URI规则",
|
||||||
|
uriList: "URI列表",
|
||||||
|
processes: "进程",
|
||||||
|
attributes: "属性",
|
||||||
|
monitorInstances: "监视实例",
|
||||||
|
processDashboards: "进程仪表板",
|
||||||
|
instanceDashboards: "实例仪表板",
|
||||||
|
detailLabel: "详细标签",
|
||||||
|
summary: "概括",
|
||||||
|
detail: "详细",
|
||||||
};
|
};
|
||||||
export default msg;
|
export default msg;
|
||||||
|
50
src/mock/index.ts
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
/**
|
||||||
|
* 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 Mock from "mockjs";
|
||||||
|
|
||||||
|
const Random = Mock.Random;
|
||||||
|
const nodes = Mock.mock({
|
||||||
|
"nodes|500": [
|
||||||
|
{
|
||||||
|
//id
|
||||||
|
id: "@guid",
|
||||||
|
name: "@name",
|
||||||
|
"type|1": ["ActiveMQ", "activemq-consumer", "H2", "APISIX", "Express", "USER", "Flash"],
|
||||||
|
"isReal|1": [true, false],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
const calls = Mock.mock({
|
||||||
|
"links|500": [
|
||||||
|
{
|
||||||
|
//id
|
||||||
|
id: "@guid",
|
||||||
|
detectPoints: ["SERVER", "CLIENT"],
|
||||||
|
source: function () {
|
||||||
|
const d = Random.integer(0, 250);
|
||||||
|
return nodes.nodes[d].id;
|
||||||
|
},
|
||||||
|
target: function () {
|
||||||
|
const d = Random.integer(250, 499);
|
||||||
|
return nodes.nodes[d].id;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
const callsMock = calls.links;
|
||||||
|
const nodesMock = nodes.nodes;
|
||||||
|
export { callsMock, nodesMock };
|
@@ -128,6 +128,27 @@ export const routesDashboard: Array<RouteRecordRaw> = [
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: "",
|
||||||
|
redirect: "/dashboard/:layerId/:entity/:serviceId/:podId/:processId/:name",
|
||||||
|
component: () => import("@/views/dashboard/Edit.vue"),
|
||||||
|
name: "ViewProcess",
|
||||||
|
meta: {
|
||||||
|
notShow: true,
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: "/dashboard/:layerId/:entity/:serviceId/:podId/:processId/:name",
|
||||||
|
component: () => import("@/views/dashboard/Edit.vue"),
|
||||||
|
name: "ViewProcess",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "/dashboard/:layerId/:entity/:serviceId/:podId/:processId/:name/tab/:activeTabIndex",
|
||||||
|
component: () => import("@/views/dashboard/Edit.vue"),
|
||||||
|
name: "ViewProcessActiveTabIndex",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: "",
|
path: "",
|
||||||
redirect: "/dashboard/:layerId/:entity/:serviceId/:podId/:destServiceId/:destPodId/:name",
|
redirect: "/dashboard/:layerId/:entity/:serviceId/:podId/:destServiceId/:destPodId/:name",
|
||||||
|
@@ -74,6 +74,22 @@ export default [
|
|||||||
layer: "AWS_DYNAMODB",
|
layer: "AWS_DYNAMODB",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: "/aws-api-gateway",
|
||||||
|
name: "APIGateway",
|
||||||
|
meta: {
|
||||||
|
title: "APIGateway",
|
||||||
|
layer: "AWS_GATEWAY",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "/aws-api-gateway/tab/:activeTabIndex",
|
||||||
|
name: "APIGatewayActiveTabIndex",
|
||||||
|
meta: {
|
||||||
|
notShow: true,
|
||||||
|
layer: "AWS_GATEWAY",
|
||||||
|
},
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
@@ -74,6 +74,38 @@ export default [
|
|||||||
layer: "AWS_DYNAMODB",
|
layer: "AWS_DYNAMODB",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: "/redis",
|
||||||
|
name: "Redis",
|
||||||
|
meta: {
|
||||||
|
title: "redis",
|
||||||
|
layer: "REDIS",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "/redis/tab/:activeTabIndex",
|
||||||
|
name: "RedisActiveTabIndex",
|
||||||
|
meta: {
|
||||||
|
notShow: true,
|
||||||
|
layer: "REDIS",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "/elasticsearch",
|
||||||
|
name: "Elasticsearch",
|
||||||
|
meta: {
|
||||||
|
title: "elasticsearch",
|
||||||
|
layer: "ELASTICSEARCH",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "/elasticsearch/tab/:activeTabIndex",
|
||||||
|
name: "ElasticsearchActiveTabIndex",
|
||||||
|
meta: {
|
||||||
|
notShow: true,
|
||||||
|
layer: "ELASTICSEARCH",
|
||||||
|
},
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
@@ -42,6 +42,22 @@ export default [
|
|||||||
layer: "APISIX",
|
layer: "APISIX",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: "/aws-gateway",
|
||||||
|
name: "AWSGateway",
|
||||||
|
meta: {
|
||||||
|
title: "AWSGateway",
|
||||||
|
layer: "AWS_GATEWAY",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "/aws-gateway/tab/:activeTabIndex",
|
||||||
|
name: "GatewayActiveTabIndex",
|
||||||
|
meta: {
|
||||||
|
notShow: true,
|
||||||
|
layer: "AWS_GATEWAY",
|
||||||
|
},
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
@@ -24,6 +24,7 @@ import browser from "./browser";
|
|||||||
import k8s from "./k8s";
|
import k8s from "./k8s";
|
||||||
import gateway from "./gateway";
|
import gateway from "./gateway";
|
||||||
import aws from "./aws";
|
import aws from "./aws";
|
||||||
|
import mq from "./mq";
|
||||||
|
|
||||||
export default [
|
export default [
|
||||||
...general,
|
...general,
|
||||||
@@ -35,5 +36,6 @@ export default [
|
|||||||
...browser,
|
...browser,
|
||||||
...gateway,
|
...gateway,
|
||||||
...database,
|
...database,
|
||||||
|
...mq,
|
||||||
...selfObservability,
|
...selfObservability,
|
||||||
];
|
];
|
||||||
|
47
src/router/data/mq.ts
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
/**
|
||||||
|
* 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 default [
|
||||||
|
{
|
||||||
|
path: "",
|
||||||
|
name: "MQ",
|
||||||
|
meta: {
|
||||||
|
title: "mq",
|
||||||
|
icon: "mq",
|
||||||
|
hasGroup: true,
|
||||||
|
},
|
||||||
|
redirect: "/rabbitMQ",
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: "/rabbitMQ",
|
||||||
|
name: "RabbitMQ",
|
||||||
|
meta: {
|
||||||
|
title: "rabbitMQ",
|
||||||
|
layer: "RABBITMQ",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "/rabbitMQ/tab/:activeTabIndex",
|
||||||
|
name: "RabbitMQActiveTabIndex",
|
||||||
|
meta: {
|
||||||
|
notShow: true,
|
||||||
|
layer: "RABBITMQ",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
];
|
@@ -38,4 +38,18 @@ export const TimeRangeConfig = {
|
|||||||
text: "text",
|
text: "text",
|
||||||
};
|
};
|
||||||
|
|
||||||
export const ControlsTypes = ["Trace", "Profile", "Log", "DemandLog", "Ebpf", "NetworkProfiling", "ThirdPartyApp"];
|
export const ControlsTypes = [
|
||||||
|
"Trace",
|
||||||
|
"Profile",
|
||||||
|
"Log",
|
||||||
|
"DemandLog",
|
||||||
|
"Ebpf",
|
||||||
|
"NetworkProfiling",
|
||||||
|
"ThirdPartyApp",
|
||||||
|
"ContinuousProfiling",
|
||||||
|
"TaskTimeline",
|
||||||
|
];
|
||||||
|
export enum EBPFProfilingTriggerType {
|
||||||
|
FIXED_TIME = "FIXED_TIME",
|
||||||
|
CONTINUOUS_PROFILING = "CONTINUOUS_PROFILING",
|
||||||
|
}
|
||||||
|
@@ -34,7 +34,7 @@ export const alarmStore = defineStore({
|
|||||||
total: 0,
|
total: 0,
|
||||||
}),
|
}),
|
||||||
actions: {
|
actions: {
|
||||||
async getAlarms(params: any) {
|
async getAlarms(params: Recordable) {
|
||||||
const res: AxiosResponse = await graphql.query("queryAlarms").params(params);
|
const res: AxiosResponse = await graphql.query("queryAlarms").params(params);
|
||||||
if (res.data.errors) {
|
if (res.data.errors) {
|
||||||
return res.data;
|
return res.data;
|
||||||
@@ -48,6 +48,6 @@ export const alarmStore = defineStore({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
export function useAlarmStore(): any {
|
export function useAlarmStore(): Recordable {
|
||||||
return alarmStore(store);
|
return alarmStore(store);
|
||||||
}
|
}
|
||||||
|
@@ -24,17 +24,17 @@ import dateFormatStep, { dateFormatTime } from "@/utils/dateFormat";
|
|||||||
import { TimeType } from "@/constants/data";
|
import { TimeType } from "@/constants/data";
|
||||||
/*global Nullable*/
|
/*global Nullable*/
|
||||||
interface AppState {
|
interface AppState {
|
||||||
durationRow: any;
|
durationRow: Recordable;
|
||||||
utc: string;
|
utc: string;
|
||||||
utcHour: number;
|
utcHour: number;
|
||||||
utcMin: number;
|
utcMin: number;
|
||||||
eventStack: (() => unknown)[];
|
eventStack: (() => unknown)[];
|
||||||
timer: Nullable<any>;
|
timer: Nullable<TimeoutHandle>;
|
||||||
autoRefresh: boolean;
|
autoRefresh: boolean;
|
||||||
pageTitle: string;
|
pageTitle: string;
|
||||||
version: string;
|
version: string;
|
||||||
isMobile: boolean;
|
isMobile: boolean;
|
||||||
reloadTimer: Nullable<any>;
|
reloadTimer: Nullable<IntervalHandle>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const appStore = defineStore({
|
export const appStore = defineStore({
|
||||||
@@ -152,7 +152,7 @@ export const appStore = defineStore({
|
|||||||
}
|
}
|
||||||
this.timer = setTimeout(
|
this.timer = setTimeout(
|
||||||
() =>
|
() =>
|
||||||
this.eventStack.forEach((event: any) => {
|
this.eventStack.forEach((event: Function) => {
|
||||||
setTimeout(event(), 0);
|
setTimeout(event(), 0);
|
||||||
}),
|
}),
|
||||||
500,
|
500,
|
||||||
@@ -179,11 +179,11 @@ export const appStore = defineStore({
|
|||||||
this.version = res.data.data.version;
|
this.version = res.data.data.version;
|
||||||
return res.data;
|
return res.data;
|
||||||
},
|
},
|
||||||
setReloadTimer(timer: any): void {
|
setReloadTimer(timer: IntervalHandle) {
|
||||||
this.reloadTimer = timer;
|
this.reloadTimer = timer;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
export function useAppStoreWithOut(): any {
|
export function useAppStoreWithOut(): Recordable {
|
||||||
return appStore(store);
|
return appStore(store);
|
||||||
}
|
}
|
||||||
|
171
src/store/modules/continous-profiling.ts
Normal file
@@ -0,0 +1,171 @@
|
|||||||
|
/**
|
||||||
|
* 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 { defineStore } from "pinia";
|
||||||
|
import type { StrategyItem, CheckItems } from "@/types/continous-profiling";
|
||||||
|
import type { EBPFTaskList, EBPFProfilingSchedule, AnalyzationTrees } from "@/types/ebpf";
|
||||||
|
import type { Instance } from "@/types/selector";
|
||||||
|
import { store } from "@/store";
|
||||||
|
import graphql from "@/graphql";
|
||||||
|
import type { MonitorInstance, MonitorProcess } from "@/types/continous-profiling";
|
||||||
|
import type { AxiosResponse } from "axios";
|
||||||
|
import { dateFormat } from "@/utils/dateFormat";
|
||||||
|
|
||||||
|
interface ContinousProfilingState {
|
||||||
|
strategyList: Array<Recordable<StrategyItem>>;
|
||||||
|
selectedStrategy: Recordable<StrategyItem>;
|
||||||
|
taskList: Array<Recordable<EBPFTaskList>>;
|
||||||
|
selectedTask: Recordable<EBPFTaskList>;
|
||||||
|
errorTip: string;
|
||||||
|
errorReason: string;
|
||||||
|
instances: Instance[];
|
||||||
|
instance: Nullable<Instance>;
|
||||||
|
eBPFSchedules: EBPFProfilingSchedule[];
|
||||||
|
currentSchedule: EBPFProfilingSchedule | Record<string, never>;
|
||||||
|
analyzeTrees: AnalyzationTrees[];
|
||||||
|
ebpfTips: string;
|
||||||
|
aggregateType: string;
|
||||||
|
instancesLoading: boolean;
|
||||||
|
policyLoading: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const continousProfilingStore = defineStore({
|
||||||
|
id: "continousProfiling",
|
||||||
|
state: (): ContinousProfilingState => ({
|
||||||
|
strategyList: [],
|
||||||
|
selectedStrategy: {},
|
||||||
|
taskList: [],
|
||||||
|
selectedTask: {},
|
||||||
|
errorReason: "",
|
||||||
|
errorTip: "",
|
||||||
|
ebpfTips: "",
|
||||||
|
instances: [],
|
||||||
|
eBPFSchedules: [],
|
||||||
|
currentSchedule: {},
|
||||||
|
analyzeTrees: [],
|
||||||
|
aggregateType: "COUNT",
|
||||||
|
instance: null,
|
||||||
|
instancesLoading: false,
|
||||||
|
policyLoading: false,
|
||||||
|
}),
|
||||||
|
actions: {
|
||||||
|
setSelectedStrategy(task: Recordable<StrategyItem>) {
|
||||||
|
this.selectedStrategy = task || {};
|
||||||
|
},
|
||||||
|
setselectedTask(task: Recordable<EBPFTaskList>) {
|
||||||
|
this.selectedTask = task || {};
|
||||||
|
},
|
||||||
|
setCurrentSchedule(s: EBPFProfilingSchedule) {
|
||||||
|
this.currentSchedule = s;
|
||||||
|
},
|
||||||
|
setAnalyzeTrees(tree: AnalyzationTrees[]) {
|
||||||
|
this.analyzeTrees = tree;
|
||||||
|
},
|
||||||
|
setCurrentInstance(instance: Nullable<Instance>) {
|
||||||
|
this.instance = instance;
|
||||||
|
},
|
||||||
|
async setContinuousProfilingPolicy(
|
||||||
|
serviceId: string,
|
||||||
|
targets: {
|
||||||
|
targetType: string;
|
||||||
|
checkItems: CheckItems[];
|
||||||
|
}[],
|
||||||
|
) {
|
||||||
|
const res: AxiosResponse = await graphql.query("editStrategy").params({
|
||||||
|
request: {
|
||||||
|
serviceId,
|
||||||
|
targets,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (res.data.errors) {
|
||||||
|
return res.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
return res.data;
|
||||||
|
},
|
||||||
|
async getStrategyList(params: { serviceId: string }) {
|
||||||
|
if (!params.serviceId) {
|
||||||
|
return new Promise((resolve) => resolve({}));
|
||||||
|
}
|
||||||
|
this.policyLoading = true;
|
||||||
|
const res: AxiosResponse = await graphql.query("getStrategyList").params(params);
|
||||||
|
|
||||||
|
this.policyLoading = false;
|
||||||
|
if (res.data.errors) {
|
||||||
|
return res.data;
|
||||||
|
}
|
||||||
|
const list = res.data.data.strategyList || [];
|
||||||
|
if (!list.length) {
|
||||||
|
this.taskList = [];
|
||||||
|
this.instances = [];
|
||||||
|
this.instance = null;
|
||||||
|
}
|
||||||
|
const arr = list.length ? res.data.data.strategyList : [{ type: "", checkItems: [{ type: "" }] }];
|
||||||
|
this.strategyList = arr.map((d: StrategyItem, index: number) => {
|
||||||
|
return {
|
||||||
|
...d,
|
||||||
|
id: index,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
this.setSelectedStrategy(this.strategyList[0]);
|
||||||
|
if (!this.selectedStrategy.type) {
|
||||||
|
return res.data;
|
||||||
|
}
|
||||||
|
this.getMonitoringInstances(params.serviceId);
|
||||||
|
return res.data;
|
||||||
|
},
|
||||||
|
async getMonitoringInstances(serviceId: string): Promise<Nullable<AxiosResponse>> {
|
||||||
|
this.instancesLoading = true;
|
||||||
|
if (!serviceId) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const res: AxiosResponse = await graphql.query("getMonitoringInstances").params({
|
||||||
|
serviceId,
|
||||||
|
target: this.selectedStrategy.type,
|
||||||
|
});
|
||||||
|
this.instancesLoading = false;
|
||||||
|
if (res.data.errors) {
|
||||||
|
return res.data;
|
||||||
|
}
|
||||||
|
this.instances = (res.data.data.instances || [])
|
||||||
|
.map((d: MonitorInstance) => {
|
||||||
|
const processes = (d.processes || [])
|
||||||
|
.sort((c: MonitorProcess, d: MonitorProcess) => d.lastTriggerTimestamp - c.lastTriggerTimestamp)
|
||||||
|
.map((p: MonitorProcess) => {
|
||||||
|
return {
|
||||||
|
...p,
|
||||||
|
lastTriggerTime: d.lastTriggerTimestamp ? dateFormat(d.lastTriggerTimestamp) : "",
|
||||||
|
labels: p.labels.join("; "),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
...d,
|
||||||
|
processes,
|
||||||
|
lastTriggerTime: d.lastTriggerTimestamp ? dateFormat(d.lastTriggerTimestamp) : "",
|
||||||
|
};
|
||||||
|
})
|
||||||
|
.sort((a: MonitorInstance, b: MonitorInstance) => b.lastTriggerTimestamp - a.lastTriggerTimestamp);
|
||||||
|
this.instance = this.instances[0] || null;
|
||||||
|
return res.data;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export function useContinousProfilingStore(): Recordable {
|
||||||
|
return continousProfilingStore(store);
|
||||||
|
}
|
@@ -25,7 +25,7 @@ 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 { useI18n } from "vue-i18n";
|
||||||
import { EntityType } from "@/views/dashboard/data";
|
import { EntityType, MetricModes } from "@/views/dashboard/data";
|
||||||
interface DashboardState {
|
interface DashboardState {
|
||||||
showConfig: boolean;
|
showConfig: boolean;
|
||||||
layout: LayoutConfig[];
|
layout: LayoutConfig[];
|
||||||
@@ -33,7 +33,7 @@ interface DashboardState {
|
|||||||
entity: string;
|
entity: string;
|
||||||
layerId: string;
|
layerId: string;
|
||||||
activedGridItem: string;
|
activedGridItem: string;
|
||||||
selectorStore: any;
|
selectorStore: Recordable;
|
||||||
showTopology: boolean;
|
showTopology: boolean;
|
||||||
currentTabItems: LayoutConfig[];
|
currentTabItems: LayoutConfig[];
|
||||||
dashboards: DashboardItem[];
|
dashboards: DashboardItem[];
|
||||||
@@ -79,7 +79,7 @@ export const dashboardStore = defineStore({
|
|||||||
this.currentDashboard = item;
|
this.currentDashboard = item;
|
||||||
},
|
},
|
||||||
addControl(type: string) {
|
addControl(type: string) {
|
||||||
const arr = this.layout.map((d: any) => 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) {
|
||||||
index = "0";
|
index = "0";
|
||||||
@@ -92,6 +92,10 @@ export const dashboardStore = defineStore({
|
|||||||
metricTypes: [""],
|
metricTypes: [""],
|
||||||
metrics: [""],
|
metrics: [""],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (type === "Widget") {
|
||||||
|
newItem.metricMode = MetricModes.Expression;
|
||||||
|
}
|
||||||
if (type === "Tab") {
|
if (type === "Tab") {
|
||||||
newItem.h = 36;
|
newItem.h = 36;
|
||||||
newItem.activedTabIndex = 0;
|
newItem.activedTabIndex = 0;
|
||||||
@@ -153,7 +157,7 @@ export const dashboardStore = defineStore({
|
|||||||
}
|
}
|
||||||
const tabIndex = this.layout[idx].activedTabIndex || 0;
|
const tabIndex = this.layout[idx].activedTabIndex || 0;
|
||||||
const { children } = (this.layout[idx].children || [])[tabIndex];
|
const { children } = (this.layout[idx].children || [])[tabIndex];
|
||||||
const arr = children.map((d: any) => Number(d.i));
|
const arr = children.map((d: Recordable) => Number(d.i));
|
||||||
let index = String(Math.max(...arr) + 1);
|
let index = String(Math.max(...arr) + 1);
|
||||||
if (!children.length) {
|
if (!children.length) {
|
||||||
index = "0";
|
index = "0";
|
||||||
@@ -167,6 +171,9 @@ export const dashboardStore = defineStore({
|
|||||||
metricTypes: [""],
|
metricTypes: [""],
|
||||||
metrics: [""],
|
metrics: [""],
|
||||||
};
|
};
|
||||||
|
if (type === "Widget") {
|
||||||
|
newItem.metricMode = MetricModes.Expression;
|
||||||
|
}
|
||||||
if (type === "Topology") {
|
if (type === "Topology") {
|
||||||
newItem.h = 32;
|
newItem.h = 32;
|
||||||
newItem.graph = {
|
newItem.graph = {
|
||||||
@@ -309,6 +316,11 @@ export const dashboardStore = defineStore({
|
|||||||
|
|
||||||
return res.data;
|
return res.data;
|
||||||
},
|
},
|
||||||
|
async getTypeOfMQE(expression: string) {
|
||||||
|
const res: AxiosResponse = await graphql.query("getTypeOfMQE").params({ expression });
|
||||||
|
|
||||||
|
return res.data;
|
||||||
|
},
|
||||||
async fetchMetricList(regex: string) {
|
async fetchMetricList(regex: string) {
|
||||||
const res: AxiosResponse = await graphql.query("queryMetrics").params({ regex });
|
const res: AxiosResponse = await graphql.query("queryMetrics").params({ regex });
|
||||||
|
|
||||||
@@ -398,7 +410,7 @@ export const dashboardStore = defineStore({
|
|||||||
children: this.layout,
|
children: this.layout,
|
||||||
...this.currentDashboard,
|
...this.currentDashboard,
|
||||||
};
|
};
|
||||||
let res: any;
|
let res: Recordable;
|
||||||
let json;
|
let json;
|
||||||
|
|
||||||
if (this.currentDashboard.id) {
|
if (this.currentDashboard.id) {
|
||||||
@@ -462,13 +474,13 @@ export const dashboardStore = defineStore({
|
|||||||
ElMessage.error(json.message);
|
ElMessage.error(json.message);
|
||||||
return res.data;
|
return res.data;
|
||||||
}
|
}
|
||||||
this.dashboards = this.dashboards.filter((d: any) => d.id !== this.currentDashboard?.id);
|
this.dashboards = this.dashboards.filter((d: Recordable) => d.id !== this.currentDashboard?.id);
|
||||||
const key = [this.currentDashboard?.layer, this.currentDashboard?.entity, this.currentDashboard?.name].join("_");
|
const key = [this.currentDashboard?.layer, this.currentDashboard?.entity, this.currentDashboard?.name].join("_");
|
||||||
sessionStorage.removeItem(key);
|
sessionStorage.removeItem(key);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
export function useDashboardStore(): any {
|
export function useDashboardStore(): Recordable {
|
||||||
return dashboardStore(store);
|
return dashboardStore(store);
|
||||||
}
|
}
|
||||||
|
@@ -27,7 +27,7 @@ interface DemandLogState {
|
|||||||
containers: Instance[];
|
containers: Instance[];
|
||||||
instances: Instance[];
|
instances: Instance[];
|
||||||
conditions: Conditions;
|
conditions: Conditions;
|
||||||
selectorStore: any;
|
selectorStore: Recordable;
|
||||||
logs: Log[];
|
logs: Log[];
|
||||||
loadLogs: boolean;
|
loadLogs: boolean;
|
||||||
message: string;
|
message: string;
|
||||||
@@ -111,6 +111,6 @@ export const demandLogStore = defineStore({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
export function useDemandLogStore(): any {
|
export function useDemandLogStore(): Recordable {
|
||||||
return demandLogStore(store);
|
return demandLogStore(store);
|
||||||
}
|
}
|
||||||
|
@@ -20,6 +20,7 @@ import type { EBPFTaskCreationRequest, EBPFProfilingSchedule, EBPFTaskList, Anal
|
|||||||
import { store } from "@/store";
|
import { store } from "@/store";
|
||||||
import graphql from "@/graphql";
|
import graphql from "@/graphql";
|
||||||
import type { AxiosResponse } from "axios";
|
import type { AxiosResponse } from "axios";
|
||||||
|
import { EBPFProfilingTriggerType } from "../data";
|
||||||
interface EbpfState {
|
interface EbpfState {
|
||||||
taskList: Array<Recordable<EBPFTaskList>>;
|
taskList: Array<Recordable<EBPFTaskList>>;
|
||||||
eBPFSchedules: EBPFProfilingSchedule[];
|
eBPFSchedules: EBPFProfilingSchedule[];
|
||||||
@@ -27,7 +28,7 @@ interface EbpfState {
|
|||||||
analyzeTrees: AnalyzationTrees[];
|
analyzeTrees: AnalyzationTrees[];
|
||||||
labels: Option[];
|
labels: Option[];
|
||||||
couldProfiling: boolean;
|
couldProfiling: boolean;
|
||||||
tip: string;
|
ebpfTips: string;
|
||||||
selectedTask: Recordable<EBPFTaskList>;
|
selectedTask: Recordable<EBPFTaskList>;
|
||||||
aggregateType: string;
|
aggregateType: string;
|
||||||
}
|
}
|
||||||
@@ -41,7 +42,7 @@ export const ebpfStore = defineStore({
|
|||||||
analyzeTrees: [],
|
analyzeTrees: [],
|
||||||
labels: [{ value: "", label: "" }],
|
labels: [{ value: "", label: "" }],
|
||||||
couldProfiling: false,
|
couldProfiling: false,
|
||||||
tip: "",
|
ebpfTips: "",
|
||||||
selectedTask: {},
|
selectedTask: {},
|
||||||
aggregateType: "COUNT",
|
aggregateType: "COUNT",
|
||||||
}),
|
}),
|
||||||
@@ -77,6 +78,7 @@ export const ebpfStore = defineStore({
|
|||||||
this.getTaskList({
|
this.getTaskList({
|
||||||
serviceId: param.serviceId,
|
serviceId: param.serviceId,
|
||||||
targets: ["ON_CPU", "OFF_CPU"],
|
targets: ["ON_CPU", "OFF_CPU"],
|
||||||
|
triggerType: EBPFProfilingTriggerType.FIXED_TIME,
|
||||||
});
|
});
|
||||||
return res.data;
|
return res.data;
|
||||||
},
|
},
|
||||||
@@ -86,7 +88,7 @@ export const ebpfStore = defineStore({
|
|||||||
}
|
}
|
||||||
const res: AxiosResponse = await graphql.query("getEBPFTasks").params(params);
|
const res: AxiosResponse = await graphql.query("getEBPFTasks").params(params);
|
||||||
|
|
||||||
this.tip = "";
|
this.ebpfTips = "";
|
||||||
if (res.data.errors) {
|
if (res.data.errors) {
|
||||||
return res.data;
|
return res.data;
|
||||||
}
|
}
|
||||||
@@ -103,13 +105,14 @@ export const ebpfStore = defineStore({
|
|||||||
if (!params.taskId) {
|
if (!params.taskId) {
|
||||||
return new Promise((resolve) => resolve({}));
|
return new Promise((resolve) => resolve({}));
|
||||||
}
|
}
|
||||||
|
|
||||||
const res: AxiosResponse = await graphql.query("getEBPFSchedules").params({ ...params });
|
const res: AxiosResponse = await graphql.query("getEBPFSchedules").params({ ...params });
|
||||||
|
|
||||||
if (res.data.errors) {
|
if (res.data.errors) {
|
||||||
this.eBPFSchedules = [];
|
this.eBPFSchedules = [];
|
||||||
return res.data;
|
return res.data;
|
||||||
}
|
}
|
||||||
this.tip = "";
|
this.ebpfTips = "";
|
||||||
const { eBPFSchedules } = res.data.data;
|
const { eBPFSchedules } = res.data.data;
|
||||||
|
|
||||||
this.eBPFSchedules = eBPFSchedules;
|
this.eBPFSchedules = eBPFSchedules;
|
||||||
@@ -138,7 +141,7 @@ export const ebpfStore = defineStore({
|
|||||||
return res.data;
|
return res.data;
|
||||||
}
|
}
|
||||||
const { analysisEBPFResult } = res.data.data;
|
const { analysisEBPFResult } = res.data.data;
|
||||||
this.tip = analysisEBPFResult.tip;
|
this.ebpfTips = analysisEBPFResult.tip;
|
||||||
if (!analysisEBPFResult) {
|
if (!analysisEBPFResult) {
|
||||||
this.analyzeTrees = [];
|
this.analyzeTrees = [];
|
||||||
return res.data;
|
return res.data;
|
||||||
@@ -153,6 +156,6 @@ export const ebpfStore = defineStore({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
export function useEbpfStore(): any {
|
export function useEbpfStore(): Recordable {
|
||||||
return ebpfStore(store);
|
return ebpfStore(store);
|
||||||
}
|
}
|
||||||
|
@@ -106,6 +106,6 @@ export const eventStore = defineStore({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
export function useEventStore(): any {
|
export function useEventStore(): Recordable {
|
||||||
return eventStore(store);
|
return eventStore(store);
|
||||||
}
|
}
|
||||||
|
@@ -27,10 +27,10 @@ interface LogState {
|
|||||||
services: Service[];
|
services: Service[];
|
||||||
instances: Instance[];
|
instances: Instance[];
|
||||||
endpoints: Endpoint[];
|
endpoints: Endpoint[];
|
||||||
conditions: any;
|
conditions: Recordable;
|
||||||
selectorStore: any;
|
selectorStore: Recordable;
|
||||||
supportQueryLogsByKeywords: boolean;
|
supportQueryLogsByKeywords: boolean;
|
||||||
logs: any[];
|
logs: Recordable[];
|
||||||
loadLogs: boolean;
|
loadLogs: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,7 +50,7 @@ export const logStore = defineStore({
|
|||||||
loadLogs: false,
|
loadLogs: false,
|
||||||
}),
|
}),
|
||||||
actions: {
|
actions: {
|
||||||
setLogCondition(data: any) {
|
setLogCondition(data: Recordable) {
|
||||||
this.conditions = { ...this.conditions, ...data };
|
this.conditions = { ...this.conditions, ...data };
|
||||||
},
|
},
|
||||||
resetState() {
|
resetState() {
|
||||||
@@ -152,6 +152,6 @@ export const logStore = defineStore({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
export function useLogStore(): any {
|
export function useLogStore(): Recordable {
|
||||||
return logStore(store);
|
return logStore(store);
|
||||||
}
|
}
|
||||||
|
@@ -22,6 +22,7 @@ import type { AxiosResponse } from "axios";
|
|||||||
import type { Call } from "@/types/topology";
|
import type { Call } from "@/types/topology";
|
||||||
import type { LayoutConfig } from "@/types/dashboard";
|
import type { LayoutConfig } from "@/types/dashboard";
|
||||||
import { ElMessage } from "element-plus";
|
import { ElMessage } from "element-plus";
|
||||||
|
import type { DurationTime } from "@/types/app";
|
||||||
|
|
||||||
interface NetworkProfilingState {
|
interface NetworkProfilingState {
|
||||||
networkTasks: Array<Recordable<EBPFTaskList>>;
|
networkTasks: Array<Recordable<EBPFTaskList>>;
|
||||||
@@ -64,6 +65,12 @@ export const networkProfilingStore = defineStore({
|
|||||||
setLink(link: Call) {
|
setLink(link: Call) {
|
||||||
this.call = link;
|
this.call = link;
|
||||||
},
|
},
|
||||||
|
seNodes(nodes: Node[]) {
|
||||||
|
this.nodes = nodes;
|
||||||
|
},
|
||||||
|
setLinks(links: Call[]) {
|
||||||
|
this.calls = links;
|
||||||
|
},
|
||||||
setMetricsLayout(layout: LayoutConfig[]) {
|
setMetricsLayout(layout: LayoutConfig[]) {
|
||||||
this.metricsLayout = layout;
|
this.metricsLayout = layout;
|
||||||
},
|
},
|
||||||
@@ -74,7 +81,7 @@ export const networkProfilingStore = defineStore({
|
|||||||
this.activeMetricIndex = index;
|
this.activeMetricIndex = index;
|
||||||
},
|
},
|
||||||
setTopology(data: { nodes: ProcessNode[]; calls: Call[] }) {
|
setTopology(data: { nodes: ProcessNode[]; calls: Call[] }) {
|
||||||
const obj = {} as any;
|
const obj = {} as Recordable;
|
||||||
let calls = (data.calls || []).reduce((prev: Call[], next: Call) => {
|
let calls = (data.calls || []).reduce((prev: Call[], next: Call) => {
|
||||||
if (!obj[next.id]) {
|
if (!obj[next.id]) {
|
||||||
obj[next.id] = true;
|
obj[next.id] = true;
|
||||||
@@ -92,8 +99,8 @@ export const networkProfilingStore = defineStore({
|
|||||||
}
|
}
|
||||||
return prev;
|
return prev;
|
||||||
}, []);
|
}, []);
|
||||||
const param = {} as any;
|
const param = {} as Recordable;
|
||||||
calls = data.calls.reduce((prev: (Call | any)[], next: Call | any) => {
|
calls = data.calls.reduce((prev: (Call & Recordable)[], next: Call & Recordable) => {
|
||||||
if (param[next.targetId + next.sourceId]) {
|
if (param[next.targetId + next.sourceId]) {
|
||||||
next.lowerArc = true;
|
next.lowerArc = true;
|
||||||
}
|
}
|
||||||
@@ -165,7 +172,7 @@ export const networkProfilingStore = defineStore({
|
|||||||
}
|
}
|
||||||
return res.data;
|
return res.data;
|
||||||
},
|
},
|
||||||
async getProcessTopology(params: { duration: any; serviceInstanceId: string }) {
|
async getProcessTopology(params: { duration: DurationTime; serviceInstanceId: string }) {
|
||||||
this.loadNodes = true;
|
this.loadNodes = true;
|
||||||
const res: AxiosResponse = await graphql.query("getProcessTopology").params(params);
|
const res: AxiosResponse = await graphql.query("getProcessTopology").params(params);
|
||||||
this.loadNodes = false;
|
this.loadNodes = false;
|
||||||
@@ -182,6 +189,6 @@ export const networkProfilingStore = defineStore({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
export function useNetworkProfilingStore(): any {
|
export function useNetworkProfilingStore(): Recordable {
|
||||||
return networkProfilingStore(store);
|
return networkProfilingStore(store);
|
||||||
}
|
}
|
||||||
|
@@ -34,6 +34,7 @@ interface ProfileState {
|
|||||||
taskEndpoints: Endpoint[];
|
taskEndpoints: Endpoint[];
|
||||||
condition: { serviceId: string; endpointName: string };
|
condition: { serviceId: string; endpointName: string };
|
||||||
taskList: TaskListItem[];
|
taskList: TaskListItem[];
|
||||||
|
currentTask: Recordable<TaskListItem>;
|
||||||
segmentList: Trace[];
|
segmentList: Trace[];
|
||||||
currentSegment: Recordable<Trace>;
|
currentSegment: Recordable<Trace>;
|
||||||
segmentSpans: Array<Recordable<SegmentSpan>>;
|
segmentSpans: Array<Recordable<SegmentSpan>>;
|
||||||
@@ -51,6 +52,7 @@ export const profileStore = defineStore({
|
|||||||
condition: { serviceId: "", endpointName: "" },
|
condition: { serviceId: "", endpointName: "" },
|
||||||
taskList: [],
|
taskList: [],
|
||||||
segmentList: [],
|
segmentList: [],
|
||||||
|
currentTask: {},
|
||||||
currentSegment: {},
|
currentSegment: {},
|
||||||
segmentSpans: [],
|
segmentSpans: [],
|
||||||
currentSpan: {},
|
currentSpan: {},
|
||||||
@@ -65,11 +67,27 @@ export const profileStore = defineStore({
|
|||||||
...data,
|
...data,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
setCurrentTask(task: TaskListItem) {
|
||||||
|
this.currentTask = task || {};
|
||||||
|
this.analyzeTrees = [];
|
||||||
|
},
|
||||||
|
setSegmentSpans(spans: Recordable<SegmentSpan>[]) {
|
||||||
|
this.currentSpan = spans[0] || {};
|
||||||
|
this.segmentSpans = spans;
|
||||||
|
},
|
||||||
setCurrentSpan(span: Recordable<SegmentSpan>) {
|
setCurrentSpan(span: Recordable<SegmentSpan>) {
|
||||||
this.currentSpan = span;
|
this.currentSpan = span;
|
||||||
|
this.analyzeTrees = [];
|
||||||
},
|
},
|
||||||
setCurrentSegment(s: Recordable<Trace>) {
|
setCurrentSegment(segment: Trace) {
|
||||||
this.currentSegment = s;
|
this.currentSegment = segment;
|
||||||
|
this.segmentSpans = segment.spans || [];
|
||||||
|
if (segment.spans) {
|
||||||
|
this.currentSpan = segment.spans[0] || {};
|
||||||
|
} else {
|
||||||
|
this.currentSpan = {};
|
||||||
|
}
|
||||||
|
this.analyzeTrees = [];
|
||||||
},
|
},
|
||||||
setHighlightTop() {
|
setHighlightTop() {
|
||||||
this.highlightTop = !this.highlightTop;
|
this.highlightTop = !this.highlightTop;
|
||||||
@@ -104,8 +122,9 @@ export const profileStore = defineStore({
|
|||||||
if (res.data.errors) {
|
if (res.data.errors) {
|
||||||
return res.data;
|
return res.data;
|
||||||
}
|
}
|
||||||
const list = res.data.data.taskList;
|
const list = res.data.data.taskList || [];
|
||||||
this.taskList = list;
|
this.taskList = list;
|
||||||
|
this.currentTask = list[0] || {};
|
||||||
if (!list.length) {
|
if (!list.length) {
|
||||||
this.segmentList = [];
|
this.segmentList = [];
|
||||||
this.segmentSpans = [];
|
this.segmentSpans = [];
|
||||||
@@ -128,7 +147,7 @@ export const profileStore = defineStore({
|
|||||||
}
|
}
|
||||||
const { segmentList } = res.data.data;
|
const { segmentList } = res.data.data;
|
||||||
|
|
||||||
this.segmentList = segmentList;
|
this.segmentList = segmentList || [];
|
||||||
if (!segmentList.length) {
|
if (!segmentList.length) {
|
||||||
this.segmentSpans = [];
|
this.segmentSpans = [];
|
||||||
this.analyzeTrees = [];
|
this.analyzeTrees = [];
|
||||||
@@ -137,7 +156,7 @@ export const profileStore = defineStore({
|
|||||||
}
|
}
|
||||||
if (segmentList[0]) {
|
if (segmentList[0]) {
|
||||||
this.currentSegment = segmentList[0];
|
this.currentSegment = segmentList[0];
|
||||||
this.getSegmentSpans({ segmentId: segmentList[0].segmentId });
|
this.getSegmentSpans(segmentList[0].segmentId);
|
||||||
} else {
|
} else {
|
||||||
this.currentSegment = {};
|
this.currentSegment = {};
|
||||||
}
|
}
|
||||||
@@ -162,7 +181,7 @@ export const profileStore = defineStore({
|
|||||||
return {
|
return {
|
||||||
...d,
|
...d,
|
||||||
segmentId: this.currentSegment?.segmentId,
|
segmentId: this.currentSegment?.segmentId,
|
||||||
traceId: (this.currentSegment.traceIds as any)[0],
|
traceId: (this.currentSegment.traceIds as string[])[0],
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
if (!(segment.spans && segment.spans.length)) {
|
if (!(segment.spans && segment.spans.length)) {
|
||||||
@@ -173,14 +192,11 @@ export const profileStore = defineStore({
|
|||||||
this.currentSpan = segment.spans[index];
|
this.currentSpan = segment.spans[index];
|
||||||
return res.data;
|
return res.data;
|
||||||
},
|
},
|
||||||
async getProfileAnalyze(params: { segmentId: string; timeRanges: Array<{ start: number; end: number }> }) {
|
async getProfileAnalyze(params: Array<{ segmentId: string; timeRange: { start: number; end: number } }>) {
|
||||||
if (!params.segmentId) {
|
if (!params.length) {
|
||||||
return new Promise((resolve) => resolve({}));
|
return new Promise((resolve) => resolve({}));
|
||||||
}
|
}
|
||||||
if (!params.timeRanges.length) {
|
const res: AxiosResponse = await graphql.query("getProfileAnalyze").params({ queries: params });
|
||||||
return new Promise((resolve) => resolve({}));
|
|
||||||
}
|
|
||||||
const res: AxiosResponse = await graphql.query("getProfileAnalyze").params(params);
|
|
||||||
|
|
||||||
if (res.data.errors) {
|
if (res.data.errors) {
|
||||||
this.analyzeTrees = [];
|
this.analyzeTrees = [];
|
||||||
@@ -220,6 +236,6 @@ export const profileStore = defineStore({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
export function useProfileStore(): any {
|
export function useProfileStore(): Recordable {
|
||||||
return profileStore(store);
|
return profileStore(store);
|
||||||
}
|
}
|
||||||
|
@@ -233,6 +233,6 @@ export const selectorStore = defineStore({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
export function useSelectorStore(): any {
|
export function useSelectorStore(): Recordable {
|
||||||
return selectorStore(store);
|
return selectorStore(store);
|
||||||
}
|
}
|
||||||
|
134
src/store/modules/task-timeline.ts
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
/**
|
||||||
|
* 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 { defineStore } from "pinia";
|
||||||
|
import { ElMessage } from "element-plus";
|
||||||
|
import { store } from "@/store";
|
||||||
|
import graphql from "@/graphql";
|
||||||
|
import type { AxiosResponse } from "axios";
|
||||||
|
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||||
|
import type { EBPFTaskList } from "@/types/ebpf";
|
||||||
|
import { useNetworkProfilingStore } from "@/store/modules/network-profiling";
|
||||||
|
import { useSelectorStore } from "@/store/modules/selectors";
|
||||||
|
import { useEbpfStore } from "@/store/modules/ebpf";
|
||||||
|
import dateFormatStep from "@/utils/dateFormat";
|
||||||
|
import getLocalTime from "@/utils/localtime";
|
||||||
|
import { TargetTypes } from "@/views/dashboard/related/continuous-profiling/data";
|
||||||
|
interface taskTimelineState {
|
||||||
|
loading: boolean;
|
||||||
|
taskList: EBPFTaskList[];
|
||||||
|
selectedTask: Recordable<EBPFTaskList>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const taskTimelineStore = defineStore({
|
||||||
|
id: "taskTimeline",
|
||||||
|
state: (): taskTimelineState => ({
|
||||||
|
loading: false,
|
||||||
|
taskList: [],
|
||||||
|
selectedTask: {},
|
||||||
|
}),
|
||||||
|
actions: {
|
||||||
|
setSelectedTask(task: Recordable<EBPFTaskList>) {
|
||||||
|
this.selectedTask = task || {};
|
||||||
|
},
|
||||||
|
setTaskList(list: EBPFTaskList[]) {
|
||||||
|
this.taskList = list;
|
||||||
|
},
|
||||||
|
async getContinousTaskList(params: {
|
||||||
|
serviceId: string;
|
||||||
|
serviceInstanceId: string;
|
||||||
|
targets: string[];
|
||||||
|
triggerType: string;
|
||||||
|
}) {
|
||||||
|
if (!params.serviceId) {
|
||||||
|
return new Promise((resolve) => resolve({}));
|
||||||
|
}
|
||||||
|
this.loading = true;
|
||||||
|
const res: AxiosResponse = await graphql.query("getEBPFTasks").params(params);
|
||||||
|
|
||||||
|
this.loading = false;
|
||||||
|
this.errorTip = "";
|
||||||
|
if (res.data.errors) {
|
||||||
|
return res.data;
|
||||||
|
}
|
||||||
|
const selectorStore = useSelectorStore();
|
||||||
|
this.taskList = (res.data.data.queryEBPFTasks || []).filter(
|
||||||
|
(d: EBPFTaskList) => selectorStore.currentProcess && d.processId === selectorStore.currentProcess.id,
|
||||||
|
);
|
||||||
|
// this.selectedTask = this.taskList[0] || {};
|
||||||
|
// await this.getGraphData();
|
||||||
|
return res.data;
|
||||||
|
},
|
||||||
|
async getGraphData() {
|
||||||
|
let res: any = {};
|
||||||
|
|
||||||
|
if (this.selectedTask.targetType === TargetTypes[2].value) {
|
||||||
|
res = await this.getTopology();
|
||||||
|
} else {
|
||||||
|
const ebpfStore = useEbpfStore();
|
||||||
|
res = await ebpfStore.getEBPFSchedules({
|
||||||
|
taskId: this.selectedTask.taskId,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res.errors) {
|
||||||
|
ElMessage.error(res.errors);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async getTopology() {
|
||||||
|
const networkProfilingStore = useNetworkProfilingStore();
|
||||||
|
const appStore = useAppStoreWithOut();
|
||||||
|
const selectorStore = useSelectorStore();
|
||||||
|
networkProfilingStore.setSelectedNetworkTask(this.selectedTask);
|
||||||
|
const { taskStartTime, fixedTriggerDuration } = this.selectedTask;
|
||||||
|
const startTime =
|
||||||
|
fixedTriggerDuration > 1800 ? taskStartTime + fixedTriggerDuration * 1000 - 30 * 60 * 1000 : taskStartTime;
|
||||||
|
let endTime = taskStartTime + fixedTriggerDuration * 1000;
|
||||||
|
if (taskStartTime + fixedTriggerDuration * 1000 > new Date().getTime()) {
|
||||||
|
endTime = new Date().getTime();
|
||||||
|
}
|
||||||
|
const resp = await networkProfilingStore.getProcessTopology({
|
||||||
|
serviceInstanceId: (selectorStore.currentPod || {}).id || "",
|
||||||
|
duration: {
|
||||||
|
start: dateFormatStep(getLocalTime(appStore.utc, new Date(startTime)), appStore.duration.step, true),
|
||||||
|
end: dateFormatStep(getLocalTime(appStore.utc, new Date(endTime)), appStore.duration.step, true),
|
||||||
|
step: appStore.duration.step,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
if (resp.errors) {
|
||||||
|
ElMessage.error(resp.errors);
|
||||||
|
}
|
||||||
|
return resp;
|
||||||
|
},
|
||||||
|
async preAnalyzeTask() {
|
||||||
|
if (this.selectedStrategy.type === "NETWORK") {
|
||||||
|
const networkProfilingStore = useNetworkProfilingStore();
|
||||||
|
await networkProfilingStore.setSelectedNetworkTask(this.selectedTask);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const res = await this.getEBPFSchedules({
|
||||||
|
taskId: this.selectedTask.taskId,
|
||||||
|
});
|
||||||
|
if (res.errors) {
|
||||||
|
ElMessage.error(res.errors);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export function useTaskTimelineStore(): Recordable {
|
||||||
|
return taskTimelineStore(store);
|
||||||
|
}
|
@@ -73,7 +73,7 @@ export const topologyStore = defineStore({
|
|||||||
this.nodes = data.nodes;
|
this.nodes = data.nodes;
|
||||||
},
|
},
|
||||||
setTopology(data: { nodes: Node[]; calls: Call[] }) {
|
setTopology(data: { nodes: Node[]; calls: Call[] }) {
|
||||||
const obj = {} as any;
|
const obj = {} as Recordable;
|
||||||
const services = useSelectorStore().services;
|
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]) {
|
||||||
@@ -302,8 +302,8 @@ export const topologyStore = defineStore({
|
|||||||
return res.data;
|
return res.data;
|
||||||
}
|
}
|
||||||
const topo = res.data.data;
|
const topo = res.data.data;
|
||||||
const calls = [] as any;
|
const calls = [] as Call[];
|
||||||
const nodes = [] as any;
|
const nodes = [] as Node[];
|
||||||
for (const key of Object.keys(topo)) {
|
for (const key of Object.keys(topo)) {
|
||||||
calls.push(...topo[key].calls);
|
calls.push(...topo[key].calls);
|
||||||
nodes.push(...topo[key].nodes);
|
nodes.push(...topo[key].nodes);
|
||||||
@@ -377,7 +377,7 @@ export const topologyStore = defineStore({
|
|||||||
}
|
}
|
||||||
const data = res.data.data;
|
const data = res.data.data;
|
||||||
const metrics = Object.keys(data);
|
const metrics = Object.keys(data);
|
||||||
this.nodes = this.nodes.map((d: Node | any) => {
|
this.nodes = this.nodes.map((d: Node & Recordable) => {
|
||||||
for (const m of metrics) {
|
for (const m of metrics) {
|
||||||
for (const val of data[m].values) {
|
for (const val of data[m].values) {
|
||||||
if (d.id === val.id) {
|
if (d.id === val.id) {
|
||||||
@@ -410,6 +410,6 @@ export const topologyStore = defineStore({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
export function useTopologyStore(): any {
|
export function useTopologyStore(): Recordable {
|
||||||
return topologyStore(store);
|
return topologyStore(store);
|
||||||
}
|
}
|
||||||
|
@@ -31,9 +31,9 @@ interface TraceState {
|
|||||||
traceList: Trace[];
|
traceList: Trace[];
|
||||||
traceSpans: Span[];
|
traceSpans: Span[];
|
||||||
currentTrace: Recordable<Trace>;
|
currentTrace: Recordable<Trace>;
|
||||||
conditions: any;
|
conditions: Recordable;
|
||||||
traceSpanLogs: any[];
|
traceSpanLogs: Recordable[];
|
||||||
selectorStore: any;
|
selectorStore: Recordable;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const traceStore = defineStore({
|
export const traceStore = defineStore({
|
||||||
@@ -55,7 +55,7 @@ export const traceStore = defineStore({
|
|||||||
selectorStore: useSelectorStore(),
|
selectorStore: useSelectorStore(),
|
||||||
}),
|
}),
|
||||||
actions: {
|
actions: {
|
||||||
setTraceCondition(data: any) {
|
setTraceCondition(data: Recordable) {
|
||||||
this.conditions = { ...this.conditions, ...data };
|
this.conditions = { ...this.conditions, ...data };
|
||||||
},
|
},
|
||||||
setCurrentTrace(trace: Recordable<Trace>) {
|
setCurrentTrace(trace: Recordable<Trace>) {
|
||||||
@@ -171,7 +171,7 @@ export const traceStore = defineStore({
|
|||||||
this.setTraceSpans(data || []);
|
this.setTraceSpans(data || []);
|
||||||
return res.data;
|
return res.data;
|
||||||
},
|
},
|
||||||
async getSpanLogs(params: any) {
|
async getSpanLogs(params: Recordable) {
|
||||||
const res: AxiosResponse = await graphql.query("queryServiceLogs").params(params);
|
const res: AxiosResponse = await graphql.query("queryServiceLogs").params(params);
|
||||||
if (res.data.errors) {
|
if (res.data.errors) {
|
||||||
this.traceSpanLogs = [];
|
this.traceSpanLogs = [];
|
||||||
@@ -197,6 +197,6 @@ export const traceStore = defineStore({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
export function useTraceStore(): any {
|
export function useTraceStore(): Recordable {
|
||||||
return traceStore(store);
|
return traceStore(store);
|
||||||
}
|
}
|
||||||
|
@@ -215,3 +215,31 @@
|
|||||||
box-shadow: inset 0 0 6px #888;
|
box-shadow: inset 0 0 6px #888;
|
||||||
background-color: #999;
|
background-color: #999;
|
||||||
}
|
}
|
||||||
|
.d3-tip {
|
||||||
|
line-height: 1;
|
||||||
|
padding: 8px;
|
||||||
|
color: #eee;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
.d3-tip {
|
||||||
|
background: #252a2f;
|
||||||
|
}
|
||||||
|
|
||||||
|
.d3-tip:after {
|
||||||
|
box-sizing: border-box;
|
||||||
|
display: block;
|
||||||
|
font-size: 10px;
|
||||||
|
width: 100%;
|
||||||
|
line-height: 0.8;
|
||||||
|
color: #252a2f;
|
||||||
|
content: "\25BC";
|
||||||
|
position: absolute;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.d3-tip.n:after {
|
||||||
|
margin: -2px 0 0 0;
|
||||||
|
top: 100%;
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
@@ -135,7 +135,7 @@ pre {
|
|||||||
.el-sub-menu .el-menu-item {
|
.el-sub-menu .el-menu-item {
|
||||||
height: 40px;
|
height: 40px;
|
||||||
line-height: 40px;
|
line-height: 40px;
|
||||||
padding-left: 56px !important;
|
padding: 0 0 0 56px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.el-sub-menu__title {
|
.el-sub-menu__title {
|
||||||
@@ -212,3 +212,6 @@ div.vis-tooltip {
|
|||||||
div:has(> a.menu-title) {
|
div:has(> a.menu-title) {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
.el-input-number .el-input__inner {
|
||||||
|
text-align: left !important;
|
||||||
|
}
|
||||||
|
3
src/types/app.d.ts
vendored
@@ -42,8 +42,7 @@ export type EventParams = {
|
|||||||
dataIndex: number;
|
dataIndex: number;
|
||||||
data: unknown;
|
data: unknown;
|
||||||
dataType: string;
|
dataType: string;
|
||||||
value: number | Array;
|
value: number | any[];
|
||||||
color: string;
|
color: string;
|
||||||
event: any;
|
event: any;
|
||||||
dataIndex: number;
|
|
||||||
};
|
};
|
||||||
|
45
src/types/continous-profiling.d.ts
vendored
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
/**
|
||||||
|
* 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 interface StrategyItem {
|
||||||
|
type: string;
|
||||||
|
checkItems: CheckItems[];
|
||||||
|
}
|
||||||
|
export type CheckItems = {
|
||||||
|
type: string;
|
||||||
|
threshold: string;
|
||||||
|
period: number;
|
||||||
|
count: number;
|
||||||
|
uriList?: string[];
|
||||||
|
uriRegex?: string;
|
||||||
|
};
|
||||||
|
export interface MonitorInstance {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
attributes: { name: string; value: string }[];
|
||||||
|
triggeredCount: number;
|
||||||
|
lastTriggerTimestamp: number;
|
||||||
|
processes: MonitorProcess[];
|
||||||
|
}
|
||||||
|
interface MonitorProcess {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
detectType: string;
|
||||||
|
labels: string[];
|
||||||
|
lastTriggerTimestamp: number;
|
||||||
|
triggeredCount: number;
|
||||||
|
}
|
14
src/types/dashboard.d.ts
vendored
@@ -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 { DurationTime } from "./app";
|
||||||
export type DashboardItem = {
|
export type DashboardItem = {
|
||||||
id?: string;
|
id?: string;
|
||||||
entity: string;
|
entity: string;
|
||||||
@@ -28,11 +28,14 @@ export interface LayoutConfig {
|
|||||||
w: number;
|
w: number;
|
||||||
h: number;
|
h: number;
|
||||||
i: string;
|
i: string;
|
||||||
|
type: string;
|
||||||
|
metricMode?: string;
|
||||||
widget?: WidgetConfig;
|
widget?: WidgetConfig;
|
||||||
graph?: GraphConfig;
|
graph?: GraphConfig;
|
||||||
metrics?: string[];
|
metrics?: string[];
|
||||||
type: string;
|
expressions?: string[];
|
||||||
metricTypes?: string[];
|
metricTypes?: string[];
|
||||||
|
typesOfMQE?: string[];
|
||||||
children?: { name: string; children: LayoutConfig[] }[];
|
children?: { name: string; children: LayoutConfig[] }[];
|
||||||
activedTabIndex?: number;
|
activedTabIndex?: number;
|
||||||
metricConfig?: MetricConfigOpt[];
|
metricConfig?: MetricConfigOpt[];
|
||||||
@@ -41,6 +44,8 @@ export interface LayoutConfig {
|
|||||||
eventAssociate?: boolean;
|
eventAssociate?: boolean;
|
||||||
filters?: Filters;
|
filters?: Filters;
|
||||||
relatedTrace?: RelatedTrace;
|
relatedTrace?: RelatedTrace;
|
||||||
|
subExpressions?: string[];
|
||||||
|
subTypesOfMQE?: string[];
|
||||||
}
|
}
|
||||||
export type RelatedTrace = {
|
export type RelatedTrace = {
|
||||||
duration: DurationTime;
|
duration: DurationTime;
|
||||||
@@ -70,10 +75,11 @@ export type MetricConfigOpt = {
|
|||||||
unit?: string;
|
unit?: string;
|
||||||
label?: string;
|
label?: string;
|
||||||
calculation?: string;
|
calculation?: string;
|
||||||
labelsIndex: string;
|
labelsIndex?: string;
|
||||||
sortOrder: string;
|
sortOrder?: string;
|
||||||
topN?: number;
|
topN?: number;
|
||||||
index?: number;
|
index?: number;
|
||||||
|
detailLabel?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export interface WidgetConfig {
|
export interface WidgetConfig {
|
||||||
|
19
src/types/ebpf.d.ts
vendored
@@ -28,12 +28,31 @@ export interface EBPFTaskList {
|
|||||||
taskId: string;
|
taskId: string;
|
||||||
serviceName: string;
|
serviceName: string;
|
||||||
serviceId: string;
|
serviceId: string;
|
||||||
|
serviceInstanceId: string;
|
||||||
|
serviceInstanceName: string;
|
||||||
|
processId: string;
|
||||||
|
processName: string;
|
||||||
processLabels: string[];
|
processLabels: string[];
|
||||||
taskStartTime: number;
|
taskStartTime: number;
|
||||||
fixedTriggerDuration: number;
|
fixedTriggerDuration: number;
|
||||||
targetType: string;
|
targetType: string;
|
||||||
createTime: number;
|
createTime: number;
|
||||||
triggerType: string;
|
triggerType: string;
|
||||||
|
continuousProfilingCauses: ProfilingCause[];
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ProfilingCause {
|
||||||
|
type: string;
|
||||||
|
singleValue: {
|
||||||
|
threshold: number;
|
||||||
|
current: number;
|
||||||
|
};
|
||||||
|
uri: {
|
||||||
|
uriRegex: string;
|
||||||
|
uriPath: string;
|
||||||
|
threshold: number;
|
||||||
|
current: number;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface EBPFProfilingSchedule {
|
export interface EBPFProfilingSchedule {
|
||||||
|
7
src/types/global.d.ts
vendored
@@ -49,7 +49,9 @@ declare global {
|
|||||||
|
|
||||||
declare type Nullable<T> = T | null;
|
declare type Nullable<T> = T | null;
|
||||||
declare type NonNullable<T> = T extends null | undefined ? never : T;
|
declare type NonNullable<T> = T extends null | undefined ? never : T;
|
||||||
|
// String type object
|
||||||
declare type Recordable<T = any> = Record<string, T>;
|
declare type Recordable<T = any> = Record<string, T>;
|
||||||
|
// Object of read-only string type
|
||||||
declare type ReadonlyRecordable<T = any> = {
|
declare type ReadonlyRecordable<T = any> = {
|
||||||
readonly [key: string]: T;
|
readonly [key: string]: T;
|
||||||
};
|
};
|
||||||
@@ -108,6 +110,11 @@ declare global {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
type AnyNormalFunction = (...arg: any) => any;
|
||||||
|
|
||||||
|
type AnyPromiseFunction = (...arg: any) => PromiseLike<any>;
|
||||||
|
|
||||||
|
declare type AnyFunction = AnyNormalFunction | AnyPromiseFunction;
|
||||||
|
|
||||||
declare module "vue" {
|
declare module "vue" {
|
||||||
export type JSXComponent<Props = any> = { new (): ComponentPublicInstance<Props> } | FunctionalComponent<Props>;
|
export type JSXComponent<Props = any> = { new (): ComponentPublicInstance<Props> } | FunctionalComponent<Props>;
|
||||||
|
17
src/types/mock.d.ts
vendored
Normal 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.
|
||||||
|
*/
|
||||||
|
declare module "mockjs";
|
3
src/types/selector.d.ts
vendored
@@ -21,6 +21,7 @@ export type Service = {
|
|||||||
layers?: string[];
|
layers?: string[];
|
||||||
normal?: boolean;
|
normal?: boolean;
|
||||||
group?: string;
|
group?: string;
|
||||||
|
merge?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type Instance = {
|
export type Instance = {
|
||||||
@@ -30,12 +31,14 @@ export type Instance = {
|
|||||||
instanceUUID?: string;
|
instanceUUID?: string;
|
||||||
attributes?: { name: string; value: string }[];
|
attributes?: { name: string; value: string }[];
|
||||||
id?: string;
|
id?: string;
|
||||||
|
merge?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type Endpoint = {
|
export type Endpoint = {
|
||||||
id?: string;
|
id?: string;
|
||||||
label: string;
|
label: string;
|
||||||
value: string;
|
value: string;
|
||||||
|
merge?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type Service = {
|
export type Service = {
|
||||||
|
8
src/types/topology.d.ts
vendored
@@ -26,6 +26,10 @@ export interface Call {
|
|||||||
lowerArc?: boolean;
|
lowerArc?: boolean;
|
||||||
sourceComponents: string[];
|
sourceComponents: string[];
|
||||||
targetComponents: string[];
|
targetComponents: string[];
|
||||||
|
sourceX?: number;
|
||||||
|
sourceY?: number;
|
||||||
|
targetY?: number;
|
||||||
|
targetX?: number;
|
||||||
}
|
}
|
||||||
export interface Node {
|
export interface Node {
|
||||||
id: string;
|
id: string;
|
||||||
@@ -34,4 +38,8 @@ export interface Node {
|
|||||||
isReal: boolean;
|
isReal: boolean;
|
||||||
layer?: string;
|
layer?: string;
|
||||||
serviceName?: string;
|
serviceName?: string;
|
||||||
|
height?: number;
|
||||||
|
x?: number;
|
||||||
|
y?: number;
|
||||||
|
level?: number;
|
||||||
}
|
}
|
||||||
|
1
src/types/trace.d.ts
vendored
@@ -22,6 +22,7 @@ export interface Trace {
|
|||||||
start: string;
|
start: string;
|
||||||
traceIds: Array<string | any>;
|
traceIds: Array<string | any>;
|
||||||
segmentId: string;
|
segmentId: string;
|
||||||
|
spans: Span[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Span {
|
export interface Span {
|
||||||
|
@@ -35,6 +35,11 @@ limitations under the License. -->
|
|||||||
metrics: config.metrics,
|
metrics: config.metrics,
|
||||||
metricTypes: config.metricTypes,
|
metricTypes: config.metricTypes,
|
||||||
metricConfig: config.metricConfig,
|
metricConfig: config.metricConfig,
|
||||||
|
metricMode: config.metricMode,
|
||||||
|
expressions: config.expressions || [],
|
||||||
|
typesOfMQE: typesOfMQE || [],
|
||||||
|
subExpressions: config.subExpressions || [],
|
||||||
|
subTypesOfMQE: config.subTypesOfMQE || [],
|
||||||
}"
|
}"
|
||||||
:needQuery="true"
|
:needQuery="true"
|
||||||
/>
|
/>
|
||||||
@@ -51,10 +56,12 @@ 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, useGetMetricEntity } from "@/hooks/useMetricsProcessor";
|
import { useQueryProcessor, useSourceProcessor } from "@/hooks/useMetricsProcessor";
|
||||||
|
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",
|
||||||
@@ -73,6 +80,7 @@ limitations under the License. -->
|
|||||||
const dashboardStore = useDashboardStore();
|
const dashboardStore = useDashboardStore();
|
||||||
const title = computed(() => (config.value.widget && config.value.widget.title) || "");
|
const title = computed(() => (config.value.widget && config.value.widget.title) || "");
|
||||||
const tips = computed(() => (config.value.widget && config.value.widget.tips) || "");
|
const tips = computed(() => (config.value.widget && config.value.widget.tips) || "");
|
||||||
|
const typesOfMQE = ref<string[]>([]);
|
||||||
|
|
||||||
init();
|
init();
|
||||||
async function init() {
|
async function init() {
|
||||||
@@ -122,10 +130,21 @@ limitations under the License. -->
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
async function queryMetrics() {
|
async function queryMetrics() {
|
||||||
const metricTypes = config.value.metricTypes || [];
|
const isExpression = config.value.metricMode === MetricModes.Expression;
|
||||||
const metrics = config.value.metrics || [];
|
if (isExpression) {
|
||||||
const catalog = await useGetMetricEntity(metrics[0], metricTypes[0]);
|
loading.value = true;
|
||||||
const params = await useQueryProcessor({ ...config.value, catalog });
|
const params = await useExpressionsQueryProcessor({
|
||||||
|
metrics: config.value.expressions || [],
|
||||||
|
metricConfig: config.value.metricConfig || [],
|
||||||
|
subExpressions: config.value.subExpressions || [],
|
||||||
|
});
|
||||||
|
|
||||||
|
loading.value = false;
|
||||||
|
source.value = params.source || {};
|
||||||
|
typesOfMQE.value = params.typesOfMQE;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const params = await useQueryProcessor({ ...config.value });
|
||||||
if (!params) {
|
if (!params) {
|
||||||
source.value = {};
|
source.value = {};
|
||||||
return;
|
return;
|
||||||
@@ -141,7 +160,7 @@ limitations under the License. -->
|
|||||||
metricTypes: config.value.metricTypes || [],
|
metricTypes: config.value.metricTypes || [],
|
||||||
metricConfig: config.value.metricConfig || [],
|
metricConfig: config.value.metricConfig || [],
|
||||||
};
|
};
|
||||||
source.value = useSourceProcessor(json, d);
|
source.value = await useSourceProcessor(json, d);
|
||||||
}
|
}
|
||||||
watch(
|
watch(
|
||||||
() => appStoreWithOut.durationTime,
|
() => appStoreWithOut.durationTime,
|
||||||
@@ -157,6 +176,7 @@ limitations under the License. -->
|
|||||||
config,
|
config,
|
||||||
title,
|
title,
|
||||||
tips,
|
tips,
|
||||||
|
typesOfMQE,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -171,7 +191,7 @@ limitations under the License. -->
|
|||||||
|
|
||||||
.widget-chart {
|
.widget-chart {
|
||||||
background: #fff;
|
background: #fff;
|
||||||
box-shadow: 0px 1px 4px 0px #00000029;
|
box-shadow: 0 1px 4px 0 #00000029;
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
@@ -59,6 +59,7 @@ 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();
|
||||||
@@ -91,7 +92,8 @@ limitations under the License. -->
|
|||||||
step: appStore.durationRow.step,
|
step: appStore.durationRow.step,
|
||||||
utc: appStore.utc,
|
utc: appStore.utc,
|
||||||
});
|
});
|
||||||
const { widget, graph, metrics, metricTypes, metricConfig } = dashboardStore.selectedGrid;
|
const { widget, graph, metrics, metricTypes, metricConfig, metricMode, expressions, typesOfMQE, subExpressions } =
|
||||||
|
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) {
|
||||||
@@ -105,11 +107,20 @@ limitations under the License. -->
|
|||||||
const opt: any = {
|
const opt: any = {
|
||||||
type: dashboardStore.selectedGrid.type,
|
type: dashboardStore.selectedGrid.type,
|
||||||
graph: graph,
|
graph: graph,
|
||||||
metrics: metrics,
|
metricMode,
|
||||||
metricTypes: metricTypes,
|
|
||||||
metricConfig: c,
|
metricConfig: c,
|
||||||
height: dashboardStore.selectedGrid.h * 20 + 60,
|
height: dashboardStore.selectedGrid.h * 20 + 60,
|
||||||
};
|
};
|
||||||
|
if (metricMode === MetricModes.Expression) {
|
||||||
|
opt.expressions = expressions;
|
||||||
|
opt.typesOfMQE = typesOfMQE;
|
||||||
|
if (subExpressions && subExpressions.length) {
|
||||||
|
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 || ""),
|
||||||
|
108
src/views/dashboard/configuration/ContinuousProfiling.vue
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
<!-- 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">
|
||||||
|
<div>{{ t("instanceDashboards") }}</div>
|
||||||
|
<Selector
|
||||||
|
:value="instanceDashboardName || ''"
|
||||||
|
:options="instanceDashboards"
|
||||||
|
size="small"
|
||||||
|
placeholder="Please select a dashboard name"
|
||||||
|
@change="changeDashboard({ instanceDashboardName: $event[0].value })"
|
||||||
|
class="selectors"
|
||||||
|
:clearable="true"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="item">
|
||||||
|
<div>{{ t("processDashboards") }}</div>
|
||||||
|
<Selector
|
||||||
|
:value="processDashboardName || ''"
|
||||||
|
:options="processDashboards"
|
||||||
|
size="small"
|
||||||
|
placeholder="Please select a dashboard name"
|
||||||
|
@change="changeDashboard({ processDashboardName: $event[0].value })"
|
||||||
|
class="selectors"
|
||||||
|
:clearable="true"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="footer">
|
||||||
|
<el-button size="small">
|
||||||
|
{{ t("cancel") }}
|
||||||
|
</el-button>
|
||||||
|
<el-button size="small" type="primary" @click="applyConfig">
|
||||||
|
{{ t("apply") }}
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { ref } from "vue";
|
||||||
|
import { useI18n } from "vue-i18n";
|
||||||
|
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||||
|
import { EntityType } from "../data";
|
||||||
|
import type { DashboardItem } from "@/types/dashboard";
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
const dashboardStore = useDashboardStore();
|
||||||
|
const instanceDashboardName = ref<boolean>(dashboardStore.selectedGrid.instanceDashboardName);
|
||||||
|
const processDashboardName = ref<number>(dashboardStore.selectedGrid.processDashboardName);
|
||||||
|
const list = JSON.parse(sessionStorage.getItem("dashboards") || "[]");
|
||||||
|
const instanceDashboards: Array<DashboardItem & { label: string; value: string }> = [];
|
||||||
|
const processDashboards: Array<DashboardItem & { label: string; value: string }> = [];
|
||||||
|
|
||||||
|
for (const item of list) {
|
||||||
|
if (item.layer === dashboardStore.layerId) {
|
||||||
|
const i = {
|
||||||
|
...item,
|
||||||
|
label: item.name,
|
||||||
|
value: item.name,
|
||||||
|
};
|
||||||
|
if (item.entity === EntityType[8].value) {
|
||||||
|
processDashboards.push(i);
|
||||||
|
}
|
||||||
|
if (item.entity === EntityType[3].value) {
|
||||||
|
instanceDashboards.push(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function applyConfig() {
|
||||||
|
dashboardStore.setConfigs(dashboardStore.selectedGrid);
|
||||||
|
dashboardStore.setConfigPanel(false);
|
||||||
|
}
|
||||||
|
function changeDashboard(param: { [key: string]: unknown }) {
|
||||||
|
dashboardStore.selectWidget({
|
||||||
|
...dashboardStore.selectedGrid,
|
||||||
|
...param,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.footer {
|
||||||
|
position: fixed;
|
||||||
|
bottom: 0;
|
||||||
|
right: 0;
|
||||||
|
border-top: 1px solid #eee;
|
||||||
|
padding: 10px;
|
||||||
|
text-align: right;
|
||||||
|
width: 100%;
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item {
|
||||||
|
margin: 10px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selectors {
|
||||||
|
width: 500px;
|
||||||
|
}
|
||||||
|
</style>
|
@@ -38,8 +38,14 @@ limitations under the License. -->
|
|||||||
metricTypes: dashboardStore.selectedGrid.metricTypes,
|
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 || [],
|
||||||
|
typesOfMQE: dashboardStore.selectedGrid.typesOfMQE || [],
|
||||||
|
subExpressions: dashboardStore.selectedGrid.subExpressions || [],
|
||||||
|
subTypesOfMQE: dashboardStore.selectedGrid.subTypesOfMQE || [],
|
||||||
}"
|
}"
|
||||||
:needQuery="true"
|
:needQuery="true"
|
||||||
|
@expressionTips="getErrors"
|
||||||
/>
|
/>
|
||||||
<div v-show="!graph.type" class="no-data">
|
<div v-show="!graph.type" class="no-data">
|
||||||
{{ t("noData") }}
|
{{ t("noData") }}
|
||||||
@@ -49,7 +55,7 @@ limitations under the License. -->
|
|||||||
<div class="collapse" :style="{ height: configHeight + 'px' }">
|
<div class="collapse" :style="{ height: configHeight + 'px' }">
|
||||||
<el-collapse v-model="states.activeNames" :style="{ '--el-collapse-header-font-size': '15px' }">
|
<el-collapse v-model="states.activeNames" :style="{ '--el-collapse-header-font-size': '15px' }">
|
||||||
<el-collapse-item :title="t('selectVisualization')" name="1">
|
<el-collapse-item :title="t('selectVisualization')" name="1">
|
||||||
<MetricOptions @update="getSource" @loading="setLoading" />
|
<MetricOptions @update="getSource" @loading="setLoading" :errors="errors" :subErrors="subErrors" />
|
||||||
</el-collapse-item>
|
</el-collapse-item>
|
||||||
<el-collapse-item :title="t('graphStyles')" name="2">
|
<el-collapse-item :title="t('graphStyles')" name="2">
|
||||||
<component :is="`${graph.type}Config`" />
|
<component :is="`${graph.type}Config`" />
|
||||||
@@ -83,6 +89,7 @@ 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",
|
||||||
@@ -96,6 +103,8 @@ limitations under the License. -->
|
|||||||
const dashboardStore = useDashboardStore();
|
const dashboardStore = useDashboardStore();
|
||||||
const appStoreWithOut = useAppStoreWithOut();
|
const appStoreWithOut = useAppStoreWithOut();
|
||||||
const loading = ref<boolean>(false);
|
const loading = ref<boolean>(false);
|
||||||
|
const errors = ref<string[]>([]);
|
||||||
|
const subErrors = ref<string[]>([]);
|
||||||
const states = reactive<{
|
const states = reactive<{
|
||||||
activeNames: string;
|
activeNames: string;
|
||||||
source: unknown;
|
source: unknown;
|
||||||
@@ -122,12 +131,34 @@ limitations under the License. -->
|
|||||||
states.source = source;
|
states.source = source;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getErrors(params: { tips: string[]; subTips: string[] }) {
|
||||||
|
errors.value = params.tips;
|
||||||
|
subErrors.value = params.subTips;
|
||||||
|
}
|
||||||
|
|
||||||
function setLoading(load: boolean) {
|
function setLoading(load: boolean) {
|
||||||
loading.value = load;
|
loading.value = load;
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -146,12 +177,15 @@ limitations under the License. -->
|
|||||||
applyConfig,
|
applyConfig,
|
||||||
cancelConfig,
|
cancelConfig,
|
||||||
getSource,
|
getSource,
|
||||||
|
getErrors,
|
||||||
setLoading,
|
setLoading,
|
||||||
widget,
|
widget,
|
||||||
graph,
|
graph,
|
||||||
title,
|
title,
|
||||||
tips,
|
tips,
|
||||||
hasAssociate,
|
hasAssociate,
|
||||||
|
errors,
|
||||||
|
subErrors,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -188,7 +222,7 @@ limitations under the License. -->
|
|||||||
|
|
||||||
.render-chart {
|
.render-chart {
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
height: 400px;
|
height: 420px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -21,6 +21,7 @@ import Topology from "./Topology.vue";
|
|||||||
import Event from "./Event.vue";
|
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";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
Text,
|
Text,
|
||||||
@@ -29,4 +30,5 @@ export default {
|
|||||||
Event,
|
Event,
|
||||||
TimeRange,
|
TimeRange,
|
||||||
ThirdPartyApp,
|
ThirdPartyApp,
|
||||||
|
ContinuousProfiling,
|
||||||
};
|
};
|
||||||
|
@@ -50,12 +50,13 @@ limitations under the License. -->
|
|||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
import { useDashboardStore } from "@/store/modules/dashboard";
|
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||||
import Legend from "./components/Legend.vue";
|
import Legend from "./components/Legend.vue";
|
||||||
|
import { isDef } from "@/utils/is";
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const dashboardStore = useDashboardStore();
|
const dashboardStore = useDashboardStore();
|
||||||
const graph = computed(() => dashboardStore.selectedGrid.graph || {});
|
const graph = computed(() => dashboardStore.selectedGrid.graph || {});
|
||||||
const smooth = ref(graph.value.smooth);
|
const smooth = ref(graph.value.smooth);
|
||||||
const showSymbol = ref(graph.value.showSymbol);
|
const showSymbol = ref(isDef(graph.value.showSymbol) ? graph.value.showSymbol : true);
|
||||||
const step = ref(graph.value.step);
|
const step = ref(graph.value.step);
|
||||||
|
|
||||||
function updateConfig(param: { [key: string]: unknown }) {
|
function updateConfig(param: { [key: string]: unknown }) {
|
||||||
|
@@ -26,7 +26,33 @@ limitations under the License. -->
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>{{ t("metrics") }}</div>
|
<div>{{ t("metrics") }}</div>
|
||||||
<div v-for="(metric, index) in states.metrics" :key="index" class="metric-item">
|
<el-switch
|
||||||
|
v-model="isExpression"
|
||||||
|
class="mb-5"
|
||||||
|
active-text="Expressions"
|
||||||
|
inactive-text="General"
|
||||||
|
size="small"
|
||||||
|
@change="changeMetricMode"
|
||||||
|
/>
|
||||||
|
<div v-if="isExpression && states.isList">
|
||||||
|
<span class="title">{{ t("summary") }}</span>
|
||||||
|
<span>{{ t("detail") }}</span>
|
||||||
|
</div>
|
||||||
|
<div v-for="(metric, index) in states.metrics" :key="index" class="mb-10">
|
||||||
|
<span v-if="isExpression">
|
||||||
|
<div class="expression-param" contenteditable="true" @blur="changeExpression($event, index)">
|
||||||
|
{{ metric }}
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-if="states.isList"
|
||||||
|
class="expression-param"
|
||||||
|
contenteditable="true"
|
||||||
|
@blur="changeSubExpression($event, index)"
|
||||||
|
>
|
||||||
|
{{ states.subMetrics[index] }}
|
||||||
|
</div>
|
||||||
|
</span>
|
||||||
|
<span v-else>
|
||||||
<Selector
|
<Selector
|
||||||
:value="metric"
|
:value="metric"
|
||||||
:options="states.metricList"
|
:options="states.metricList"
|
||||||
@@ -43,6 +69,7 @@ limitations under the License. -->
|
|||||||
@change="changeMetricType(index, $event)"
|
@change="changeMetricType(index, $event)"
|
||||||
class="selectors"
|
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)">
|
||||||
@@ -51,7 +78,12 @@ limitations under the License. -->
|
|||||||
</template>
|
</template>
|
||||||
<Standard @update="queryMetrics" :currentMetricConfig="currentMetricConfig" :index="index" />
|
<Standard @update="queryMetrics" :currentMetricConfig="currentMetricConfig" :index="index" />
|
||||||
</el-popover>
|
</el-popover>
|
||||||
<span v-show="states.isList || states.metricTypes[0] === ProtocolTypes.ReadMetricsValues">
|
<span
|
||||||
|
v-show="
|
||||||
|
states.isList ||
|
||||||
|
[ProtocolTypes.ReadMetricsValues, ExpressionResultType.TIME_SERIES_VALUES as string].includes(states.metricTypes[0])
|
||||||
|
"
|
||||||
|
>
|
||||||
<Icon
|
<Icon
|
||||||
class="cp mr-5"
|
class="cp mr-5"
|
||||||
v-if="index === states.metrics.length - 1 && states.metrics.length < defaultLen"
|
v-if="index === states.metrics.length - 1 && states.metrics.length < defaultLen"
|
||||||
@@ -61,6 +93,15 @@ 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">
|
||||||
|
{{ states.tips[index] }}
|
||||||
|
</div>
|
||||||
|
<div v-if="(errors || [])[index] && isExpression" class="ml-10 red sm">
|
||||||
|
{{ (errors || [])[index] }}
|
||||||
|
</div>
|
||||||
|
<div v-if="(subErrors || [])[index] && isExpression" class="ml-10 red sm">
|
||||||
|
{{ (subErrors || [])[index] }}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>{{ t("visualization") }}</div>
|
<div>{{ t("visualization") }}</div>
|
||||||
<div class="chart-types">
|
<div class="chart-types">
|
||||||
@@ -68,9 +109,7 @@ limitations under the License. -->
|
|||||||
v-for="(type, index) in setVisTypes"
|
v-for="(type, index) in setVisTypes"
|
||||||
:key="index"
|
:key="index"
|
||||||
@click="changeChartType(type)"
|
@click="changeChartType(type)"
|
||||||
:class="{
|
:class="{ active: type.value === graph.type }"
|
||||||
active: type.value === graph.type,
|
|
||||||
}"
|
|
||||||
>
|
>
|
||||||
{{ type.label }}
|
{{ type.label }}
|
||||||
</span>
|
</span>
|
||||||
@@ -78,6 +117,7 @@ limitations under the License. -->
|
|||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { reactive, ref, computed } from "vue";
|
import { reactive, ref, computed } from "vue";
|
||||||
|
import type { PropType } from "vue";
|
||||||
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 {
|
||||||
@@ -89,29 +129,52 @@ limitations under the License. -->
|
|||||||
PodsChartTypes,
|
PodsChartTypes,
|
||||||
MetricsType,
|
MetricsType,
|
||||||
ProtocolTypes,
|
ProtocolTypes,
|
||||||
|
ExpressionResultType,
|
||||||
|
MetricModes,
|
||||||
} from "../../../data";
|
} from "../../../data";
|
||||||
import { ElMessage } from "element-plus";
|
import { ElMessage } from "element-plus";
|
||||||
import Icon from "@/components/Icon.vue";
|
import Icon from "@/components/Icon.vue";
|
||||||
import { useQueryProcessor, useSourceProcessor, useGetMetricEntity } from "@/hooks/useMetricsProcessor";
|
import { useQueryProcessor, useSourceProcessor } from "@/hooks/useMetricsProcessor";
|
||||||
|
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";
|
||||||
|
|
||||||
/*global defineEmits */
|
/*global defineEmits, Indexable */
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const emit = defineEmits(["update", "loading"]);
|
const emit = defineEmits(["update", "loading"]);
|
||||||
|
/*global defineProps */
|
||||||
|
defineProps({
|
||||||
|
errors: {
|
||||||
|
type: Array as PropType<string[]>,
|
||||||
|
},
|
||||||
|
subErrors: {
|
||||||
|
type: Array as PropType<string[]>,
|
||||||
|
},
|
||||||
|
});
|
||||||
const dashboardStore = useDashboardStore();
|
const dashboardStore = useDashboardStore();
|
||||||
const metrics = computed(() => dashboardStore.selectedGrid.metrics || []);
|
const isExpression = ref<boolean>(dashboardStore.selectedGrid.metricMode === MetricModes.Expression ? true : false);
|
||||||
|
const metrics = computed(
|
||||||
|
() => (isExpression.value ? dashboardStore.selectedGrid.expressions : dashboardStore.selectedGrid.metrics) || [],
|
||||||
|
);
|
||||||
|
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(() => dashboardStore.selectedGrid.metricTypes || []);
|
const metricTypes = computed(
|
||||||
|
() => (isExpression.value ? dashboardStore.selectedGrid.typesOfMQE : dashboardStore.selectedGrid.metricTypes) || [],
|
||||||
|
);
|
||||||
const states = reactive<{
|
const states = reactive<{
|
||||||
metrics: string[];
|
metrics: string[];
|
||||||
|
subMetrics: string[];
|
||||||
|
subMetricTypes: string[];
|
||||||
metricTypes: string[];
|
metricTypes: string[];
|
||||||
metricTypeList: Option[][];
|
metricTypeList: Option[][];
|
||||||
isList: boolean;
|
isList: boolean;
|
||||||
metricList: (Option & { type: string })[];
|
metricList: (Option & { type: string })[];
|
||||||
dashboardName: string;
|
dashboardName: string;
|
||||||
dashboardList: ((DashboardItem & { label: string; value: string }) | any)[];
|
dashboardList: ((DashboardItem & { label: string; value: string }) | any)[];
|
||||||
|
tips: string[];
|
||||||
|
subTips: string[];
|
||||||
}>({
|
}>({
|
||||||
metrics: metrics.value.length ? metrics.value : [""],
|
metrics: metrics.value.length ? metrics.value : [""],
|
||||||
metricTypes: metricTypes.value.length ? metricTypes.value : [""],
|
metricTypes: metricTypes.value.length ? metricTypes.value : [""],
|
||||||
@@ -120,6 +183,10 @@ limitations under the License. -->
|
|||||||
metricList: [],
|
metricList: [],
|
||||||
dashboardName: graph.value.dashboardName,
|
dashboardName: graph.value.dashboardName,
|
||||||
dashboardList: [{ label: "", value: "" }],
|
dashboardList: [{ label: "", value: "" }],
|
||||||
|
tips: [],
|
||||||
|
subTips: [],
|
||||||
|
subMetrics: subMetrics.value.length ? subMetrics.value : [""],
|
||||||
|
subMetricTypes: subMetricTypes.value.length ? subMetricTypes.value : [""],
|
||||||
});
|
});
|
||||||
const currentMetricConfig = ref<MetricConfigOpt>({
|
const currentMetricConfig = ref<MetricConfigOpt>({
|
||||||
unit: "",
|
unit: "",
|
||||||
@@ -131,6 +198,8 @@ limitations under the License. -->
|
|||||||
|
|
||||||
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();
|
setMetricType();
|
||||||
|
|
||||||
@@ -158,7 +227,7 @@ limitations under the License. -->
|
|||||||
}
|
}
|
||||||
arr = json.data.metrics;
|
arr = json.data.metrics;
|
||||||
}
|
}
|
||||||
states.metricList = (arr || []).filter((d: { catalog: string; type: string }) => {
|
states.metricList = (arr || []).filter((d: { type: string }) => {
|
||||||
if (states.isList) {
|
if (states.isList) {
|
||||||
if (d.type === MetricsType.REGULAR_VALUE || d.type === MetricsType.LABELED_VALUE) {
|
if (d.type === MetricsType.REGULAR_VALUE || d.type === MetricsType.LABELED_VALUE) {
|
||||||
return d;
|
return d;
|
||||||
@@ -171,6 +240,14 @@ limitations under the License. -->
|
|||||||
return d;
|
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 }) =>
|
const metrics: any = states.metricList.filter((d: { value: string; type: string }) =>
|
||||||
states.metrics.includes(d.value),
|
states.metrics.includes(d.value),
|
||||||
);
|
);
|
||||||
@@ -234,12 +311,22 @@ limitations under the License. -->
|
|||||||
...dashboardStore.selectedGrid,
|
...dashboardStore.selectedGrid,
|
||||||
metrics: [""],
|
metrics: [""],
|
||||||
metricTypes: [""],
|
metricTypes: [""],
|
||||||
|
expressions: [""],
|
||||||
|
typesOfMQE: [""],
|
||||||
});
|
});
|
||||||
states.metrics = [""];
|
states.metrics = [""];
|
||||||
states.metricTypes = [""];
|
states.metricTypes = [""];
|
||||||
defaultLen.value = 5;
|
defaultLen.value = 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isExpression.value) {
|
||||||
|
dashboardStore.selectWidget({
|
||||||
|
...dashboardStore.selectedGrid,
|
||||||
|
graph: chart,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
setMetricType(chart);
|
setMetricType(chart);
|
||||||
|
}
|
||||||
setDashboards(chart.type);
|
setDashboards(chart.type);
|
||||||
states.dashboardName = "";
|
states.dashboardName = "";
|
||||||
defaultLen.value = 10;
|
defaultLen.value = 10;
|
||||||
@@ -300,12 +387,15 @@ limitations under the License. -->
|
|||||||
if (states.isList) {
|
if (states.isList) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const { metricConfig, metricTypes, metrics } = dashboardStore.selectedGrid;
|
if (isExpression.value) {
|
||||||
if (!(metrics && metrics[0] && metricTypes && metricTypes[0])) {
|
queryMetricsWithExpressions();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const catalog = await useGetMetricEntity(metrics[0], metricTypes[0]);
|
const { metricConfig, metricTypes, metrics } = dashboardStore.selectedGrid;
|
||||||
const params = useQueryProcessor({ ...states, metricConfig, catalog });
|
if (!(metrics && metrics[0] && metricTypes && metricTypes[0])) {
|
||||||
|
return emit("update", {});
|
||||||
|
}
|
||||||
|
const params = useQueryProcessor({ ...states, metricConfig });
|
||||||
if (!params) {
|
if (!params) {
|
||||||
emit("update", {});
|
emit("update", {});
|
||||||
return;
|
return;
|
||||||
@@ -322,6 +412,23 @@ limitations under the License. -->
|
|||||||
emit("update", source);
|
emit("update", source);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function queryMetricsWithExpressions() {
|
||||||
|
const { expressions, metricConfig } = dashboardStore.selectedGrid;
|
||||||
|
if (!(expressions && expressions[0])) {
|
||||||
|
return emit("update", {});
|
||||||
|
}
|
||||||
|
|
||||||
|
const params: Indexable = (await useExpressionsQueryProcessor({ ...states, metricConfig })) || {};
|
||||||
|
states.tips = params.tips || [];
|
||||||
|
states.metricTypes = params.typesOfMQE || [];
|
||||||
|
dashboardStore.selectWidget({
|
||||||
|
...dashboardStore.selectedGrid,
|
||||||
|
typesOfMQE: states.metricTypes,
|
||||||
|
});
|
||||||
|
|
||||||
|
emit("update", params.source || {});
|
||||||
|
}
|
||||||
|
|
||||||
function changeDashboard(opt: any) {
|
function changeDashboard(opt: any) {
|
||||||
if (!opt[0]) {
|
if (!opt[0]) {
|
||||||
states.dashboardName = "";
|
states.dashboardName = "";
|
||||||
@@ -339,31 +446,77 @@ limitations under the License. -->
|
|||||||
}
|
}
|
||||||
function addMetric() {
|
function addMetric() {
|
||||||
states.metrics.push("");
|
states.metrics.push("");
|
||||||
|
states.tips.push("");
|
||||||
|
if (isExpression.value && states.isList) {
|
||||||
|
states.subMetrics.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]);
|
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 = [""];
|
||||||
|
let v = {};
|
||||||
|
if (isExpression.value) {
|
||||||
|
v = { typesOfMQE: states.metricTypes, expressions: states.metrics };
|
||||||
|
if (states.isList) {
|
||||||
|
states.subMetrics = [""];
|
||||||
|
states.subMetricTypes = [""];
|
||||||
|
states.subTips = [""];
|
||||||
|
v = {
|
||||||
|
...v,
|
||||||
|
subTypesOfMQE: states.subMetricTypes,
|
||||||
|
subExpressions: states.subMetrics,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
v = { metricTypes: states.metricTypes, metrics: states.metrics };
|
||||||
|
}
|
||||||
dashboardStore.selectWidget({
|
dashboardStore.selectWidget({
|
||||||
...dashboardStore.selectedGrid,
|
...dashboardStore.selectedGrid,
|
||||||
...{ metricTypes: states.metricTypes, metrics: states.metrics },
|
...v,
|
||||||
metricConfig: [],
|
metricConfig: [],
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
states.metrics.splice(index, 1);
|
states.metrics.splice(index, 1);
|
||||||
states.metricTypes.splice(index, 1);
|
states.metricTypes.splice(index, 1);
|
||||||
|
states.tips.splice(index, 1);
|
||||||
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 = {};
|
||||||
|
if (isExpression.value) {
|
||||||
|
if (states.isList) {
|
||||||
|
states.subMetrics.splice(index, 1);
|
||||||
|
states.subMetricTypes.splice(index, 1);
|
||||||
|
states.subTips.splice(index, 1);
|
||||||
|
p = {
|
||||||
|
...p,
|
||||||
|
typesOfMQE: states.metricTypes,
|
||||||
|
expressions: states.metrics,
|
||||||
|
subTypesOfMQE: states.subMetricTypes,
|
||||||
|
subExpressions: states.subMetrics,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
p = { metricTypes: states.metricTypes, metrics: states.metrics };
|
||||||
|
}
|
||||||
dashboardStore.selectWidget({
|
dashboardStore.selectWidget({
|
||||||
...dashboardStore.selectedGrid,
|
...dashboardStore.selectedGrid,
|
||||||
...{ metricTypes: states.metricTypes, metrics: states.metrics },
|
...p,
|
||||||
metricConfig,
|
metricConfig,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -393,6 +546,45 @@ 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) {
|
||||||
|
const params = (event.target.textContent || "").replace(/\s+/g, "");
|
||||||
|
|
||||||
|
states.metrics[index] = params;
|
||||||
|
dashboardStore.selectWidget({
|
||||||
|
...dashboardStore.selectedGrid,
|
||||||
|
expressions: states.metrics,
|
||||||
|
});
|
||||||
|
if (params) {
|
||||||
|
await queryMetrics();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
async function changeSubExpression(event: any, index: number) {
|
||||||
|
const params = (event.target.textContent || "").replace(/\s+/g, "");
|
||||||
|
|
||||||
|
states.subMetrics[index] = params;
|
||||||
|
dashboardStore.selectWidget({
|
||||||
|
...dashboardStore.selectedGrid,
|
||||||
|
subExpressions: states.subMetrics,
|
||||||
|
subTypesOfMQE: states.subMetricTypes,
|
||||||
|
});
|
||||||
|
if (params) {
|
||||||
|
await queryMetrics();
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.ds-name {
|
.ds-name {
|
||||||
@@ -400,7 +592,7 @@ limitations under the License. -->
|
|||||||
}
|
}
|
||||||
|
|
||||||
.selectors {
|
.selectors {
|
||||||
width: 500px;
|
width: 400px;
|
||||||
margin-right: 10px;
|
margin-right: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -427,4 +619,26 @@ limitations under the License. -->
|
|||||||
background-color: #409eff;
|
background-color: #409eff;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.expression-param {
|
||||||
|
display: inline-block;
|
||||||
|
width: 400px;
|
||||||
|
border: 1px solid #dcdfe6;
|
||||||
|
cursor: text;
|
||||||
|
padding: 0 5px;
|
||||||
|
border-radius: 3px;
|
||||||
|
color: #606266;
|
||||||
|
outline: none;
|
||||||
|
margin-right: 5px;
|
||||||
|
min-height: 26px;
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
border-color: #409eff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
display: inline-block;
|
||||||
|
width: 410px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@@ -28,13 +28,13 @@ limitations under the License. -->
|
|||||||
"
|
"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="item mb-10" v-if="hasLabel">
|
<div class="item mb-10" v-if="hasLabel || isExpression">
|
||||||
<span class="label">{{ t("labels") }}</span>
|
<span class="label">{{ t("labels") }}</span>
|
||||||
<el-input
|
<el-input
|
||||||
class="input"
|
class="input"
|
||||||
v-model="currentMetric.label"
|
v-model="currentMetric.label"
|
||||||
size="small"
|
size="small"
|
||||||
placeholder="Please input a name"
|
placeholder="Please input a label"
|
||||||
@change="
|
@change="
|
||||||
updateConfig(index, {
|
updateConfig(index, {
|
||||||
label: encodeURIComponent(currentMetric.label || ''),
|
label: encodeURIComponent(currentMetric.label || ''),
|
||||||
@@ -42,7 +42,21 @@ limitations under the License. -->
|
|||||||
"
|
"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="item mb-10" v-if="metricType === 'readLabeledMetricsValues'">
|
<div class="item mb-10" v-if="isList && isExpression">
|
||||||
|
<span class="label">{{ t("detailLabel") }}</span>
|
||||||
|
<el-input
|
||||||
|
class="input"
|
||||||
|
v-model="currentMetric.detailLabel"
|
||||||
|
size="small"
|
||||||
|
placeholder="Please input a label"
|
||||||
|
@change="
|
||||||
|
updateConfig(index, {
|
||||||
|
detailLabel: encodeURIComponent(currentMetric.detailLabel || ''),
|
||||||
|
})
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="item mb-10" v-if="[ProtocolTypes.ReadLabeledMetricsValues].includes(metricType) && !isExpression">
|
||||||
<span class="label">{{ t("labelsIndex") }}</span>
|
<span class="label">{{ t("labelsIndex") }}</span>
|
||||||
<el-input
|
<el-input
|
||||||
class="input"
|
class="input"
|
||||||
@@ -51,12 +65,12 @@ limitations under the License. -->
|
|||||||
placeholder="auto"
|
placeholder="auto"
|
||||||
@change="
|
@change="
|
||||||
updateConfig(index, {
|
updateConfig(index, {
|
||||||
labelsIndex: encodeURIComponent(currentMetric.labelsIndex),
|
labelsIndex: encodeURIComponent(currentMetric.labelsIndex || ''),
|
||||||
})
|
})
|
||||||
"
|
"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="item mb-10">
|
<div class="item mb-10" v-show="!isExpression">
|
||||||
<span class="label">{{ t("aggregation") }}</span>
|
<span class="label">{{ t("aggregation") }}</span>
|
||||||
<SelectSingle
|
<SelectSingle
|
||||||
:value="currentMetric.calculation"
|
:value="currentMetric.calculation"
|
||||||
@@ -85,7 +99,7 @@ limitations under the License. -->
|
|||||||
type="number"
|
type="number"
|
||||||
:min="1"
|
:min="1"
|
||||||
:max="100"
|
:max="100"
|
||||||
@change="changeConfigs(index, { topN: currentMetric.topN || 10 })"
|
@change="changeConfigs(index, { topN: Number(currentMetric.topN) || 10 })"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -94,7 +108,7 @@ 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 } from "../../../data";
|
import { SortOrder, CalculationOpts, MetricModes } from "../../../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";
|
import { ListChartTypes, ProtocolTypes } from "../../../data";
|
||||||
@@ -110,12 +124,15 @@ 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 = dashboardStore.selectedGrid.metricTypes || [];
|
const metricTypes = computed(
|
||||||
const metricType = computed(() => (dashboardStore.selectedGrid.metricTypes || [])[props.index]);
|
() => (isExpression.value ? dashboardStore.selectedGrid.typesOfMQE : dashboardStore.selectedGrid.metricTypes) || [],
|
||||||
|
);
|
||||||
|
const metricType = computed(() => metricTypes.value[props.index]);
|
||||||
const hasLabel = computed(() => {
|
const hasLabel = computed(() => {
|
||||||
const graph = dashboardStore.selectedGrid.graph || {};
|
const graph = dashboardStore.selectedGrid.graph || {};
|
||||||
return (
|
return (
|
||||||
@@ -123,11 +140,16 @@ limitations under the License. -->
|
|||||||
[ProtocolTypes.ReadLabeledMetricsValues, ProtocolTypes.ReadMetricsValues].includes(metricType.value)
|
[ProtocolTypes.ReadLabeledMetricsValues, ProtocolTypes.ReadMetricsValues].includes(metricType.value)
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
const isList = computed(() => {
|
||||||
|
const graph = dashboardStore.selectedGrid.graph || {};
|
||||||
|
return ListChartTypes.includes(graph.type);
|
||||||
|
});
|
||||||
const isTopn = computed(() =>
|
const isTopn = computed(() =>
|
||||||
[ProtocolTypes.SortMetrics, ProtocolTypes.ReadSampledRecords, ProtocolTypes.ReadRecords].includes(
|
[ProtocolTypes.SortMetrics, ProtocolTypes.ReadSampledRecords, ProtocolTypes.ReadRecords].includes(
|
||||||
metricTypes[props.index],
|
metricTypes.value[props.index],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
function updateConfig(index: number, param: { [key: string]: string }) {
|
function updateConfig(index: number, param: { [key: string]: string }) {
|
||||||
const key = Object.keys(param)[0];
|
const key = Object.keys(param)[0];
|
||||||
if (!key) {
|
if (!key) {
|
||||||
@@ -148,9 +170,10 @@ 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: props.currentMetricConfig.topN || 10,
|
topN: Number(props.currentMetricConfig.topN) || 10,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
100
src/views/dashboard/controls/ContinuousProfiling.vue
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
<!-- 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="profile-wrapper flex-v">
|
||||||
|
<div class="title">Continuous Profiling</div>
|
||||||
|
<el-popover placement="bottom" trigger="click" :width="100" v-if="dashboardStore.editMode">
|
||||||
|
<template #reference>
|
||||||
|
<span class="operation cp">
|
||||||
|
<Icon iconName="ellipsis_v" size="middle" />
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
<div class="tools" @click="editConfig">
|
||||||
|
<span>{{ t("edit") }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="tools" @click="removeWidget">
|
||||||
|
<span>{{ t("delete") }}</span>
|
||||||
|
</div>
|
||||||
|
</el-popover>
|
||||||
|
<Content :config="props.data" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import type { PropType } from "vue";
|
||||||
|
import { useI18n } from "vue-i18n";
|
||||||
|
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||||
|
import Content from "../related/continuous-profiling/Content.vue";
|
||||||
|
|
||||||
|
/*global defineProps */
|
||||||
|
const props = defineProps({
|
||||||
|
data: {
|
||||||
|
type: Object as PropType<any>,
|
||||||
|
default: () => ({ graph: {} }),
|
||||||
|
},
|
||||||
|
activeIndex: { type: String, default: "" },
|
||||||
|
needQuery: { type: Boolean, default: true },
|
||||||
|
});
|
||||||
|
const { t } = useI18n();
|
||||||
|
const dashboardStore = useDashboardStore();
|
||||||
|
|
||||||
|
function removeWidget() {
|
||||||
|
dashboardStore.removeControls(props.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
function editConfig() {
|
||||||
|
dashboardStore.setConfigPanel(true);
|
||||||
|
dashboardStore.selectWidget(props.data);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.profile-wrapper {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
font-size: 12px;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.operation {
|
||||||
|
position: absolute;
|
||||||
|
top: 8px;
|
||||||
|
right: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
padding: 10px;
|
||||||
|
font-size: 12px;
|
||||||
|
border-bottom: 1px solid #dcdfe6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tools {
|
||||||
|
padding: 5px 0;
|
||||||
|
color: #999;
|
||||||
|
cursor: pointer;
|
||||||
|
position: relative;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: #409eff;
|
||||||
|
background-color: #eee;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
font-weight: bold;
|
||||||
|
line-height: 40px;
|
||||||
|
padding: 0 10px;
|
||||||
|
border-bottom: 1px solid #dcdfe6;
|
||||||
|
}
|
||||||
|
</style>
|
@@ -285,7 +285,7 @@ limitations under the License. -->
|
|||||||
}
|
}
|
||||||
|
|
||||||
.tab-name {
|
.tab-name {
|
||||||
max-width: 110px;
|
max-width: 130px;
|
||||||
height: 20px;
|
height: 20px;
|
||||||
line-height: 20px;
|
line-height: 20px;
|
||||||
outline: none;
|
outline: none;
|
||||||
@@ -348,7 +348,7 @@ limitations under the License. -->
|
|||||||
|
|
||||||
.vue-grid-item:not(.vue-grid-placeholder) {
|
.vue-grid-item:not(.vue-grid-placeholder) {
|
||||||
background: #fff;
|
background: #fff;
|
||||||
box-shadow: 0px 1px 4px 0px #00000029;
|
box-shadow: 0 1px 4px 0 #00000029;
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
92
src/views/dashboard/controls/TaskTimeline.vue
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
<!-- 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="content-wrapper flex-v">
|
||||||
|
<div class="title">Task Timeline</div>
|
||||||
|
<el-popover placement="bottom" trigger="click" :width="100" v-if="dashboardStore.editMode">
|
||||||
|
<template #reference>
|
||||||
|
<span class="operation cp">
|
||||||
|
<Icon iconName="ellipsis_v" size="middle" />
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
<div class="tools" @click="removeWidget">
|
||||||
|
<span>{{ t("delete") }}</span>
|
||||||
|
</div>
|
||||||
|
</el-popover>
|
||||||
|
<Content :config="props.data" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import type { PropType } from "vue";
|
||||||
|
import { useI18n } from "vue-i18n";
|
||||||
|
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||||
|
import Content from "../related/task-timeline/Content.vue";
|
||||||
|
|
||||||
|
/*global defineProps */
|
||||||
|
const props = defineProps({
|
||||||
|
data: {
|
||||||
|
type: Object as PropType<any>,
|
||||||
|
default: () => ({ graph: {} }),
|
||||||
|
},
|
||||||
|
activeIndex: { type: String, default: "" },
|
||||||
|
needQuery: { type: Boolean, default: true },
|
||||||
|
});
|
||||||
|
const { t } = useI18n();
|
||||||
|
const dashboardStore = useDashboardStore();
|
||||||
|
|
||||||
|
function removeWidget() {
|
||||||
|
dashboardStore.removeControls(props.data);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.content-wrapper {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
font-size: 12px;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.operation {
|
||||||
|
position: absolute;
|
||||||
|
top: 8px;
|
||||||
|
right: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
padding: 10px;
|
||||||
|
font-size: 12px;
|
||||||
|
border-bottom: 1px solid #dcdfe6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tools {
|
||||||
|
padding: 5px 0;
|
||||||
|
color: #999;
|
||||||
|
cursor: pointer;
|
||||||
|
position: relative;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: #409eff;
|
||||||
|
background-color: #eee;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
font-weight: bold;
|
||||||
|
line-height: 40px;
|
||||||
|
padding: 0 10px;
|
||||||
|
border-bottom: 1px solid #dcdfe6;
|
||||||
|
}
|
||||||
|
</style>
|
@@ -59,7 +59,7 @@ limitations under the License. -->
|
|||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.topology {
|
.topology {
|
||||||
background-color: #333840;
|
// background-color: #333840;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
|
@@ -59,6 +59,11 @@ limitations under the License. -->
|
|||||||
filters: data.filters || {},
|
filters: data.filters || {},
|
||||||
relatedTrace: data.relatedTrace || {},
|
relatedTrace: data.relatedTrace || {},
|
||||||
associate: data.associate || [],
|
associate: data.associate || [],
|
||||||
|
metricMode: data.metricMode,
|
||||||
|
expressions: data.expressions || [],
|
||||||
|
typesOfMQE: typesOfMQE || [],
|
||||||
|
subExpressions: data.subExpressions || [],
|
||||||
|
subTypesOfMQE: data.subTypesOfMQE || [],
|
||||||
}"
|
}"
|
||||||
:needQuery="needQuery"
|
:needQuery="needQuery"
|
||||||
@click="clickHandle"
|
@click="clickHandle"
|
||||||
@@ -76,10 +81,12 @@ limitations under the License. -->
|
|||||||
import { useSelectorStore } from "@/store/modules/selectors";
|
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, useGetMetricEntity } from "@/hooks/useMetricsProcessor";
|
import { useQueryProcessor, useSourceProcessor } from "@/hooks/useMetricsProcessor";
|
||||||
|
import { useExpressionsQueryProcessor } from "@/hooks/useExpressionsProcessor";
|
||||||
import { EntityType, 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: {
|
||||||
@@ -107,16 +114,28 @@ limitations under the License. -->
|
|||||||
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 isList = computed(() => ListChartTypes.includes((props.data.graph && props.data.graph.type) || ""));
|
||||||
|
const typesOfMQE = ref<string[]>([]);
|
||||||
|
|
||||||
if ((props.needQuery || !dashboardStore.currentDashboard.id) && !isList.value) {
|
if ((props.needQuery || !dashboardStore.currentDashboard.id) && !isList.value) {
|
||||||
queryMetrics();
|
queryMetrics();
|
||||||
}
|
}
|
||||||
|
|
||||||
async function queryMetrics() {
|
async function queryMetrics() {
|
||||||
const metricTypes = props.data.metricTypes || [];
|
const isExpression = props.data.metricMode === MetricModes.Expression;
|
||||||
const metrics = props.data.metrics || [];
|
|
||||||
const catalog = await useGetMetricEntity(metrics[0], metricTypes[0]);
|
if (isExpression) {
|
||||||
const params = await useQueryProcessor({ ...props.data, catalog });
|
loading.value = true;
|
||||||
|
const e = {
|
||||||
|
metrics: props.data.expressions || [],
|
||||||
|
metricConfig: props.data.metricConfig || [],
|
||||||
|
};
|
||||||
|
const params = (await useExpressionsQueryProcessor(e)) || {};
|
||||||
|
loading.value = false;
|
||||||
|
state.source = params.source || {};
|
||||||
|
typesOfMQE.value = params.typesOfMQE;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const params = await useQueryProcessor({ ...props.data });
|
||||||
|
|
||||||
if (!params) {
|
if (!params) {
|
||||||
state.source = {};
|
state.source = {};
|
||||||
@@ -133,7 +152,7 @@ limitations under the License. -->
|
|||||||
metricTypes: props.data.metricTypes || [],
|
metricTypes: props.data.metricTypes || [],
|
||||||
metricConfig: props.data.metricConfig || [],
|
metricConfig: props.data.metricConfig || [],
|
||||||
};
|
};
|
||||||
state.source = useSourceProcessor(json, d);
|
state.source = await useSourceProcessor(json, d);
|
||||||
}
|
}
|
||||||
|
|
||||||
function removeWidget() {
|
function removeWidget() {
|
||||||
@@ -169,7 +188,7 @@ limitations under the License. -->
|
|||||||
dashboardStore.selectWidget(props.data);
|
dashboardStore.selectWidget(props.data);
|
||||||
}
|
}
|
||||||
watch(
|
watch(
|
||||||
() => [props.data.metricTypes, props.data.metrics],
|
() => [props.data.metricTypes, props.data.metrics, props.data.expressions],
|
||||||
() => {
|
() => {
|
||||||
if (!dashboardStore.selectedGrid) {
|
if (!dashboardStore.selectedGrid) {
|
||||||
return;
|
return;
|
||||||
@@ -190,7 +209,7 @@ limitations under the License. -->
|
|||||||
if (isList.value) {
|
if (isList.value) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (dashboardStore.entity === EntityType[0].value || dashboardStore.entity === EntityType[4].value) {
|
if ([EntityType[0].value, EntityType[4].value].includes(dashboardStore.entity)) {
|
||||||
queryMetrics();
|
queryMetrics();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -198,7 +217,7 @@ limitations under the License. -->
|
|||||||
watch(
|
watch(
|
||||||
() => [selectorStore.currentPod, selectorStore.currentDestPod],
|
() => [selectorStore.currentPod, selectorStore.currentDestPod],
|
||||||
() => {
|
() => {
|
||||||
if (dashboardStore.entity === EntityType[0].value || dashboardStore.entity === EntityType[7].value) {
|
if ([EntityType[0].value, EntityType[7].value, EntityType[8].value].includes(dashboardStore.entity)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (isList.value) {
|
if (isList.value) {
|
||||||
@@ -210,10 +229,10 @@ limitations under the License. -->
|
|||||||
watch(
|
watch(
|
||||||
() => [selectorStore.currentProcess, selectorStore.currentDestProcess],
|
() => [selectorStore.currentProcess, selectorStore.currentDestProcess],
|
||||||
() => {
|
() => {
|
||||||
if (!(selectorStore.currentDestProcess && selectorStore.currentProcess)) {
|
if (isList.value) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (dashboardStore.entity === EntityType[7].value) {
|
if ([EntityType[7].value, EntityType[8].value].includes(dashboardStore.entity)) {
|
||||||
queryMetrics();
|
queryMetrics();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -242,6 +261,7 @@ limitations under the License. -->
|
|||||||
t,
|
t,
|
||||||
graph,
|
graph,
|
||||||
widget,
|
widget,
|
||||||
|
typesOfMQE,
|
||||||
clickHandle,
|
clickHandle,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
@@ -25,8 +25,10 @@ import Ebpf from "./Ebpf.vue";
|
|||||||
import DemandLog from "./DemandLog.vue";
|
import DemandLog from "./DemandLog.vue";
|
||||||
import Event from "./Event.vue";
|
import Event from "./Event.vue";
|
||||||
import NetworkProfiling from "./NetworkProfiling.vue";
|
import NetworkProfiling from "./NetworkProfiling.vue";
|
||||||
|
import ContinuousProfiling from "./ContinuousProfiling.vue";
|
||||||
import TimeRange from "./TimeRange.vue";
|
import TimeRange from "./TimeRange.vue";
|
||||||
import ThirdPartyApp from "./ThirdPartyApp.vue";
|
import ThirdPartyApp from "./ThirdPartyApp.vue";
|
||||||
|
import TaskTimeline from "./TaskTimeline.vue";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
Tab,
|
Tab,
|
||||||
@@ -40,6 +42,8 @@ export default {
|
|||||||
DemandLog,
|
DemandLog,
|
||||||
Event,
|
Event,
|
||||||
NetworkProfiling,
|
NetworkProfiling,
|
||||||
|
ContinuousProfiling,
|
||||||
TimeRange,
|
TimeRange,
|
||||||
ThirdPartyApp,
|
ThirdPartyApp,
|
||||||
|
TaskTimeline,
|
||||||
};
|
};
|
||||||
|
@@ -24,8 +24,10 @@ import Ebpf from "./Ebpf.vue";
|
|||||||
import DemandLog from "./DemandLog.vue";
|
import DemandLog from "./DemandLog.vue";
|
||||||
import Event from "./Event.vue";
|
import Event from "./Event.vue";
|
||||||
import NetworkProfiling from "./NetworkProfiling.vue";
|
import NetworkProfiling from "./NetworkProfiling.vue";
|
||||||
|
import ContinuousProfiling from "./ContinuousProfiling.vue";
|
||||||
import TimeRange from "./TimeRange.vue";
|
import TimeRange from "./TimeRange.vue";
|
||||||
import ThirdPartyApp from "./ThirdPartyApp.vue";
|
import ThirdPartyApp from "./ThirdPartyApp.vue";
|
||||||
|
import TaskTimeline from "./TaskTimeline.vue";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
Widget,
|
Widget,
|
||||||
@@ -40,4 +42,6 @@ export default {
|
|||||||
NetworkProfiling,
|
NetworkProfiling,
|
||||||
TimeRange,
|
TimeRange,
|
||||||
ThirdPartyApp,
|
ThirdPartyApp,
|
||||||
|
ContinuousProfiling,
|
||||||
|
TaskTimeline,
|
||||||
};
|
};
|
||||||
|
@@ -56,6 +56,15 @@ export enum ProtocolTypes {
|
|||||||
ReadMetricsValues = "readMetricsValues",
|
ReadMetricsValues = "readMetricsValues",
|
||||||
ReadMetricsValue = "readMetricsValue",
|
ReadMetricsValue = "readMetricsValue",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum ExpressionResultType {
|
||||||
|
UNKNOWN = "UNKNOWN",
|
||||||
|
SINGLE_VALUE = "SINGLE_VALUE",
|
||||||
|
TIME_SERIES_VALUES = "TIME_SERIES_VALUES",
|
||||||
|
SORTED_LIST = "SORTED_LIST",
|
||||||
|
RECORD_LIST = "RECORD_LIST",
|
||||||
|
}
|
||||||
|
|
||||||
export const DefaultGraphConfig: { [key: string]: any } = {
|
export const DefaultGraphConfig: { [key: string]: any } = {
|
||||||
Bar: {
|
Bar: {
|
||||||
type: "Bar",
|
type: "Bar",
|
||||||
@@ -65,7 +74,7 @@ export const DefaultGraphConfig: { [key: string]: any } = {
|
|||||||
type: "Line",
|
type: "Line",
|
||||||
step: false,
|
step: false,
|
||||||
smooth: false,
|
smooth: false,
|
||||||
showSymbol: false,
|
showSymbol: true,
|
||||||
showXAxis: true,
|
showXAxis: true,
|
||||||
showYAxis: true,
|
showYAxis: true,
|
||||||
},
|
},
|
||||||
@@ -167,6 +176,7 @@ export const EntityType = [
|
|||||||
},
|
},
|
||||||
{ value: "EndpointRelation", label: "Endpoint Relation", key: 4 },
|
{ value: "EndpointRelation", label: "Endpoint Relation", key: 4 },
|
||||||
{ value: "ProcessRelation", label: "Process Relation", key: 5 },
|
{ value: "ProcessRelation", label: "Process Relation", key: 5 },
|
||||||
|
{ value: "Process", label: "Process", key: 6 },
|
||||||
];
|
];
|
||||||
export const ListEntity: any = {
|
export const ListEntity: any = {
|
||||||
InstanceList: EntityType[3].value,
|
InstanceList: EntityType[3].value,
|
||||||
@@ -194,6 +204,7 @@ export const ServiceTools = [
|
|||||||
{ name: "merge", content: "Add Trace", id: "addTrace" },
|
{ name: "merge", content: "Add Trace", id: "addTrace" },
|
||||||
{ name: "timeline", content: "Add Trace Profiling", id: "addProfile" },
|
{ name: "timeline", content: "Add Trace Profiling", id: "addProfile" },
|
||||||
{ name: "insert_chart", content: "Add eBPF Profiling", id: "addEbpf" },
|
{ name: "insert_chart", content: "Add eBPF Profiling", id: "addEbpf" },
|
||||||
|
{ name: "continuous_profiling", content: "Add Continuous Profiling", id: "addContinuousProfiling" },
|
||||||
{ name: "assignment", content: "Add Log", id: "addLog" },
|
{ name: "assignment", content: "Add Log", id: "addLog" },
|
||||||
{ name: "demand", content: "Add On Demand Log", id: "addDemandLog" },
|
{ name: "demand", content: "Add On Demand Log", id: "addDemandLog" },
|
||||||
{ name: "event", content: "Add Event", id: "addEvent" },
|
{ name: "event", content: "Add Event", id: "addEvent" },
|
||||||
@@ -225,10 +236,16 @@ export const EndpointTools = [
|
|||||||
{ name: "add_iframe", content: "Add Iframe", id: "addIframe" },
|
{ name: "add_iframe", content: "Add Iframe", id: "addIframe" },
|
||||||
];
|
];
|
||||||
export const ProcessTools = [
|
export const ProcessTools = [
|
||||||
|
{ name: "playlist_add", content: "Add Widget", id: "addWidget" },
|
||||||
|
{ name: "all_inbox", content: "Add Tabs", id: "addTab" },
|
||||||
|
{ name: "task_timeline", content: "Add Task Timeline", id: "addTaskTimeline" },
|
||||||
|
{ name: "library_books", content: "Add Text", id: "addText" },
|
||||||
|
{ name: "add_iframe", content: "Add Iframe", id: "addIframe" },
|
||||||
|
];
|
||||||
|
export const ProcessRelationTools = [
|
||||||
{ name: "playlist_add", content: "Add Widget", id: "addWidget" },
|
{ name: "playlist_add", content: "Add Widget", id: "addWidget" },
|
||||||
{ name: "all_inbox", content: "Add Tabs", id: "addTab" },
|
{ name: "all_inbox", content: "Add Tabs", id: "addTab" },
|
||||||
{ name: "library_books", content: "Add Text", id: "addText" },
|
{ name: "library_books", content: "Add Text", id: "addText" },
|
||||||
{ name: "time_range", content: "Add Time Range Text", id: "addTimeRange" },
|
|
||||||
{ name: "add_iframe", content: "Add Iframe", id: "addIframe" },
|
{ name: "add_iframe", content: "Add Iframe", id: "addIframe" },
|
||||||
];
|
];
|
||||||
export const ServiceRelationTools = [
|
export const ServiceRelationTools = [
|
||||||
@@ -300,7 +317,6 @@ export const CalculationOpts = [
|
|||||||
{ label: "Apdex", value: "apdex" },
|
{ label: "Apdex", value: "apdex" },
|
||||||
{ label: "Avg-preview", value: "average" },
|
{ label: "Avg-preview", value: "average" },
|
||||||
{ label: "Percentage + Avg-preview", value: "percentageAvg" },
|
{ label: "Percentage + Avg-preview", value: "percentageAvg" },
|
||||||
{ label: "CPM5D + Avg-preview", value: "cpm5dAvg" },
|
|
||||||
{ label: "Apdex + Avg-preview", value: "apdexAvg" },
|
{ label: "Apdex + Avg-preview", value: "apdexAvg" },
|
||||||
{ label: "Byte to KB", value: "byteToKB" },
|
{ label: "Byte to KB", value: "byteToKB" },
|
||||||
{ label: "Byte to MB", value: "byteToMB" },
|
{ label: "Byte to MB", value: "byteToMB" },
|
||||||
@@ -310,7 +326,6 @@ export const CalculationOpts = [
|
|||||||
value: "convertMilliseconds",
|
value: "convertMilliseconds",
|
||||||
},
|
},
|
||||||
{ label: "Seconds to YYYY-MM-DD HH:mm:ss", value: "convertSeconds" },
|
{ label: "Seconds to YYYY-MM-DD HH:mm:ss", value: "convertSeconds" },
|
||||||
{ label: "CPM5D", value: "cpm5d" },
|
|
||||||
{ label: "Milliseconds to seconds", value: "msTos" },
|
{ label: "Milliseconds to seconds", value: "msTos" },
|
||||||
{ label: "Seconds to days", value: "secondToDay" },
|
{ label: "Seconds to days", value: "secondToDay" },
|
||||||
{ label: "Nanoseconds to milliseconds", value: "nanosecondToMillisecond" },
|
{ label: "Nanoseconds to milliseconds", value: "nanosecondToMillisecond" },
|
||||||
@@ -324,3 +339,8 @@ export const RefreshOptions = [
|
|||||||
{ label: "Last 8 hours", value: "8", step: "HOUR" },
|
{ label: "Last 8 hours", value: "8", step: "HOUR" },
|
||||||
{ label: "Last 7 days", value: "7", step: "DAY" },
|
{ label: "Last 7 days", value: "7", step: "DAY" },
|
||||||
];
|
];
|
||||||
|
|
||||||
|
export enum MetricModes {
|
||||||
|
Expression = "Expression",
|
||||||
|
General = "General",
|
||||||
|
}
|
||||||
|
@@ -23,6 +23,7 @@ limitations under the License. -->
|
|||||||
import type { PropType } from "vue";
|
import type { PropType } from "vue";
|
||||||
import type { BarConfig, EventParams, RelatedTrace, Filters } from "@/types/dashboard";
|
import type { BarConfig, EventParams, RelatedTrace, Filters } from "@/types/dashboard";
|
||||||
import useLegendProcess from "@/hooks/useLegendProcessor";
|
import useLegendProcess from "@/hooks/useLegendProcessor";
|
||||||
|
import Legend from "./components/Legend.vue";
|
||||||
|
|
||||||
/*global defineProps, defineEmits */
|
/*global defineProps, defineEmits */
|
||||||
const emits = defineEmits(["click"]);
|
const emits = defineEmits(["click"]);
|
||||||
|
@@ -15,7 +15,7 @@ limitations under the License. -->
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
v-if="!isNaN(singleVal)"
|
v-if="singleVal !== null && !isNaN(singleVal)"
|
||||||
class="chart-card"
|
class="chart-card"
|
||||||
:style="{
|
:style="{
|
||||||
fontSize: `${config.fontSize}px`,
|
fontSize: `${config.fontSize}px`,
|
||||||
@@ -27,7 +27,7 @@ limitations under the License. -->
|
|||||||
{{ decodeURIComponent(unit) }}
|
{{ decodeURIComponent(unit) }}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="center no-data" v-else>{{ t("noData") }}</div>
|
<div v-else class="card-no-data" :class="config.textAlign === 'center' ? 'center' : ''">{{ t("noData") }}</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed } from "vue";
|
import { computed } from "vue";
|
||||||
@@ -68,13 +68,20 @@ limitations under the License. -->
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.no-data {
|
.card-no-data {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
color: #666;
|
color: #666;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.unit {
|
.unit {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
margin-left: 2px;
|
margin-left: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.center {
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@@ -17,7 +17,7 @@ limitations under the License. -->
|
|||||||
<div class="search">
|
<div class="search">
|
||||||
<el-input v-model="searchText" placeholder="Search for more endpoints" @change="searchList" class="inputs">
|
<el-input v-model="searchText" placeholder="Search for more endpoints" @change="searchList" class="inputs">
|
||||||
<template #append>
|
<template #append>
|
||||||
<el-button @click="searchList" class="btn">
|
<el-button @click="searchList">
|
||||||
<Icon size="middle" iconName="search" />
|
<Icon size="middle" iconName="search" />
|
||||||
</el-button>
|
</el-button>
|
||||||
</template>
|
</template>
|
||||||
@@ -36,11 +36,12 @@ limitations under the License. -->
|
|||||||
<ColumnGraph
|
<ColumnGraph
|
||||||
:intervalTime="intervalTime"
|
:intervalTime="intervalTime"
|
||||||
:colMetrics="colMetrics"
|
:colMetrics="colMetrics"
|
||||||
|
:colSubMetrics="colSubMetrics"
|
||||||
:config="{
|
:config="{
|
||||||
...config,
|
...config,
|
||||||
metrics: colMetrics,
|
|
||||||
metricConfig,
|
metricConfig,
|
||||||
metricTypes,
|
metricTypes,
|
||||||
|
metricMode,
|
||||||
}"
|
}"
|
||||||
v-if="colMetrics.length"
|
v-if="colMetrics.length"
|
||||||
/>
|
/>
|
||||||
@@ -58,7 +59,8 @@ limitations under the License. -->
|
|||||||
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 { useQueryPodsMetrics, usePodsSource } from "@/hooks/useMetricsProcessor";
|
||||||
import { EntityType } from "../data";
|
import { useExpressionsQueryPodsMetrics } from "@/hooks/useExpressionsProcessor";
|
||||||
|
import { EntityType, MetricModes } 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,6 +77,11 @@ limitations under the License. -->
|
|||||||
i: string;
|
i: string;
|
||||||
metrics: string[];
|
metrics: string[];
|
||||||
metricTypes: string[];
|
metricTypes: string[];
|
||||||
|
metricMode: string;
|
||||||
|
expressions: string[];
|
||||||
|
typesOfMQE: string[];
|
||||||
|
subExpressions: string[];
|
||||||
|
subTypesOfMQE: string[];
|
||||||
} & { metricConfig: MetricConfigOpt[] }
|
} & { metricConfig: MetricConfigOpt[] }
|
||||||
>,
|
>,
|
||||||
default: () => ({
|
default: () => ({
|
||||||
@@ -89,6 +96,7 @@ limitations under the License. -->
|
|||||||
intervalTime: { type: Array as PropType<string[]>, default: () => [] },
|
intervalTime: { type: Array as PropType<string[]>, default: () => [] },
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const emit = defineEmits(["expressionTips"]);
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const selectorStore = useSelectorStore();
|
const selectorStore = useSelectorStore();
|
||||||
const dashboardStore = useDashboardStore();
|
const dashboardStore = useDashboardStore();
|
||||||
@@ -96,8 +104,10 @@ limitations under the License. -->
|
|||||||
const endpoints = ref<Endpoint[]>([]);
|
const endpoints = ref<Endpoint[]>([]);
|
||||||
const searchText = ref<string>("");
|
const searchText = ref<string>("");
|
||||||
const colMetrics = ref<string[]>([]);
|
const colMetrics = 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 metricTypes = ref<string[]>(props.config.metricTypes || []);
|
||||||
|
const metricMode = ref<string>(props.config.metricMode);
|
||||||
|
|
||||||
if (props.needQuery) {
|
if (props.needQuery) {
|
||||||
queryEndpoints();
|
queryEndpoints();
|
||||||
@@ -113,11 +123,23 @@ limitations under the License. -->
|
|||||||
ElMessage.error(resp.errors);
|
ElMessage.error(resp.errors);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
endpoints.value = selectorStore.pods;
|
endpoints.value = resp.data.pods || [];
|
||||||
queryEndpointMetrics(endpoints.value);
|
queryEndpointMetrics(endpoints.value);
|
||||||
}
|
}
|
||||||
async function queryEndpointMetrics(currentPods: Endpoint[]) {
|
async function queryEndpointMetrics(arr: Endpoint[]) {
|
||||||
if (!currentPods.length) {
|
if (!arr.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const currentPods = arr.map((d: Endpoint) => {
|
||||||
|
return {
|
||||||
|
id: d.id,
|
||||||
|
value: d.value,
|
||||||
|
label: d.label,
|
||||||
|
merge: d.merge,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
if (props.config.metricMode === MetricModes.Expression) {
|
||||||
|
queryEndpointExpressions(currentPods);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const metrics = props.config.metrics || [];
|
const metrics = props.config.metrics || [];
|
||||||
@@ -141,6 +163,35 @@ limitations under the License. -->
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
endpoints.value = currentPods;
|
endpoints.value = currentPods;
|
||||||
|
colMetrics.value = [];
|
||||||
|
metricTypes.value = [];
|
||||||
|
metricConfig.value = [];
|
||||||
|
}
|
||||||
|
async function queryEndpointExpressions(currentPods: Endpoint[]) {
|
||||||
|
const expressions = props.config.expressions || [];
|
||||||
|
const subExpressions = props.config.subExpressions || [];
|
||||||
|
|
||||||
|
if (expressions.length && expressions[0]) {
|
||||||
|
const params = await useExpressionsQueryPodsMetrics(
|
||||||
|
currentPods,
|
||||||
|
{ metricConfig: metricConfig.value || [], expressions, subExpressions },
|
||||||
|
EntityType[2].value,
|
||||||
|
);
|
||||||
|
endpoints.value = params.data;
|
||||||
|
colMetrics.value = params.names;
|
||||||
|
colSubMetrics.value = params.subNames;
|
||||||
|
metricTypes.value = params.metricTypesArr;
|
||||||
|
metricConfig.value = params.metricConfigArr;
|
||||||
|
emit("expressionTips", { tips: params.expressionsTips, subTips: params.subExpressionsTips });
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
endpoints.value = currentPods;
|
||||||
|
colMetrics.value = [];
|
||||||
|
colSubMetrics.value = [];
|
||||||
|
metricTypes.value = [];
|
||||||
|
metricConfig.value = [];
|
||||||
|
emit("expressionTips", [], []);
|
||||||
}
|
}
|
||||||
function clickEndpoint(scope: any) {
|
function clickEndpoint(scope: any) {
|
||||||
const { dashboard } = getDashboard({
|
const { dashboard } = getDashboard({
|
||||||
@@ -160,12 +211,20 @@ limitations under the License. -->
|
|||||||
await queryEndpoints();
|
await queryEndpoints();
|
||||||
}
|
}
|
||||||
watch(
|
watch(
|
||||||
() => [...(props.config.metricTypes || []), ...(props.config.metrics || []), ...(props.config.metricConfig || [])],
|
() => [
|
||||||
|
...(props.config.metricTypes || []),
|
||||||
|
...(props.config.metrics || []),
|
||||||
|
...(props.config.metricConfig || []),
|
||||||
|
...(props.config.expressions || []),
|
||||||
|
...(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);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@@ -177,9 +236,9 @@ limitations under the License. -->
|
|||||||
);
|
);
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@import "./style.scss";
|
@import url("./style.scss");
|
||||||
|
|
||||||
.tips {
|
.tips {
|
||||||
color: rgba(255, 0, 0, 0.5);
|
color: rgb(255 0 0 / 50%);
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@@ -17,7 +17,7 @@ limitations under the License. -->
|
|||||||
<div class="search">
|
<div class="search">
|
||||||
<el-input v-model="searchText" placeholder="Please input instance name" @change="searchList" class="inputs">
|
<el-input v-model="searchText" placeholder="Please input instance name" @change="searchList" class="inputs">
|
||||||
<template #append>
|
<template #append>
|
||||||
<el-button class="btn" @click="searchList">
|
<el-button @click="searchList">
|
||||||
<Icon size="sm" iconName="search" />
|
<Icon size="sm" iconName="search" />
|
||||||
</el-button>
|
</el-button>
|
||||||
</template>
|
</template>
|
||||||
@@ -35,11 +35,12 @@ limitations under the License. -->
|
|||||||
<ColumnGraph
|
<ColumnGraph
|
||||||
:intervalTime="intervalTime"
|
:intervalTime="intervalTime"
|
||||||
:colMetrics="colMetrics"
|
:colMetrics="colMetrics"
|
||||||
|
:colSubMetrics="colSubMetrics"
|
||||||
:config="{
|
:config="{
|
||||||
...config,
|
...config,
|
||||||
metrics: colMetrics,
|
|
||||||
metricConfig,
|
metricConfig,
|
||||||
metricTypes,
|
metricTypes,
|
||||||
|
metricMode,
|
||||||
}"
|
}"
|
||||||
v-if="colMetrics.length"
|
v-if="colMetrics.length"
|
||||||
/>
|
/>
|
||||||
@@ -70,7 +71,7 @@ limitations under the License. -->
|
|||||||
small
|
small
|
||||||
layout="prev, pager, next"
|
layout="prev, pager, next"
|
||||||
:page-size="pageSize"
|
:page-size="pageSize"
|
||||||
:total="selectorStore.pods.length"
|
:total="pods.length"
|
||||||
@current-change="changePage"
|
@current-change="changePage"
|
||||||
@prev-click="changePage"
|
@prev-click="changePage"
|
||||||
@next-click="changePage"
|
@next-click="changePage"
|
||||||
@@ -87,7 +88,8 @@ limitations under the License. -->
|
|||||||
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 { useQueryPodsMetrics, usePodsSource } from "@/hooks/useMetricsProcessor";
|
||||||
import { EntityType } from "../data";
|
import { useExpressionsQueryPodsMetrics } from "@/hooks/useExpressionsProcessor";
|
||||||
|
import { EntityType, MetricModes } 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";
|
||||||
@@ -102,6 +104,11 @@ limitations under the License. -->
|
|||||||
metrics: string[];
|
metrics: string[];
|
||||||
metricTypes: string[];
|
metricTypes: string[];
|
||||||
isEdit: boolean;
|
isEdit: boolean;
|
||||||
|
metricMode: string;
|
||||||
|
expressions: string[];
|
||||||
|
typesOfMQE: string[];
|
||||||
|
subExpressions: string[];
|
||||||
|
subTypesOfMQE: string[];
|
||||||
} & { metricConfig: MetricConfigOpt[] }
|
} & { metricConfig: MetricConfigOpt[] }
|
||||||
>,
|
>,
|
||||||
default: () => ({
|
default: () => ({
|
||||||
@@ -115,6 +122,7 @@ limitations under the License. -->
|
|||||||
intervalTime: { type: Array as PropType<string[]>, default: () => [] },
|
intervalTime: { type: Array as PropType<string[]>, default: () => [] },
|
||||||
needQuery: { type: Boolean, default: false },
|
needQuery: { type: Boolean, default: false },
|
||||||
});
|
});
|
||||||
|
const emit = defineEmits(["expressionTips"]);
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const selectorStore = useSelectorStore();
|
const selectorStore = useSelectorStore();
|
||||||
const dashboardStore = useDashboardStore();
|
const dashboardStore = useDashboardStore();
|
||||||
@@ -123,8 +131,11 @@ limitations under the License. -->
|
|||||||
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 metricConfig = ref<MetricConfigOpt[]>(props.config.metricConfig || []);
|
const metricConfig = ref<MetricConfigOpt[]>(props.config.metricConfig || []);
|
||||||
const metricTypes = ref<string[]>(props.config.metricTypes || []);
|
const metricTypes = ref<string[]>(props.config.metricTypes || []);
|
||||||
|
const pods = ref<Instance[]>([]); // all instances
|
||||||
|
const metricMode = ref<string>(props.config.metricMode);
|
||||||
if (props.needQuery) {
|
if (props.needQuery) {
|
||||||
queryInstance();
|
queryInstance();
|
||||||
}
|
}
|
||||||
@@ -137,14 +148,31 @@ limitations under the License. -->
|
|||||||
if (resp && resp.errors) {
|
if (resp && resp.errors) {
|
||||||
ElMessage.error(resp.errors);
|
ElMessage.error(resp.errors);
|
||||||
instances.value = [];
|
instances.value = [];
|
||||||
|
pods.value = [];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
instances.value = selectorStore.pods.filter((d: unknown, index: number) => index < pageSize);
|
pods.value = resp.data.pods || [];
|
||||||
|
instances.value = pods.value.filter((d: unknown, index: number) => index < pageSize);
|
||||||
queryInstanceMetrics(instances.value);
|
queryInstanceMetrics(instances.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function queryInstanceMetrics(currentInstances: Instance[]) {
|
async function queryInstanceMetrics(arr: Instance[]) {
|
||||||
if (!currentInstances.length) {
|
if (!arr.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const currentInstances = arr.map((d: Instance) => {
|
||||||
|
return {
|
||||||
|
id: d.id,
|
||||||
|
value: d.value,
|
||||||
|
label: d.label,
|
||||||
|
merge: d.merge,
|
||||||
|
language: d.language,
|
||||||
|
instanceUUID: d.instanceUUID,
|
||||||
|
attributes: d.attributes,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
if (props.config.metricMode === MetricModes.Expression) {
|
||||||
|
queryInstanceExpressions(currentInstances);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const metrics = props.config.metrics || [];
|
const metrics = props.config.metrics || [];
|
||||||
@@ -166,9 +194,40 @@ limitations under the License. -->
|
|||||||
colMetrics.value = names;
|
colMetrics.value = names;
|
||||||
metricTypes.value = metricTypesArr;
|
metricTypes.value = metricTypesArr;
|
||||||
metricConfig.value = metricConfigArr;
|
metricConfig.value = metricConfigArr;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
instances.value = currentInstances;
|
instances.value = currentInstances;
|
||||||
|
colMetrics.value = [];
|
||||||
|
metricTypes.value = [];
|
||||||
|
metricConfig.value = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
async function queryInstanceExpressions(currentInstances: Instance[]) {
|
||||||
|
const expressions = props.config.expressions || [];
|
||||||
|
const subExpressions = props.config.subExpressions || [];
|
||||||
|
|
||||||
|
if (expressions.length && expressions[0]) {
|
||||||
|
const params = await useExpressionsQueryPodsMetrics(
|
||||||
|
currentInstances,
|
||||||
|
{ metricConfig: metricConfig.value || [], expressions, subExpressions },
|
||||||
|
EntityType[3].value,
|
||||||
|
);
|
||||||
|
instances.value = params.data;
|
||||||
|
colMetrics.value = params.names;
|
||||||
|
colSubMetrics.value = params.subNames;
|
||||||
|
metricTypes.value = params.metricTypesArr;
|
||||||
|
metricConfig.value = params.metricConfigArr;
|
||||||
|
emit("expressionTips", { tips: params.expressionsTips, subTips: params.subExpressionsTips });
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
instances.value = currentInstances;
|
||||||
|
colSubMetrics.value = [];
|
||||||
|
colMetrics.value = [];
|
||||||
|
metricTypes.value = [];
|
||||||
|
metricConfig.value = [];
|
||||||
|
emit("expressionTips", [], []);
|
||||||
}
|
}
|
||||||
|
|
||||||
function clickInstance(scope: any) {
|
function clickInstance(scope: any) {
|
||||||
@@ -189,7 +248,7 @@ limitations under the License. -->
|
|||||||
}
|
}
|
||||||
|
|
||||||
function changePage(pageIndex: number) {
|
function changePage(pageIndex: number) {
|
||||||
instances.value = selectorStore.pods.filter((d: unknown, index: number) => {
|
instances.value = pods.value.filter((d: unknown, index: number) => {
|
||||||
if (index >= (pageIndex - 1) * pageSize && index < pageIndex * pageSize) {
|
if (index >= (pageIndex - 1) * pageSize && index < pageIndex * pageSize) {
|
||||||
return d;
|
return d;
|
||||||
}
|
}
|
||||||
@@ -198,18 +257,26 @@ limitations under the License. -->
|
|||||||
}
|
}
|
||||||
|
|
||||||
function searchList() {
|
function searchList() {
|
||||||
const searchInstances = selectorStore.pods.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((d: unknown, index: number) => index < pageSize);
|
||||||
queryInstanceMetrics(instances.value);
|
queryInstanceMetrics(instances.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => [...(props.config.metricTypes || []), ...(props.config.metrics || []), ...(props.config.metricConfig || [])],
|
() => [
|
||||||
|
...(props.config.metricTypes || []),
|
||||||
|
...(props.config.metrics || []),
|
||||||
|
...(props.config.metricConfig || []),
|
||||||
|
...(props.config.expressions || []),
|
||||||
|
...(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);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@@ -221,7 +288,7 @@ limitations under the License. -->
|
|||||||
);
|
);
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@import "./style.scss";
|
@import url("./style.scss");
|
||||||
|
|
||||||
.attributes {
|
.attributes {
|
||||||
max-height: 400px;
|
max-height: 400px;
|
||||||
|
@@ -30,6 +30,7 @@ limitations under the License. -->
|
|||||||
import type { LineConfig, EventParams, RelatedTrace, Filters } from "@/types/dashboard";
|
import type { LineConfig, EventParams, RelatedTrace, Filters } from "@/types/dashboard";
|
||||||
import Legend from "./components/Legend.vue";
|
import Legend from "./components/Legend.vue";
|
||||||
import useLegendProcess from "@/hooks/useLegendProcessor";
|
import useLegendProcess from "@/hooks/useLegendProcessor";
|
||||||
|
import { isDef } from "@/utils/is";
|
||||||
|
|
||||||
/*global defineProps, defineEmits */
|
/*global defineProps, defineEmits */
|
||||||
const emits = defineEmits(["click"]);
|
const emits = defineEmits(["click"]);
|
||||||
@@ -73,12 +74,12 @@ limitations under the License. -->
|
|||||||
name: i,
|
name: i,
|
||||||
type: "line",
|
type: "line",
|
||||||
symbol: "circle",
|
symbol: "circle",
|
||||||
symbolSize: 8,
|
symbolSize: 4,
|
||||||
showSymbol: props.config.showSymbol,
|
showSymbol: isDef(props.config.showSymbol) ? props.config.showSymbol : true,
|
||||||
step: props.config.step,
|
step: props.config.step,
|
||||||
smooth: props.config.smooth,
|
smooth: props.config.smooth,
|
||||||
lineStyle: {
|
lineStyle: {
|
||||||
width: 1.5,
|
width: 2,
|
||||||
type: "solid",
|
type: "solid",
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@@ -17,7 +17,7 @@ limitations under the License. -->
|
|||||||
<div class="search">
|
<div class="search">
|
||||||
<el-input v-model="searchText" placeholder="Please input service name" @change="searchList" class="inputs mt-5">
|
<el-input v-model="searchText" placeholder="Please input service name" @change="searchList" class="inputs mt-5">
|
||||||
<template #append>
|
<template #append>
|
||||||
<el-button class="btn" @click="searchList">
|
<el-button @click="searchList">
|
||||||
<Icon size="sm" iconName="search" />
|
<Icon size="sm" iconName="search" />
|
||||||
</el-button>
|
</el-button>
|
||||||
</template>
|
</template>
|
||||||
@@ -47,11 +47,12 @@ limitations under the License. -->
|
|||||||
<ColumnGraph
|
<ColumnGraph
|
||||||
:intervalTime="intervalTime"
|
:intervalTime="intervalTime"
|
||||||
:colMetrics="colMetrics"
|
:colMetrics="colMetrics"
|
||||||
|
:colSubMetrics="colSubMetrics"
|
||||||
:config="{
|
:config="{
|
||||||
...config,
|
...config,
|
||||||
metrics: colMetrics,
|
|
||||||
metricConfig,
|
metricConfig,
|
||||||
metricTypes,
|
metricTypes,
|
||||||
|
metricMode,
|
||||||
}"
|
}"
|
||||||
v-if="colMetrics.length"
|
v-if="colMetrics.length"
|
||||||
/>
|
/>
|
||||||
@@ -80,7 +81,8 @@ limitations under the License. -->
|
|||||||
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 { useQueryPodsMetrics, usePodsSource } from "@/hooks/useMetricsProcessor";
|
||||||
import { EntityType } from "../data";
|
import { useExpressionsQueryPodsMetrics } from "@/hooks/useExpressionsProcessor";
|
||||||
|
import { EntityType, MetricModes } 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,6 +102,11 @@ limitations under the License. -->
|
|||||||
isEdit: boolean;
|
isEdit: boolean;
|
||||||
names: string[];
|
names: string[];
|
||||||
metricConfig: MetricConfigOpt[];
|
metricConfig: MetricConfigOpt[];
|
||||||
|
metricMode: string;
|
||||||
|
expressions: string[];
|
||||||
|
typesOfMQE: string[];
|
||||||
|
subExpressions: string[];
|
||||||
|
subTypesOfMQE: string[];
|
||||||
}
|
}
|
||||||
>,
|
>,
|
||||||
default: () => ({ dashboardName: "", fontSize: 12 }),
|
default: () => ({ dashboardName: "", fontSize: 12 }),
|
||||||
@@ -107,6 +114,7 @@ limitations under the License. -->
|
|||||||
intervalTime: { type: Array as PropType<string[]>, default: () => [] },
|
intervalTime: { type: Array as PropType<string[]>, default: () => [] },
|
||||||
isEdit: { type: Boolean, default: false },
|
isEdit: { type: Boolean, default: false },
|
||||||
});
|
});
|
||||||
|
const emit = defineEmits(["expressionTips"]);
|
||||||
const selectorStore = useSelectorStore();
|
const selectorStore = useSelectorStore();
|
||||||
const dashboardStore = useDashboardStore();
|
const dashboardStore = useDashboardStore();
|
||||||
const appStore = useAppStoreWithOut();
|
const appStore = useAppStoreWithOut();
|
||||||
@@ -114,11 +122,13 @@ limitations under the License. -->
|
|||||||
const pageSize = 10;
|
const pageSize = 10;
|
||||||
const services = ref<Service[]>([]);
|
const services = ref<Service[]>([]);
|
||||||
const colMetrics = ref<string[]>([]);
|
const colMetrics = ref<string[]>([]);
|
||||||
|
const colSubMetrics = ref<string[]>([]);
|
||||||
const searchText = ref<string>("");
|
const searchText = ref<string>("");
|
||||||
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 metricTypes = ref<string[]>(props.config.metricTypes || []);
|
||||||
|
const metricMode = ref<string>(props.config.metricMode);
|
||||||
|
|
||||||
queryServices();
|
queryServices();
|
||||||
|
|
||||||
@@ -187,8 +197,23 @@ limitations under the License. -->
|
|||||||
|
|
||||||
router.push(path);
|
router.push(path);
|
||||||
}
|
}
|
||||||
async function queryServiceMetrics(currentServices: Service[]) {
|
async function queryServiceMetrics(arr: Service[]) {
|
||||||
if (!currentServices.length) {
|
if (!arr.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const currentServices = arr.map((d: Service) => {
|
||||||
|
return {
|
||||||
|
id: d.id,
|
||||||
|
value: d.value,
|
||||||
|
label: d.label,
|
||||||
|
layers: d.layers,
|
||||||
|
group: d.group,
|
||||||
|
normal: d.normal,
|
||||||
|
merge: d.merge,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
if (props.config.metricMode === MetricModes.Expression) {
|
||||||
|
queryServiceExpressions(currentServices);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const metrics = props.config.metrics || [];
|
const metrics = props.config.metrics || [];
|
||||||
@@ -211,6 +236,7 @@ limitations under the License. -->
|
|||||||
...props.config,
|
...props.config,
|
||||||
metricConfig: metricConfig.value || [],
|
metricConfig: metricConfig.value || [],
|
||||||
});
|
});
|
||||||
|
|
||||||
services.value = data;
|
services.value = data;
|
||||||
colMetrics.value = names;
|
colMetrics.value = names;
|
||||||
metricTypes.value = metricTypesArr;
|
metricTypes.value = metricTypesArr;
|
||||||
@@ -219,6 +245,35 @@ limitations under the License. -->
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
services.value = currentServices;
|
services.value = currentServices;
|
||||||
|
colMetrics.value = [];
|
||||||
|
colMetrics.value = [];
|
||||||
|
metricTypes.value = [];
|
||||||
|
metricConfig.value = [];
|
||||||
|
}
|
||||||
|
async function queryServiceExpressions(currentServices: Service[]) {
|
||||||
|
const expressions = props.config.expressions || [];
|
||||||
|
const subExpressions = props.config.subExpressions || [];
|
||||||
|
|
||||||
|
if (expressions.length && expressions[0]) {
|
||||||
|
const params = await useExpressionsQueryPodsMetrics(
|
||||||
|
currentServices,
|
||||||
|
{ metricConfig: metricConfig.value || [], expressions, subExpressions },
|
||||||
|
EntityType[0].value,
|
||||||
|
);
|
||||||
|
services.value = params.data;
|
||||||
|
colMetrics.value = params.names;
|
||||||
|
colSubMetrics.value = params.subNames;
|
||||||
|
metricTypes.value = params.metricTypesArr;
|
||||||
|
metricConfig.value = params.metricConfigArr;
|
||||||
|
emit("expressionTips", { tips: params.expressionsTips, subTips: params.subExpressionsTips });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
services.value = currentServices;
|
||||||
|
colMetrics.value = [];
|
||||||
|
colSubMetrics.value = [];
|
||||||
|
metricTypes.value = [];
|
||||||
|
metricConfig.value = [];
|
||||||
|
emit("expressionTips", [], []);
|
||||||
}
|
}
|
||||||
function objectSpanMethod(param: any): any {
|
function objectSpanMethod(param: any): any {
|
||||||
if (!props.config.showGroup) {
|
if (!props.config.showGroup) {
|
||||||
@@ -251,15 +306,24 @@ limitations under the License. -->
|
|||||||
}
|
}
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => [...(props.config.metricTypes || []), ...(props.config.metrics || []), ...(props.config.metricConfig || [])],
|
() => [
|
||||||
|
...(props.config.metricTypes || []),
|
||||||
|
...(props.config.metrics || []),
|
||||||
|
...(props.config.metricConfig || []),
|
||||||
|
...(props.config.expressions || []),
|
||||||
|
...(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);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => appStore.durationTime,
|
() => appStore.durationTime,
|
||||||
() => {
|
() => {
|
||||||
@@ -270,5 +334,5 @@ limitations under the License. -->
|
|||||||
);
|
);
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@import "./style.scss";
|
@import url("./style.scss");
|
||||||
</style>
|
</style>
|
||||||
|
@@ -64,19 +64,23 @@ 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 } from "../data";
|
import { QueryOrders, Status, RefIdTypes, ProtocolTypes, ExpressionResultType } from "../data";
|
||||||
|
|
||||||
/*global defineProps */
|
/*global defineProps */
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
data: {
|
data: {
|
||||||
type: Object as PropType<{
|
type: Object as PropType<{
|
||||||
[key: string]: { name: string; value: number; id: string }[];
|
[key: string]: { name: string; value: number; refId: string }[];
|
||||||
}>,
|
}>,
|
||||||
default: () => ({}),
|
default: () => ({}),
|
||||||
},
|
},
|
||||||
config: {
|
config: {
|
||||||
type: Object as PropType<{
|
type: Object as PropType<{
|
||||||
|
metricMode: string;
|
||||||
color: string;
|
color: string;
|
||||||
metrics: string[];
|
metrics: string[];
|
||||||
|
metricTypes: string[];
|
||||||
|
typesOfMQE: string[];
|
||||||
relatedTrace: any;
|
relatedTrace: any;
|
||||||
}>,
|
}>,
|
||||||
default: () => ({ color: "purple" }),
|
default: () => ({ color: "purple" }),
|
||||||
@@ -105,13 +109,17 @@ limitations under the License. -->
|
|||||||
function handleClick(i: string) {
|
function handleClick(i: string) {
|
||||||
copy(i);
|
copy(i);
|
||||||
}
|
}
|
||||||
function viewTrace(item: { name: string; id: string; value: unknown }) {
|
function viewTrace(item: { name: string; refId: string; value: unknown }) {
|
||||||
const filters = {
|
const filters = {
|
||||||
...item,
|
...item,
|
||||||
queryOrder: QueryOrders[1].value,
|
queryOrder: QueryOrders[1].value,
|
||||||
status: Status[2].value,
|
status: Status[2].value,
|
||||||
id: item.id || item.name,
|
id: item.refId,
|
||||||
metricValue: [{ label: props.config.metrics[0], data: item.value, value: item.name }],
|
metricValue: [{ label: props.config.metrics[0], data: item.value, value: item.name }],
|
||||||
|
isReadRecords:
|
||||||
|
props.config.typesOfMQE.includes(ExpressionResultType.RECORD_LIST) ||
|
||||||
|
props.config.metricTypes.includes(ProtocolTypes.ReadRecords) ||
|
||||||
|
undefined,
|
||||||
};
|
};
|
||||||
traceOptions.value = {
|
traceOptions.value = {
|
||||||
...traceOptions.value,
|
...traceOptions.value,
|
||||||
@@ -160,7 +168,7 @@ limitations under the License. -->
|
|||||||
}
|
}
|
||||||
|
|
||||||
.chart-slow-link {
|
.chart-slow-link {
|
||||||
padding: 4px 10px 7px 10px;
|
padding: 4px 10px 7px;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
border: 1px solid #ddd;
|
border: 1px solid #ddd;
|
||||||
color: #333;
|
color: #333;
|
||||||
|