Compare commits
45 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
f9aa6600a7 | ||
![]() |
3c37d7c197 | ||
![]() |
c875c95c20 | ||
![]() |
30069ce825 | ||
![]() |
0a746a125b | ||
![]() |
4d26728eb5 | ||
![]() |
74cb089271 | ||
![]() |
b34c0b0c72 | ||
![]() |
45f896bf36 | ||
![]() |
f334985cf0 | ||
![]() |
f2e75f2b9f | ||
![]() |
b544decbbb | ||
![]() |
b953904c71 | ||
![]() |
7e0d716111 | ||
![]() |
21523b8cb5 | ||
![]() |
8c7fee4d86 | ||
![]() |
7f474984c4 | ||
![]() |
918791f7ed | ||
![]() |
784c2e97b8 | ||
![]() |
b492787027 | ||
![]() |
0e0f2704b3 | ||
![]() |
ca14a7d2c2 | ||
![]() |
49c4c96a6a | ||
![]() |
a0b57d0a5a | ||
![]() |
024a0fe44c | ||
![]() |
918b0551ad | ||
![]() |
d93a7cead2 | ||
![]() |
2a2500a28d | ||
![]() |
7d1bb43adb | ||
![]() |
4c1884d552 | ||
![]() |
f40e9633df | ||
![]() |
02f5c4b976 | ||
![]() |
8a07b1d804 | ||
![]() |
393885324b | ||
![]() |
6bfb7915bb | ||
![]() |
be60d5c770 | ||
![]() |
3c68a4a327 | ||
![]() |
f22208395a | ||
![]() |
26db1ec23e | ||
![]() |
69a9c6de13 | ||
![]() |
2dd9df19d7 | ||
![]() |
5dfbbacd14 | ||
![]() |
deb59705ae | ||
![]() |
3b4c3cc4ea | ||
![]() |
1d83e14f22 |
@@ -28,6 +28,8 @@ header:
|
||||
- '.gitignore'
|
||||
- '.prettierrc'
|
||||
- '.browserslistrc'
|
||||
- 'src/types/auto-imports.d.ts'
|
||||
- 'src/types/components.d.ts'
|
||||
- '**/*.md'
|
||||
- '**/*.json'
|
||||
|
||||
|
21
.prettierignore
Normal file
@@ -0,0 +1,21 @@
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
/src/types/auto-imports.d.ts
|
||||
/src/types/components.d.ts
|
585
package-lock.json
generated
@@ -1,19 +1,21 @@
|
||||
{
|
||||
"name": "skywalking-booster-ui",
|
||||
"version": "0.1.0",
|
||||
"version": "9.1.0",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "skywalking-booster-ui",
|
||||
"version": "0.1.0",
|
||||
"version": "9.1.0",
|
||||
"dependencies": {
|
||||
"axios": "^0.24.0",
|
||||
"d3": "^7.3.0",
|
||||
"d3-flame-graph": "^4.1.3",
|
||||
"d3-tip": "^0.9.1",
|
||||
"echarts": "^5.2.2",
|
||||
"element-plus": "^2.0.2",
|
||||
"lodash": "^4.17.21",
|
||||
"monaco-editor": "^0.27.0",
|
||||
"pinia": "^2.0.5",
|
||||
"vue": "^3.0.0",
|
||||
"vue-grid-layout": "^3.0.0-beta1",
|
||||
@@ -49,6 +51,7 @@
|
||||
"eslint-plugin-vue": "^7.0.0",
|
||||
"husky": "^7.0.4",
|
||||
"lint-staged": "^12.1.3",
|
||||
"monaco-editor-webpack-plugin": "^4.1.2",
|
||||
"node-sass": "^6.0.1",
|
||||
"postcss-html": "^1.3.0",
|
||||
"postcss-scss": "^4.0.2",
|
||||
@@ -61,9 +64,20 @@
|
||||
"stylelint-order": "^5.0.0",
|
||||
"svg-sprite-loader": "^6.0.11",
|
||||
"typescript": "~4.4.4",
|
||||
"unplugin-auto-import": "^0.7.0",
|
||||
"unplugin-vue-components": "^0.19.2",
|
||||
"vue-jest": "^5.0.0-0"
|
||||
}
|
||||
},
|
||||
"node_modules/@antfu/utils": {
|
||||
"version": "0.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@antfu/utils/-/utils-0.5.1.tgz",
|
||||
"integrity": "sha512-8Afo0+xvYe1K8Wm4xHTymfTkpzy36aaqDvhXIayUwl+mecMG9Xzl3XjXa6swG6Bk8FBeQ646RyvmsYt6+2Be9g==",
|
||||
"dev": true,
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/antfu"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/code-frame": {
|
||||
"version": "7.16.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz",
|
||||
@@ -2798,6 +2812,19 @@
|
||||
"url": "https://opencollective.com/popperjs"
|
||||
}
|
||||
},
|
||||
"node_modules/@rollup/pluginutils": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-4.2.0.tgz",
|
||||
"integrity": "sha512-2WUyJNRkyH5p487pGnn4tWAsxhEFKN/pT8CMgHshd5H+IXkOnKvKZwsz5ZWz+YCXkleZRAU5kwbfgF8CPfDRqA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"estree-walker": "^2.0.1",
|
||||
"picomatch": "^2.2.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@soda/friendly-errors-webpack-plugin": {
|
||||
"version": "1.8.1",
|
||||
"resolved": "https://registry.npmjs.org/@soda/friendly-errors-webpack-plugin/-/friendly-errors-webpack-plugin-1.8.1.tgz",
|
||||
@@ -7286,10 +7313,16 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/chokidar": {
|
||||
"version": "3.5.2",
|
||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz",
|
||||
"integrity": "sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==",
|
||||
"version": "3.5.3",
|
||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
|
||||
"integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"anymatch": "~3.1.2",
|
||||
"braces": "~3.0.2",
|
||||
@@ -9074,6 +9107,16 @@
|
||||
"node": ">=0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/cypress/node_modules/uuid": {
|
||||
"version": "3.4.0",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
|
||||
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==",
|
||||
"deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"uuid": "bin/uuid"
|
||||
}
|
||||
},
|
||||
"node_modules/d3": {
|
||||
"version": "7.3.0",
|
||||
"resolved": "https://registry.npmjs.org/d3/-/d3-7.3.0.tgz",
|
||||
@@ -9276,6 +9319,21 @@
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/d3-flame-graph": {
|
||||
"version": "4.1.3",
|
||||
"resolved": "https://registry.npmjs.org/d3-flame-graph/-/d3-flame-graph-4.1.3.tgz",
|
||||
"integrity": "sha512-NijuhJZhaTMwobVgwGQ67x9PovqMMHXBbs0FMHEGJvsWZGuL4M7OsB03v8mHdyVyHhnQYGsYnb5w021e9+R+RQ==",
|
||||
"dependencies": {
|
||||
"d3-array": "^3.1.1",
|
||||
"d3-dispatch": "^3.0.1",
|
||||
"d3-ease": "^3.0.1",
|
||||
"d3-format": "^3.0.1",
|
||||
"d3-hierarchy": "^3.0.1",
|
||||
"d3-scale": "^4.0.2",
|
||||
"d3-selection": "^3.0.0",
|
||||
"d3-transition": "^3.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/d3-force": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/d3-force/-/d3-force-3.0.0.tgz",
|
||||
@@ -9545,9 +9603,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/debug": {
|
||||
"version": "4.3.3",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz",
|
||||
"integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==",
|
||||
"version": "4.3.4",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
||||
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"ms": "2.1.2"
|
||||
@@ -11024,9 +11082,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/eventsource": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/eventsource/-/eventsource-1.1.0.tgz",
|
||||
"integrity": "sha512-VSJjT5oCNrFvCS6igjzPAt5hBzQ2qPBFIbJ03zLI9SE0mxwZpMw6BfJrbFHm1a141AavMEB8JHmBhWAd66PfCg==",
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/eventsource/-/eventsource-1.1.1.tgz",
|
||||
"integrity": "sha512-qV5ZC0h7jYIAOhArFJgSfdyz6rALJyb270714o7ZtNnw2WSJ+eexhKtE0O8LYPRsHZHf2osHKZBxGPvm3kPkCA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"original": "^1.0.0"
|
||||
@@ -11509,9 +11567,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/fast-glob": {
|
||||
"version": "3.2.10",
|
||||
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.10.tgz",
|
||||
"integrity": "sha512-s9nFhFnvR63wls6/kM88kQqDhMu0AfdjqouE2l5GVQPbqLgyFjjU5ry/r2yKsJxpb9Py1EYNqieFrmMaX4v++A==",
|
||||
"version": "3.2.11",
|
||||
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz",
|
||||
"integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@nodelib/fs.stat": "^2.0.2",
|
||||
@@ -11804,9 +11862,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/follow-redirects": {
|
||||
"version": "1.14.7",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.7.tgz",
|
||||
"integrity": "sha512-+hbxoLbFMbRKDwohX8GkTataGqO6Jb7jGwpAlwgy2bIz25XtRm7KEzJM76R1WiNT5SwZkX4Y75SwBolkpmE7iQ==",
|
||||
"version": "1.14.9",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.9.tgz",
|
||||
"integrity": "sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
@@ -17450,6 +17508,18 @@
|
||||
"json5": "lib/cli.js"
|
||||
}
|
||||
},
|
||||
"node_modules/local-pkg": {
|
||||
"version": "0.4.1",
|
||||
"resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-0.4.1.tgz",
|
||||
"integrity": "sha512-lL87ytIGP2FU5PWwNDo0w3WhIo2gopIAxPg9RxDYF7m4rr5ahuZxP22xnJHIvaLTe4Z9P6uKKY2UHiwyB4pcrw==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/antfu"
|
||||
}
|
||||
},
|
||||
"node_modules/locate-path": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
|
||||
@@ -18166,6 +18236,38 @@
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/monaco-editor": {
|
||||
"version": "0.27.0",
|
||||
"resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.27.0.tgz",
|
||||
"integrity": "sha512-UhwP78Wb8w0ZSYoKXQNTV/0CHObp6NS3nCt51QfKE6sKyBo5PBsvuDOHoI2ooBakc6uIwByRLHVeT7+yXQe2fQ=="
|
||||
},
|
||||
"node_modules/monaco-editor-webpack-plugin": {
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/monaco-editor-webpack-plugin/-/monaco-editor-webpack-plugin-4.1.2.tgz",
|
||||
"integrity": "sha512-snmHecygICKT0UlHhva+Cs2WaLPpxy3111xbvInhjjTr5m0xQTFHlmJ2QQDcB14Vzmm7f07uc1TtbvOpmL50BA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"loader-utils": "^2.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"monaco-editor": "0.25.x || 0.26.x || 0.27.x",
|
||||
"webpack": "^4.5.0 || 5.x"
|
||||
}
|
||||
},
|
||||
"node_modules/monaco-editor-webpack-plugin/node_modules/loader-utils": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.2.tgz",
|
||||
"integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"big.js": "^5.2.2",
|
||||
"emojis-list": "^3.0.0",
|
||||
"json5": "^2.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/move-concurrently": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz",
|
||||
@@ -22369,6 +22471,16 @@
|
||||
"request": "^2.34"
|
||||
}
|
||||
},
|
||||
"node_modules/request/node_modules/uuid": {
|
||||
"version": "3.4.0",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
|
||||
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==",
|
||||
"deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"uuid": "bin/uuid"
|
||||
}
|
||||
},
|
||||
"node_modules/require-directory": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
|
||||
@@ -22400,12 +22512,12 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/resolve": {
|
||||
"version": "1.21.0",
|
||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.21.0.tgz",
|
||||
"integrity": "sha512-3wCbTpk5WJlyE4mSOtDLhqQmGFi0/TD9VPwmiolnk8U0wRgMEktqCXd3vy5buTO3tljvalNvKrjHEfrd2WpEKA==",
|
||||
"version": "1.22.0",
|
||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz",
|
||||
"integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"is-core-module": "^2.8.0",
|
||||
"is-core-module": "^2.8.1",
|
||||
"path-parse": "^1.0.7",
|
||||
"supports-preserve-symlinks-flag": "^1.0.0"
|
||||
},
|
||||
@@ -23704,15 +23816,6 @@
|
||||
"ms": "^2.1.1"
|
||||
}
|
||||
},
|
||||
"node_modules/sockjs/node_modules/uuid": {
|
||||
"version": "8.3.2",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
|
||||
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"uuid": "dist/bin/uuid"
|
||||
}
|
||||
},
|
||||
"node_modules/sort-keys": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz",
|
||||
@@ -26397,6 +26500,156 @@
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/unplugin": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/unplugin/-/unplugin-0.6.1.tgz",
|
||||
"integrity": "sha512-cQqRCgQ2v/Q4fPIWNVZ6sNIDdl5v8JXOnlsUOsGzT4fblTONoPWaytiYSpu5qJ9lvSDZYAQN6BRVo3XQoZMfUQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"chokidar": "^3.5.3",
|
||||
"webpack-sources": "^3.2.3",
|
||||
"webpack-virtual-modules": "^0.4.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"esbuild": ">=0.13",
|
||||
"rollup": "^2.50.0",
|
||||
"vite": "^2.3.0",
|
||||
"webpack": "4 || 5"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"esbuild": {
|
||||
"optional": true
|
||||
},
|
||||
"rollup": {
|
||||
"optional": true
|
||||
},
|
||||
"vite": {
|
||||
"optional": true
|
||||
},
|
||||
"webpack": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/unplugin-auto-import": {
|
||||
"version": "0.7.0",
|
||||
"resolved": "https://registry.npmjs.org/unplugin-auto-import/-/unplugin-auto-import-0.7.0.tgz",
|
||||
"integrity": "sha512-40oC7bxzSyyvJI4mXmk8gDD7gKjR10gYkeWBu/UigK8TusXwUsJOjwvIr+REgzOMBGH/5pUiVMoBYEZrLejk3w==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@antfu/utils": "^0.5.0",
|
||||
"@rollup/pluginutils": "^4.2.0",
|
||||
"local-pkg": "^0.4.1",
|
||||
"magic-string": "^0.26.1",
|
||||
"resolve": "^1.22.0",
|
||||
"unplugin": "^0.6.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/antfu"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@vueuse/core": "*"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@vueuse/core": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/unplugin-auto-import/node_modules/magic-string": {
|
||||
"version": "0.26.1",
|
||||
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.26.1.tgz",
|
||||
"integrity": "sha512-ndThHmvgtieXe8J/VGPjG+Apu7v7ItcD5mhEIvOscWjPF/ccOiLxHaSuCAS2G+3x4GKsAbT8u7zdyamupui8Tg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"sourcemap-codec": "^1.4.8"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/unplugin-vue-components": {
|
||||
"version": "0.19.2",
|
||||
"resolved": "https://registry.npmjs.org/unplugin-vue-components/-/unplugin-vue-components-0.19.2.tgz",
|
||||
"integrity": "sha512-7DhQfTyHLyVIWR6VBQONLU6dDBOXtEYvZQYUpN9C+t11WOb5baIFoxfzDxkeFHTHGMhznyEOw6afHyV9JKWnig==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@antfu/utils": "^0.5.0",
|
||||
"@rollup/pluginutils": "^4.2.0",
|
||||
"chokidar": "^3.5.3",
|
||||
"debug": "^4.3.4",
|
||||
"fast-glob": "^3.2.11",
|
||||
"local-pkg": "^0.4.1",
|
||||
"magic-string": "^0.26.1",
|
||||
"minimatch": "^5.0.1",
|
||||
"resolve": "^1.22.0",
|
||||
"unplugin": "^0.6.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/antfu"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@babel/parser": "^7.15.8",
|
||||
"@babel/traverse": "^7.15.4",
|
||||
"vue": "2 || 3"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@babel/parser": {
|
||||
"optional": true
|
||||
},
|
||||
"@babel/traverse": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/unplugin-vue-components/node_modules/brace-expansion": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
|
||||
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"balanced-match": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/unplugin-vue-components/node_modules/magic-string": {
|
||||
"version": "0.26.1",
|
||||
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.26.1.tgz",
|
||||
"integrity": "sha512-ndThHmvgtieXe8J/VGPjG+Apu7v7ItcD5mhEIvOscWjPF/ccOiLxHaSuCAS2G+3x4GKsAbT8u7zdyamupui8Tg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"sourcemap-codec": "^1.4.8"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/unplugin-vue-components/node_modules/minimatch": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz",
|
||||
"integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"brace-expansion": "^2.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/unplugin/node_modules/webpack-sources": {
|
||||
"version": "3.2.3",
|
||||
"resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz",
|
||||
"integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=10.13.0"
|
||||
}
|
||||
},
|
||||
"node_modules/unquote": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/unquote/-/unquote-1.1.1.tgz",
|
||||
@@ -26535,9 +26788,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/url-parse": {
|
||||
"version": "1.5.4",
|
||||
"resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.4.tgz",
|
||||
"integrity": "sha512-ITeAByWWoqutFClc/lRZnFplgXgEZr3WJ6XngMM/N9DMIm4K8zXPCZ1Jdu0rERwO84w1WC5wkle2ubwTA4NTBg==",
|
||||
"version": "1.5.10",
|
||||
"resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz",
|
||||
"integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"querystringify": "^2.1.1",
|
||||
@@ -26615,13 +26868,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/uuid": {
|
||||
"version": "3.4.0",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
|
||||
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==",
|
||||
"deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.",
|
||||
"version": "8.3.2",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
|
||||
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"uuid": "bin/uuid"
|
||||
"uuid": "dist/bin/uuid"
|
||||
}
|
||||
},
|
||||
"node_modules/v8-compile-cache": {
|
||||
@@ -28074,6 +28326,16 @@
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/webpack-log/node_modules/uuid": {
|
||||
"version": "3.4.0",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
|
||||
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==",
|
||||
"deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"uuid": "bin/uuid"
|
||||
}
|
||||
},
|
||||
"node_modules/webpack-merge": {
|
||||
"version": "4.2.2",
|
||||
"resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-4.2.2.tgz",
|
||||
@@ -28102,6 +28364,12 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/webpack-virtual-modules": {
|
||||
"version": "0.4.3",
|
||||
"resolved": "https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.4.3.tgz",
|
||||
"integrity": "sha512-5NUqC2JquIL2pBAAo/VfBP6KuGkHIZQXW/lNKupLPfhViwh8wNsu0BObtl09yuKZszeEUfbXz8xhrHvSG16Nqw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/webpack/node_modules/acorn": {
|
||||
"version": "6.4.2",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz",
|
||||
@@ -28746,6 +29014,12 @@
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@antfu/utils": {
|
||||
"version": "0.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@antfu/utils/-/utils-0.5.1.tgz",
|
||||
"integrity": "sha512-8Afo0+xvYe1K8Wm4xHTymfTkpzy36aaqDvhXIayUwl+mecMG9Xzl3XjXa6swG6Bk8FBeQ646RyvmsYt6+2Be9g==",
|
||||
"dev": true
|
||||
},
|
||||
"@babel/code-frame": {
|
||||
"version": "7.16.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz",
|
||||
@@ -30755,6 +31029,16 @@
|
||||
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.2.tgz",
|
||||
"integrity": "sha512-92FRmppjjqz29VMJ2dn+xdyXZBrMlE42AV6Kq6BwjWV7CNUW1hs2FtxSNLQE+gJhaZ6AAmYuO9y8dshhcBl7vA=="
|
||||
},
|
||||
"@rollup/pluginutils": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-4.2.0.tgz",
|
||||
"integrity": "sha512-2WUyJNRkyH5p487pGnn4tWAsxhEFKN/pT8CMgHshd5H+IXkOnKvKZwsz5ZWz+YCXkleZRAU5kwbfgF8CPfDRqA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"estree-walker": "^2.0.1",
|
||||
"picomatch": "^2.2.2"
|
||||
}
|
||||
},
|
||||
"@soda/friendly-errors-webpack-plugin": {
|
||||
"version": "1.8.1",
|
||||
"resolved": "https://registry.npmjs.org/@soda/friendly-errors-webpack-plugin/-/friendly-errors-webpack-plugin-1.8.1.tgz",
|
||||
@@ -34463,9 +34747,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"chokidar": {
|
||||
"version": "3.5.2",
|
||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz",
|
||||
"integrity": "sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==",
|
||||
"version": "3.5.3",
|
||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
|
||||
"integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"anymatch": "~3.1.2",
|
||||
@@ -35884,6 +36168,12 @@
|
||||
"psl": "^1.1.24",
|
||||
"punycode": "^1.4.1"
|
||||
}
|
||||
},
|
||||
"uuid": {
|
||||
"version": "3.4.0",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
|
||||
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -36035,6 +36325,21 @@
|
||||
"d3-dsv": "1 - 3"
|
||||
}
|
||||
},
|
||||
"d3-flame-graph": {
|
||||
"version": "4.1.3",
|
||||
"resolved": "https://registry.npmjs.org/d3-flame-graph/-/d3-flame-graph-4.1.3.tgz",
|
||||
"integrity": "sha512-NijuhJZhaTMwobVgwGQ67x9PovqMMHXBbs0FMHEGJvsWZGuL4M7OsB03v8mHdyVyHhnQYGsYnb5w021e9+R+RQ==",
|
||||
"requires": {
|
||||
"d3-array": "^3.1.1",
|
||||
"d3-dispatch": "^3.0.1",
|
||||
"d3-ease": "^3.0.1",
|
||||
"d3-format": "^3.0.1",
|
||||
"d3-hierarchy": "^3.0.1",
|
||||
"d3-scale": "^4.0.2",
|
||||
"d3-selection": "^3.0.0",
|
||||
"d3-transition": "^3.0.1"
|
||||
}
|
||||
},
|
||||
"d3-force": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/d3-force/-/d3-force-3.0.0.tgz",
|
||||
@@ -36241,9 +36546,9 @@
|
||||
}
|
||||
},
|
||||
"debug": {
|
||||
"version": "4.3.3",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz",
|
||||
"integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==",
|
||||
"version": "4.3.4",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
||||
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ms": "2.1.2"
|
||||
@@ -37385,9 +37690,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"eventsource": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/eventsource/-/eventsource-1.1.0.tgz",
|
||||
"integrity": "sha512-VSJjT5oCNrFvCS6igjzPAt5hBzQ2qPBFIbJ03zLI9SE0mxwZpMw6BfJrbFHm1a141AavMEB8JHmBhWAd66PfCg==",
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/eventsource/-/eventsource-1.1.1.tgz",
|
||||
"integrity": "sha512-qV5ZC0h7jYIAOhArFJgSfdyz6rALJyb270714o7ZtNnw2WSJ+eexhKtE0O8LYPRsHZHf2osHKZBxGPvm3kPkCA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"original": "^1.0.0"
|
||||
@@ -37787,9 +38092,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"fast-glob": {
|
||||
"version": "3.2.10",
|
||||
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.10.tgz",
|
||||
"integrity": "sha512-s9nFhFnvR63wls6/kM88kQqDhMu0AfdjqouE2l5GVQPbqLgyFjjU5ry/r2yKsJxpb9Py1EYNqieFrmMaX4v++A==",
|
||||
"version": "3.2.11",
|
||||
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz",
|
||||
"integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@nodelib/fs.stat": "^2.0.2",
|
||||
@@ -38036,9 +38341,9 @@
|
||||
}
|
||||
},
|
||||
"follow-redirects": {
|
||||
"version": "1.14.7",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.7.tgz",
|
||||
"integrity": "sha512-+hbxoLbFMbRKDwohX8GkTataGqO6Jb7jGwpAlwgy2bIz25XtRm7KEzJM76R1WiNT5SwZkX4Y75SwBolkpmE7iQ=="
|
||||
"version": "1.14.9",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.9.tgz",
|
||||
"integrity": "sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w=="
|
||||
},
|
||||
"for-in": {
|
||||
"version": "1.0.2",
|
||||
@@ -42411,6 +42716,12 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"local-pkg": {
|
||||
"version": "0.4.1",
|
||||
"resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-0.4.1.tgz",
|
||||
"integrity": "sha512-lL87ytIGP2FU5PWwNDo0w3WhIo2gopIAxPg9RxDYF7m4rr5ahuZxP22xnJHIvaLTe4Z9P6uKKY2UHiwyB4pcrw==",
|
||||
"dev": true
|
||||
},
|
||||
"locate-path": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
|
||||
@@ -42994,6 +43305,33 @@
|
||||
"integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==",
|
||||
"dev": true
|
||||
},
|
||||
"monaco-editor": {
|
||||
"version": "0.27.0",
|
||||
"resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.27.0.tgz",
|
||||
"integrity": "sha512-UhwP78Wb8w0ZSYoKXQNTV/0CHObp6NS3nCt51QfKE6sKyBo5PBsvuDOHoI2ooBakc6uIwByRLHVeT7+yXQe2fQ=="
|
||||
},
|
||||
"monaco-editor-webpack-plugin": {
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/monaco-editor-webpack-plugin/-/monaco-editor-webpack-plugin-4.1.2.tgz",
|
||||
"integrity": "sha512-snmHecygICKT0UlHhva+Cs2WaLPpxy3111xbvInhjjTr5m0xQTFHlmJ2QQDcB14Vzmm7f07uc1TtbvOpmL50BA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"loader-utils": "^2.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"loader-utils": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.2.tgz",
|
||||
"integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"big.js": "^5.2.2",
|
||||
"emojis-list": "^3.0.0",
|
||||
"json5": "^2.1.2"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"move-concurrently": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz",
|
||||
@@ -46215,6 +46553,14 @@
|
||||
"tough-cookie": "~2.5.0",
|
||||
"tunnel-agent": "^0.6.0",
|
||||
"uuid": "^3.3.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"uuid": {
|
||||
"version": "3.4.0",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
|
||||
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"request-progress": {
|
||||
@@ -46271,12 +46617,12 @@
|
||||
"dev": true
|
||||
},
|
||||
"resolve": {
|
||||
"version": "1.21.0",
|
||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.21.0.tgz",
|
||||
"integrity": "sha512-3wCbTpk5WJlyE4mSOtDLhqQmGFi0/TD9VPwmiolnk8U0wRgMEktqCXd3vy5buTO3tljvalNvKrjHEfrd2WpEKA==",
|
||||
"version": "1.22.0",
|
||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz",
|
||||
"integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"is-core-module": "^2.8.0",
|
||||
"is-core-module": "^2.8.1",
|
||||
"path-parse": "^1.0.7",
|
||||
"supports-preserve-symlinks-flag": "^1.0.0"
|
||||
}
|
||||
@@ -47311,14 +47657,6 @@
|
||||
"faye-websocket": "^0.11.3",
|
||||
"uuid": "^8.3.2",
|
||||
"websocket-driver": "^0.7.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"uuid": {
|
||||
"version": "8.3.2",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
|
||||
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"sockjs-client": {
|
||||
@@ -49480,6 +49818,97 @@
|
||||
"integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=",
|
||||
"dev": true
|
||||
},
|
||||
"unplugin": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/unplugin/-/unplugin-0.6.1.tgz",
|
||||
"integrity": "sha512-cQqRCgQ2v/Q4fPIWNVZ6sNIDdl5v8JXOnlsUOsGzT4fblTONoPWaytiYSpu5qJ9lvSDZYAQN6BRVo3XQoZMfUQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"chokidar": "^3.5.3",
|
||||
"webpack-sources": "^3.2.3",
|
||||
"webpack-virtual-modules": "^0.4.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"webpack-sources": {
|
||||
"version": "3.2.3",
|
||||
"resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz",
|
||||
"integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"unplugin-auto-import": {
|
||||
"version": "0.7.0",
|
||||
"resolved": "https://registry.npmjs.org/unplugin-auto-import/-/unplugin-auto-import-0.7.0.tgz",
|
||||
"integrity": "sha512-40oC7bxzSyyvJI4mXmk8gDD7gKjR10gYkeWBu/UigK8TusXwUsJOjwvIr+REgzOMBGH/5pUiVMoBYEZrLejk3w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@antfu/utils": "^0.5.0",
|
||||
"@rollup/pluginutils": "^4.2.0",
|
||||
"local-pkg": "^0.4.1",
|
||||
"magic-string": "^0.26.1",
|
||||
"resolve": "^1.22.0",
|
||||
"unplugin": "^0.6.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"magic-string": {
|
||||
"version": "0.26.1",
|
||||
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.26.1.tgz",
|
||||
"integrity": "sha512-ndThHmvgtieXe8J/VGPjG+Apu7v7ItcD5mhEIvOscWjPF/ccOiLxHaSuCAS2G+3x4GKsAbT8u7zdyamupui8Tg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"sourcemap-codec": "^1.4.8"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"unplugin-vue-components": {
|
||||
"version": "0.19.2",
|
||||
"resolved": "https://registry.npmjs.org/unplugin-vue-components/-/unplugin-vue-components-0.19.2.tgz",
|
||||
"integrity": "sha512-7DhQfTyHLyVIWR6VBQONLU6dDBOXtEYvZQYUpN9C+t11WOb5baIFoxfzDxkeFHTHGMhznyEOw6afHyV9JKWnig==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@antfu/utils": "^0.5.0",
|
||||
"@rollup/pluginutils": "^4.2.0",
|
||||
"chokidar": "^3.5.3",
|
||||
"debug": "^4.3.4",
|
||||
"fast-glob": "^3.2.11",
|
||||
"local-pkg": "^0.4.1",
|
||||
"magic-string": "^0.26.1",
|
||||
"minimatch": "^5.0.1",
|
||||
"resolve": "^1.22.0",
|
||||
"unplugin": "^0.6.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"brace-expansion": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
|
||||
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"balanced-match": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"magic-string": {
|
||||
"version": "0.26.1",
|
||||
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.26.1.tgz",
|
||||
"integrity": "sha512-ndThHmvgtieXe8J/VGPjG+Apu7v7ItcD5mhEIvOscWjPF/ccOiLxHaSuCAS2G+3x4GKsAbT8u7zdyamupui8Tg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"sourcemap-codec": "^1.4.8"
|
||||
}
|
||||
},
|
||||
"minimatch": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz",
|
||||
"integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"brace-expansion": "^2.0.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"unquote": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/unquote/-/unquote-1.1.1.tgz",
|
||||
@@ -49595,9 +50024,9 @@
|
||||
}
|
||||
},
|
||||
"url-parse": {
|
||||
"version": "1.5.4",
|
||||
"resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.4.tgz",
|
||||
"integrity": "sha512-ITeAByWWoqutFClc/lRZnFplgXgEZr3WJ6XngMM/N9DMIm4K8zXPCZ1Jdu0rERwO84w1WC5wkle2ubwTA4NTBg==",
|
||||
"version": "1.5.10",
|
||||
"resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz",
|
||||
"integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"querystringify": "^2.1.1",
|
||||
@@ -49665,9 +50094,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"uuid": {
|
||||
"version": "3.4.0",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
|
||||
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==",
|
||||
"version": "8.3.2",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
|
||||
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
|
||||
"dev": true
|
||||
},
|
||||
"v8-compile-cache": {
|
||||
@@ -50996,6 +51425,14 @@
|
||||
"requires": {
|
||||
"ansi-colors": "^3.0.0",
|
||||
"uuid": "^3.3.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"uuid": {
|
||||
"version": "3.4.0",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
|
||||
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"webpack-merge": {
|
||||
@@ -51025,6 +51462,12 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"webpack-virtual-modules": {
|
||||
"version": "0.4.3",
|
||||
"resolved": "https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.4.3.tgz",
|
||||
"integrity": "sha512-5NUqC2JquIL2pBAAo/VfBP6KuGkHIZQXW/lNKupLPfhViwh8wNsu0BObtl09yuKZszeEUfbXz8xhrHvSG16Nqw==",
|
||||
"dev": true
|
||||
},
|
||||
"websocket-driver": {
|
||||
"version": "0.7.4",
|
||||
"resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz",
|
||||
|
12
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "skywalking-booster-ui",
|
||||
"version": "0.1.0",
|
||||
"version": "9.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"serve": "vue-cli-service serve",
|
||||
@@ -12,10 +12,12 @@
|
||||
"dependencies": {
|
||||
"axios": "^0.24.0",
|
||||
"d3": "^7.3.0",
|
||||
"d3-flame-graph": "^4.1.3",
|
||||
"d3-tip": "^0.9.1",
|
||||
"echarts": "^5.2.2",
|
||||
"element-plus": "^2.0.2",
|
||||
"lodash": "^4.17.21",
|
||||
"monaco-editor": "^0.27.0",
|
||||
"pinia": "^2.0.5",
|
||||
"vue": "^3.0.0",
|
||||
"vue-grid-layout": "^3.0.0-beta1",
|
||||
@@ -51,6 +53,7 @@
|
||||
"eslint-plugin-vue": "^7.0.0",
|
||||
"husky": "^7.0.4",
|
||||
"lint-staged": "^12.1.3",
|
||||
"monaco-editor-webpack-plugin": "^4.1.2",
|
||||
"node-sass": "^6.0.1",
|
||||
"postcss-html": "^1.3.0",
|
||||
"postcss-scss": "^4.0.2",
|
||||
@@ -63,6 +66,8 @@
|
||||
"stylelint-order": "^5.0.0",
|
||||
"svg-sprite-loader": "^6.0.11",
|
||||
"typescript": "~4.4.4",
|
||||
"unplugin-auto-import": "^0.7.0",
|
||||
"unplugin-vue-components": "^0.19.2",
|
||||
"vue-jest": "^5.0.0-0"
|
||||
},
|
||||
"eslintConfig": {
|
||||
@@ -103,6 +108,9 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"eslintIgnore": [
|
||||
"vue.config.js"
|
||||
],
|
||||
"browserslist": [
|
||||
"> 1%",
|
||||
"last 2 versions",
|
||||
@@ -133,7 +141,7 @@
|
||||
"package.json": [
|
||||
"prettier --write"
|
||||
],
|
||||
"*.{scss,less,styl,html}": [
|
||||
"*.{scss,less,styl}": [
|
||||
"stylelint --fix",
|
||||
"prettier --write"
|
||||
],
|
||||
|
@@ -13,7 +13,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License. -->
|
||||
<!DOCTYPE html>
|
||||
<html lang="">
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
|
@@ -13,11 +13,13 @@ 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>
|
||||
<router-view :key="$route.fullPath" />
|
||||
<router-view />
|
||||
</template>
|
||||
<style>
|
||||
#app {
|
||||
color: #2c3e50;
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
min-width: 1024px;
|
||||
}
|
||||
</style>
|
||||
|
16
src/assets/icons/arrow-down.svg
Executable 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 xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><path id="a" d="m10.472352 7.28232367c.3431062-.36783247.904419-.36783247 1.2592596-.00644059.3578153.36442148.3578153.95850784.0002156 1.28561559l-3.10532264 3.16826253c-.17025689.1734002-.39845625.2702388-.62654793.2702388-.24380864 0-.45151514-.0919745-.62697852-.2706782l-3.09835734-3.16693764c-.36405333-.352236-.36405333-.94614513-.01248284-1.28566765.34310619-.36783247.90441901-.36783247 1.25901327-.0066912l2.48658215 2.52737493z"/></svg>
|
After Width: | Height: | Size: 1.3 KiB |
16
src/assets/icons/demand.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 t="1654161407133" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1721" width="16" height="16"><path d="M804.224 86.144c0-19.264-15.616-34.944-34.944-34.944l-734.336 0c-19.264 0-34.944 15.68-34.944 34.944l0 82.048 804.224 0 0-82.048zM738.88 602.432c0 47.072-38.176 85.248-85.248 85.248s-85.248-38.176-85.248-85.248c0-47.072 38.176-85.248 85.248-85.248s85.248 38.176 85.248 85.248zM804.992 264.64l0-62.976-804.224 0 0 665.408c0 18.56 14.656 33.472 32.96 34.56l402.24 0c61.12 44.544 136.192 71.168 217.664 71.168 204.544 0 370.368-165.824 370.368-370.368 0-150.592-89.984-279.936-219.008-337.792zM412.096 298.24l30.528 0c-10.624 7.36-20.8 15.36-30.528 23.744l0-23.744zM63.04 298.24l153.024 0 0 153.024-153.024 0 0-153.024zM216.064 805.056l-153.024 0 0-153.024 153.024 0 0 153.024zM219.136 631.232l-153.024 0 0-153.024 153.024 0 0 153.024zM237.568 805.056l0-153.024 49.408 0c7.488 55.936 27.264 107.904 56.832 153.024l-106.24 0zM284.672 631.232l-44.032 0 0-153.024 64.384 0c-13.824 38.848-21.824 80.576-21.824 124.224 0 9.728 0.768 19.264 1.472 28.8zM390.592 341.76c-31.168 31.424-56.512 68.544-74.88 109.44l-78.144 0 0-152.96 153.024 0 0 43.52zM899.136 638.4l-63.36 12.864c-4.288 16.064-10.688 31.296-18.816 45.376l35.712 53.888-50.944 50.944-53.888-35.712c-14.08 8.128-29.312 14.528-45.376 18.816l-12.864 63.36-72 0-12.864-63.36c-16.064-4.288-31.296-10.688-45.376-18.816l-53.888 35.712-50.944-50.944 35.712-53.888c-8.128-14.08-14.528-29.312-18.816-45.376l-63.36-12.864 0-72 63.36-12.864c4.352-16.064 10.688-31.296 18.816-45.312l-35.712-53.952 50.944-50.944 53.888 35.776c14.08-8.128 29.312-14.464 45.376-18.816l12.864-63.36 72 0 12.864 63.36c16.064 4.288 31.296 10.688 45.376 18.816l53.888-35.712 50.944 50.944-35.712 53.824c8.128 14.08 14.528 29.312 18.816 45.376l63.36 12.864 0 72z" p-id="1722" fill="#707070"></path></svg>
|
After Width: | Height: | Size: 2.6 KiB |
17
src/assets/icons/insert_chart.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 version="1.1" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
|
||||
<path d="M17.016 17.016v-4.031h-2.016v4.031h2.016zM12.984 17.016v-10.031h-1.969v10.031h1.969zM9 17.016v-7.031h-2.016v7.031h2.016zM18.984 3q0.797 0 1.406 0.609t0.609 1.406v13.969q0 0.797-0.609 1.406t-1.406 0.609h-13.969q-0.797 0-1.406-0.609t-0.609-1.406v-13.969q0-0.797 0.609-1.406t1.406-0.609h13.969z"></path>
|
||||
</svg>
|
After Width: | Height: | Size: 1.2 KiB |
@@ -13,6 +13,5 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License. -->
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
|
||||
<title>timeline</title>
|
||||
<path d="M23.016 8.016q0 0.797-0.609 1.383t-1.406 0.586h-0.047q-0.328 0-0.469-0.047l-3.563 3.563q0.094 0.281 0.094 0.516 0 0.797-0.609 1.383t-1.406 0.586-1.406-0.586-0.609-1.383q0-0.234 0.094-0.516l-2.578-2.578q-0.281 0.094-0.516 0.094t-0.516-0.094l-4.547 4.547q0.094 0.281 0.094 0.516 0 0.797-0.609 1.406t-1.406 0.609-1.406-0.609-0.609-1.406 0.609-1.383 1.406-0.586q0.375 0 0.516 0.047l4.547-4.547q-0.047-0.141-0.047-0.516 0-0.797 0.586-1.406t1.383-0.609 1.406 0.609 0.609 1.406q0 0.375-0.047 0.516l2.531 2.531q0.141-0.047 0.516-0.047t0.516 0.047l3.563-3.516q-0.094-0.281-0.094-0.516 0-0.797 0.609-1.406t1.406-0.609 1.406 0.609 0.609 1.406z"></path>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
15
src/assets/icons/view.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="1650287922642" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3055" width="48" height="48"><path d="M277.333333 325.333333m5.333334 0l325.333333 0q5.333333 0 5.333333 5.333334l0 64q0 5.333333-5.333333 5.333333l-325.333333 0q-5.333333 0-5.333334-5.333333l0-64q0-5.333333 5.333334-5.333334Z" p-id="3056" fill="#707070"></path><path d="M277.333333 474.666667m5.333334 0l325.333333 0q5.333333 0 5.333333 5.333333l0 64q0 5.333333-5.333333 5.333333l-325.333333 0q-5.333333 0-5.333334-5.333333l0-64q0-5.333333 5.333334-5.333333Z" p-id="3057" fill="#707070"></path><path d="M277.333333 624m5.333334 0l247.36 0q5.333333 0 5.333333 5.333333l0 64q0 5.333333-5.333333 5.333334l-247.36 0q-5.333333 0-5.333334-5.333334l0-64q0-5.333333 5.333334-5.333333Z" p-id="3058" fill="#707070"></path><path d="M565.333333 842.666667H186.666667a5.333333 5.333333 0 0 1-5.333334-5.333334V186.666667a5.333333 5.333333 0 0 1 5.333334-5.333334h522.666666v346.24a5.333333 5.333333 0 0 0 5.333334 5.333334h64a5.333333 5.333333 0 0 0 5.333333-5.333334V106.666667H112a5.333333 5.333333 0 0 0-5.333333 5.333333v800a5.333333 5.333333 0 0 0 5.333333 5.333333h453.333333a5.333333 5.333333 0 0 0 5.333334-5.333333v-64a5.333333 5.333333 0 0 0-5.333334-5.333333z" p-id="3059" fill="#707070"></path><path d="M868.426667 723.786667a144.64 144.64 0 1 0-144.64 144.64 144.64 144.64 0 0 0 144.64-144.64z m-144.64 69.973333a69.973333 69.973333 0 1 1 69.973333-69.973333 70.026667 70.026667 0 0 1-69.973333 69.973333z" p-id="3060" fill="#707070"></path><path d="M811.758007 864.533065m3.771237-3.771236l45.254834-45.254834q3.771236-3.771236 7.542472 0l45.254834 45.254834q3.771236 3.771236 0 7.542472l-45.254834 45.254834q-3.771236 3.771236-7.542472 0l-45.254834-45.254834q-3.771236-3.771236 0-7.542472Z" p-id="3061" fill="#707070"></path></svg>
|
After Width: | Height: | Size: 2.6 KiB |
BIN
src/assets/img/technologies/APACHESHENYU.png
Normal file
After Width: | Height: | Size: 2.1 KiB |
@@ -247,7 +247,7 @@ limitations under the License. -->
|
||||
(state.showMinutes = state.showSeconds = false)
|
||||
"
|
||||
:class="{ on: state.showHours }"
|
||||
>{{ state.hour || dd }}</a
|
||||
>{{ dd(state.hour) }}</a
|
||||
>
|
||||
<span>:</span>
|
||||
<a
|
||||
@@ -257,7 +257,7 @@ limitations under the License. -->
|
||||
(state.showHours = state.showSeconds = false)
|
||||
"
|
||||
:class="{ on: state.showMinutes }"
|
||||
>{{ state.minute || dd }}</a
|
||||
>{{ dd(state.minute) }}</a
|
||||
>
|
||||
<span v-show="state.m !== 'D'">
|
||||
<span>:</span>
|
||||
@@ -268,7 +268,7 @@ limitations under the License. -->
|
||||
(state.showHours = state.showMinutes = false)
|
||||
"
|
||||
:class="{ on: state.showSeconds }"
|
||||
>{{ state.second || dd }}</a
|
||||
>{{ dd(state.second) }}</a
|
||||
>
|
||||
</span>
|
||||
</div>
|
||||
@@ -464,7 +464,6 @@ const status = (
|
||||
const minutes = time.getMinutes();
|
||||
const seconds = time.getSeconds();
|
||||
const milliseconds = time.getMilliseconds();
|
||||
const dd = (t: number) => `0${t}`.slice(-2);
|
||||
const map: { [key: string]: string | number } = {
|
||||
YYYY: year,
|
||||
MM: dd(month + 1),
|
||||
|
@@ -53,9 +53,6 @@ const available = computed(
|
||||
(Array.isArray(props.option.series.data) && props.option.series.data[0])
|
||||
);
|
||||
onMounted(async () => {
|
||||
if (!available.value) {
|
||||
return;
|
||||
}
|
||||
await setOptions(props.option);
|
||||
chartRef.value && addResizeListener(unref(chartRef), resize);
|
||||
setTimeout(() => {
|
||||
|
@@ -32,7 +32,7 @@ interface Option {
|
||||
const emit = defineEmits(["change"]);
|
||||
const props = defineProps({
|
||||
options: {
|
||||
type: Array as PropType<(Option & { disabled: boolean })[]>,
|
||||
type: Array as PropType<Option[]>,
|
||||
default: () => [],
|
||||
},
|
||||
value: {
|
||||
@@ -44,7 +44,7 @@ const props = defineProps({
|
||||
|
||||
const selected = ref<string>(props.value);
|
||||
|
||||
function checked(opt: string) {
|
||||
function checked(opt: unknown) {
|
||||
emit("change", opt);
|
||||
}
|
||||
</script>
|
||||
|
@@ -45,7 +45,7 @@ import { Option } from "@/types/app";
|
||||
const emit = defineEmits(["change"]);
|
||||
const props = defineProps({
|
||||
options: {
|
||||
type: Array as PropType<(Option & { disabled: boolean })[]>,
|
||||
type: Array as PropType<Option[]>,
|
||||
default: () => [],
|
||||
},
|
||||
value: {
|
||||
|
@@ -58,7 +58,7 @@ const props = defineProps({
|
||||
},
|
||||
size: { type: null, default: "default" },
|
||||
placeholder: {
|
||||
type: [String, Number] as PropType<string | number>,
|
||||
type: [String, undefined] as PropType<string>,
|
||||
default: "Select a option",
|
||||
},
|
||||
borderRadius: { type: Number, default: 3 },
|
||||
|
@@ -14,13 +14,13 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import type { App } from "vue";
|
||||
import Icon from "./Icon.vue";
|
||||
import TimePicker from "./TimePicker.vue";
|
||||
import Selector from "./Selector.vue";
|
||||
import Graph from "./Graph.vue";
|
||||
import Radio from "./Radio.vue";
|
||||
import SelectSingle from "./SelectSingle.vue";
|
||||
import type { App } from "vue";
|
||||
import VueGridLayout from "vue-grid-layout";
|
||||
|
||||
const components: { [key: string]: any } = {
|
||||
|
@@ -23,6 +23,7 @@ export enum TimeType {
|
||||
export const Languages = [
|
||||
{ label: "English", value: "en" },
|
||||
{ label: "Chinese", value: "zh" },
|
||||
{ label: "Spanish", value: "es" },
|
||||
];
|
||||
|
||||
export const RoutesMap: { [key: string]: string } = {
|
||||
|
@@ -45,6 +45,5 @@ export const Alarm = {
|
||||
endTime
|
||||
}
|
||||
}
|
||||
total
|
||||
}`,
|
||||
};
|
||||
|
36
src/graphql/fragments/demand-log.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* 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 const queryContainers = {
|
||||
variable: "$condition: OndemandContainergQueryCondition!",
|
||||
query: `
|
||||
containers: listContainers(condition: $condition) {
|
||||
errorReason
|
||||
containers
|
||||
}`,
|
||||
};
|
||||
|
||||
export const queryStreamingLogs = {
|
||||
variable: "$condition: OndemandLogQueryCondition",
|
||||
query: `
|
||||
logs: ondemandPodLogs(condition: $condition) {
|
||||
errorReason
|
||||
logs {
|
||||
content
|
||||
}
|
||||
}`,
|
||||
};
|
92
src/graphql/fragments/ebpf.ts
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.
|
||||
*/
|
||||
|
||||
export const queryCreateTaskData = {
|
||||
variable: "$serviceId: ID!",
|
||||
query: `
|
||||
createTaskData: queryPrepareCreateEBPFProfilingTaskData(serviceId: $serviceId) {
|
||||
couldProfiling
|
||||
processLabels
|
||||
}`,
|
||||
};
|
||||
export const createEBPFTask = {
|
||||
variable: "$request: EBPFProfilingTaskFixedTimeCreationRequest!",
|
||||
query: `
|
||||
createTaskData: createEBPFProfilingFixedTimeTask(request: $request) {
|
||||
status
|
||||
errorReason
|
||||
id
|
||||
}`,
|
||||
};
|
||||
export const queryEBPFTasks = {
|
||||
variable: "$serviceId: ID!",
|
||||
query: `
|
||||
queryEBPFTasks: queryEBPFProfilingTasks(serviceId: $serviceId) {
|
||||
taskId
|
||||
serviceName
|
||||
serviceId
|
||||
processLabels
|
||||
taskStartTime
|
||||
triggerType
|
||||
fixedTriggerDuration
|
||||
targetType
|
||||
createTime
|
||||
}`,
|
||||
};
|
||||
export const queryEBPFSchedules = {
|
||||
variable: "$taskId: ID!",
|
||||
query: `
|
||||
eBPFSchedules: queryEBPFProfilingSchedules(taskId: $taskId) {
|
||||
scheduleId
|
||||
taskId
|
||||
process {
|
||||
id
|
||||
name
|
||||
serviceId
|
||||
serviceName
|
||||
instanceId
|
||||
instanceName
|
||||
agentId
|
||||
detectType
|
||||
attributes {
|
||||
name
|
||||
value
|
||||
}
|
||||
labels
|
||||
}
|
||||
startTime
|
||||
endTime
|
||||
}`,
|
||||
};
|
||||
|
||||
export const analysisEBPFResult = {
|
||||
variable:
|
||||
"$scheduleIdList: [ID!]!, $timeRanges: [EBPFProfilingAnalyzeTimeRange!]!, $aggregateType: EBPFProfilingAnalyzeAggregateType",
|
||||
query: `
|
||||
analysisEBPFResult: analysisEBPFProfilingResult(scheduleIdList: $scheduleIdList, timeRanges: $timeRanges, aggregateType: $aggregateType) {
|
||||
tip
|
||||
trees {
|
||||
elements {
|
||||
id
|
||||
parentId
|
||||
symbol
|
||||
stackType
|
||||
dumpCount
|
||||
}
|
||||
}
|
||||
}`,
|
||||
};
|
@@ -35,6 +35,5 @@ export const FetchEvents = {
|
||||
startTime
|
||||
endTime
|
||||
}
|
||||
total
|
||||
}`,
|
||||
};
|
||||
|
@@ -30,7 +30,6 @@ export const QueryBrowserErrorLogs = {
|
||||
stack
|
||||
grade
|
||||
}
|
||||
total
|
||||
}`,
|
||||
};
|
||||
|
||||
@@ -54,7 +53,6 @@ export const QueryServiceLogs = {
|
||||
value
|
||||
}
|
||||
}
|
||||
total
|
||||
}`,
|
||||
};
|
||||
|
||||
@@ -63,3 +61,15 @@ export const QueryLogsByKeywords = {
|
||||
query: `
|
||||
support: supportQueryLogsByKeywords`,
|
||||
};
|
||||
|
||||
export const LogTagKeys = {
|
||||
variable: "$duration: Duration!",
|
||||
query: `
|
||||
tagKeys: queryLogTagAutocompleteKeys(duration: $duration)`,
|
||||
};
|
||||
|
||||
export const LogTagValues = {
|
||||
variable: "$tagKey: String!, $duration: Duration!",
|
||||
query: `
|
||||
tagValues: queryLogTagAutocompleteValues(tagKey: $tagKey, duration: $duration)`,
|
||||
};
|
||||
|
@@ -20,10 +20,10 @@ export const Services = {
|
||||
services: listServices(layer: $layer) {
|
||||
id
|
||||
value: name
|
||||
label: name
|
||||
group
|
||||
layers
|
||||
normal
|
||||
label: name
|
||||
group
|
||||
layers
|
||||
normal
|
||||
}
|
||||
`,
|
||||
};
|
||||
@@ -36,17 +36,16 @@ export const Instances = {
|
||||
variable: "$serviceId: ID!, $duration: Duration!",
|
||||
query: `
|
||||
pods: listInstances(duration: $duration, serviceId: $serviceId) {
|
||||
id
|
||||
value: name
|
||||
label: name
|
||||
language
|
||||
instanceUUID
|
||||
layer
|
||||
attributes {
|
||||
name
|
||||
value
|
||||
}
|
||||
id
|
||||
value: name
|
||||
label: name
|
||||
language
|
||||
instanceUUID
|
||||
attributes {
|
||||
name
|
||||
value
|
||||
}
|
||||
}
|
||||
`,
|
||||
};
|
||||
export const Endpoints = {
|
||||
@@ -66,10 +65,10 @@ export const getService = {
|
||||
service: getService(serviceId: $serviceId) {
|
||||
id
|
||||
value: name
|
||||
label: name
|
||||
group
|
||||
layers
|
||||
normal
|
||||
label: name
|
||||
group
|
||||
layers
|
||||
normal
|
||||
}
|
||||
`,
|
||||
};
|
||||
@@ -79,16 +78,15 @@ export const getInstance = {
|
||||
query: `
|
||||
instance: getInstance(instanceId: $instanceId) {
|
||||
id
|
||||
value: name
|
||||
label: name
|
||||
language
|
||||
instanceUUID
|
||||
layer
|
||||
attributes {
|
||||
name
|
||||
value
|
||||
}
|
||||
value: name
|
||||
label: name
|
||||
language
|
||||
instanceUUID
|
||||
attributes {
|
||||
name
|
||||
value
|
||||
}
|
||||
}
|
||||
`,
|
||||
};
|
||||
|
||||
@@ -97,10 +95,10 @@ export const getEndpoint = {
|
||||
query: `
|
||||
endpoint: getEndpointInfo(endpointId: $endpointId) {
|
||||
id
|
||||
value: name
|
||||
label: name
|
||||
serviceId
|
||||
serviceName
|
||||
value: name
|
||||
label: name
|
||||
serviceId
|
||||
serviceName
|
||||
}
|
||||
`,
|
||||
};
|
||||
|
@@ -27,7 +27,6 @@ export const Traces = {
|
||||
isError
|
||||
traceIds
|
||||
}
|
||||
total
|
||||
}`,
|
||||
};
|
||||
|
||||
@@ -74,3 +73,14 @@ export const TraceSpans = {
|
||||
}
|
||||
`,
|
||||
};
|
||||
export const TraceTagKeys = {
|
||||
variable: "$duration: Duration!",
|
||||
query: `
|
||||
tagKeys: queryTraceTagAutocompleteKeys(duration: $duration)`,
|
||||
};
|
||||
|
||||
export const TraceTagValues = {
|
||||
variable: "$tagKey: String!, $duration: Duration!",
|
||||
query: `
|
||||
tagValues: queryTraceTagAutocompleteValues(tagKey: $tagKey, duration: $duration)`,
|
||||
};
|
||||
|
@@ -25,6 +25,8 @@ import * as log from "./query/log";
|
||||
import * as profile from "./query/profile";
|
||||
import * as alarm from "./query/alarm";
|
||||
import * as event from "./query/event";
|
||||
import * as ebpf from "./query/ebpf";
|
||||
import * as demandLog from "./query/demand-log";
|
||||
|
||||
const query: { [key: string]: string } = {
|
||||
...app,
|
||||
@@ -36,6 +38,8 @@ const query: { [key: string]: string } = {
|
||||
...profile,
|
||||
...alarm,
|
||||
...event,
|
||||
...ebpf,
|
||||
...demandLog,
|
||||
};
|
||||
class Graphql {
|
||||
private queryData = "";
|
||||
|
22
src/graphql/query/demand-log.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* 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 { queryContainers, queryStreamingLogs } from "../fragments/demand-log";
|
||||
|
||||
export const fetchContainers = `query listContainers(${queryContainers.variable}) {${queryContainers.query}}`;
|
||||
|
||||
export const fetchDemandPodLogs = `query ondemandPodLogs(${queryStreamingLogs.variable}) {${queryStreamingLogs.query}}`;
|
34
src/graphql/query/ebpf.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* 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 {
|
||||
queryCreateTaskData,
|
||||
createEBPFTask,
|
||||
queryEBPFTasks,
|
||||
queryEBPFSchedules,
|
||||
analysisEBPFResult,
|
||||
} from "../fragments/ebpf";
|
||||
|
||||
export const getCreateTaskData = `query queryCreateTaskData(${queryCreateTaskData.variable}) {${queryCreateTaskData.query}}`;
|
||||
|
||||
export const saveEBPFTask = `mutation createEBPFTask(${createEBPFTask.variable}) {${createEBPFTask.query}}`;
|
||||
|
||||
export const getEBPFTasks = `query queryEBPFTasks(${queryEBPFTasks.variable}) {${queryEBPFTasks.query}}`;
|
||||
|
||||
export const getEBPFSchedules = `query queryEBPFSchedules(${queryEBPFSchedules.variable}) {${queryEBPFSchedules.query}}`;
|
||||
|
||||
export const getEBPFResult = `query analysisEBPFResult(${analysisEBPFResult.variable}) {${analysisEBPFResult.query}}`;
|
@@ -19,9 +19,13 @@ import {
|
||||
QueryBrowserErrorLogs,
|
||||
QueryServiceLogs,
|
||||
QueryLogsByKeywords,
|
||||
LogTagValues,
|
||||
LogTagKeys,
|
||||
} from "../fragments/log";
|
||||
|
||||
export const queryBrowserErrorLogs = `query queryBrowserErrorLogs(${QueryBrowserErrorLogs.variable}) {
|
||||
${QueryBrowserErrorLogs.query}}`;
|
||||
export const queryServiceLogs = `query queryLogs(${QueryServiceLogs.variable}) {${QueryServiceLogs.query}}`;
|
||||
export const queryLogsByKeywords = `query queryLogsByKeywords {${QueryLogsByKeywords.query}}`;
|
||||
export const queryLogTagValues = `query queryTagValues(${LogTagValues.variable}) {${LogTagValues.query}}`;
|
||||
export const queryLogTagKeys = `query queryTagKeys(${LogTagKeys.variable}) {${LogTagKeys.query}}`;
|
||||
|
@@ -15,8 +15,17 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Traces, TraceSpans } from "../fragments/trace";
|
||||
import {
|
||||
Traces,
|
||||
TraceSpans,
|
||||
TraceTagKeys,
|
||||
TraceTagValues,
|
||||
} from "../fragments/trace";
|
||||
|
||||
export const queryTraces = `query queryTraces(${Traces.variable}) {${Traces.query}}`;
|
||||
|
||||
export const queryTrace = `query queryTrace(${TraceSpans.variable}) {${TraceSpans.query}}`;
|
||||
|
||||
export const queryTraceTagKeys = `query queryTraceTagKeys(${TraceTagKeys.variable}) {${TraceTagKeys.query}}`;
|
||||
|
||||
export const queryTraceTagValues = `query queryTraceTagValues(${TraceTagValues.variable}) {${TraceTagValues.query}}`;
|
||||
|
@@ -33,6 +33,9 @@ export enum Calculations {
|
||||
ConvertSeconds = "convertSeconds",
|
||||
ConvertMilliseconds = "convertMilliseconds",
|
||||
MsTos = "msTos",
|
||||
Average = "average",
|
||||
PercentageAvg = "percentageAvg",
|
||||
ApdexAvg = "apdexAvg",
|
||||
}
|
||||
export enum sizeEnum {
|
||||
XS = "XS",
|
||||
|
@@ -79,7 +79,11 @@ export function useECharts(
|
||||
if (!el || !unref(el)) {
|
||||
return;
|
||||
}
|
||||
const { width, height } = el.getBoundingClientRect();
|
||||
|
||||
if (!width || !height) {
|
||||
return;
|
||||
}
|
||||
chartInstance = echarts.init(el, t);
|
||||
const { removeEvent } = useEventListener({
|
||||
el: window,
|
||||
|
39
src/hooks/useListConfig.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { MetricQueryTypes, Calculations } from "./data";
|
||||
export function useListConfig(config: any, index: string) {
|
||||
const i = Number(index);
|
||||
const types = [
|
||||
Calculations.Average,
|
||||
Calculations.ApdexAvg,
|
||||
Calculations.PercentageAvg,
|
||||
];
|
||||
const calculation =
|
||||
config.metricConfig &&
|
||||
config.metricConfig[i] &&
|
||||
config.metricConfig[i].calculation;
|
||||
const line =
|
||||
config.metricTypes[i] === MetricQueryTypes.ReadMetricsValues &&
|
||||
!types.includes(calculation);
|
||||
const isAvg =
|
||||
config.metricTypes[i] === MetricQueryTypes.ReadMetricsValues &&
|
||||
types.includes(calculation);
|
||||
return {
|
||||
isLinear: line,
|
||||
isAvg,
|
||||
};
|
||||
}
|
@@ -150,9 +150,7 @@ export function useSourceProcessor(
|
||||
const c = (config.metricConfig && config.metricConfig[index]) || {};
|
||||
|
||||
if (type === MetricQueryTypes.ReadMetricsValues) {
|
||||
source[m] = resp.data[keys[index]].values.values.map(
|
||||
(d: { value: number }) => aggregation(d.value, c)
|
||||
);
|
||||
source[m] = calculateExp(resp.data[keys[index]].values.values, c);
|
||||
}
|
||||
if (type === MetricQueryTypes.ReadLabeledMetricsValues) {
|
||||
const resVal = Object.values(resp.data)[0] || [];
|
||||
@@ -166,7 +164,6 @@ export function useSourceProcessor(
|
||||
const values = item.values.values.map((d: { value: number }) =>
|
||||
aggregation(Number(d.value), c)
|
||||
);
|
||||
|
||||
const indexNum = labelsIdx.findIndex((d: string) => d === item.label);
|
||||
if (labels[indexNum] && indexNum > -1) {
|
||||
source[labels[indexNum]] = values;
|
||||
@@ -281,14 +278,24 @@ export function usePodsSource(
|
||||
}
|
||||
const data = pods.map((d: Instance | any, idx: number) => {
|
||||
config.metrics.map((name: string, index: number) => {
|
||||
const c = (config.metricConfig && config.metricConfig[index]) || {};
|
||||
const c: any = (config.metricConfig && config.metricConfig[index]) || {};
|
||||
const key = name + idx + index;
|
||||
if (config.metricTypes[index] === MetricQueryTypes.ReadMetricsValue) {
|
||||
d[name] = aggregation(resp.data[key], c);
|
||||
}
|
||||
if (config.metricTypes[index] === MetricQueryTypes.ReadMetricsValues) {
|
||||
d[name] = resp.data[key].values.values.map((d: { value: number }) =>
|
||||
aggregation(d.value, c)
|
||||
d[name] = {};
|
||||
if (
|
||||
[
|
||||
Calculations.Average,
|
||||
Calculations.ApdexAvg,
|
||||
Calculations.PercentageAvg,
|
||||
].includes(c.calculation)
|
||||
) {
|
||||
d[name]["avg"] = calculateExp(resp.data[key].values.values, c);
|
||||
}
|
||||
d[name]["values"] = resp.data[key].values.values.map(
|
||||
(val: { value: number }) => aggregation(val.value, c)
|
||||
);
|
||||
}
|
||||
});
|
||||
@@ -322,26 +329,59 @@ export function useQueryTopologyMetrics(metrics: string[], ids: string[]) {
|
||||
|
||||
return { queryStr, conditions };
|
||||
}
|
||||
function calculateExp(
|
||||
arr: { value: number }[],
|
||||
config: { calculation?: string }
|
||||
): (number | string)[] {
|
||||
const sum = arr
|
||||
.map((d: { value: number }) => d.value)
|
||||
.reduce((a, b) => a + b);
|
||||
let data: (number | string)[] = [];
|
||||
switch (config.calculation) {
|
||||
case Calculations.Average:
|
||||
data = [(sum / arr.length).toFixed(2)];
|
||||
break;
|
||||
case Calculations.PercentageAvg:
|
||||
data = [(sum / arr.length / 100).toFixed(2)];
|
||||
break;
|
||||
case Calculations.ApdexAvg:
|
||||
data = [(sum / arr.length / 10000).toFixed(2)];
|
||||
break;
|
||||
default:
|
||||
data = arr.map((d) => aggregation(d.value, config));
|
||||
break;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
export function aggregation(val: number, config: any): number | string {
|
||||
export function aggregation(
|
||||
val: number,
|
||||
config: { calculation?: string }
|
||||
): number | string {
|
||||
let data: number | string = Number(val);
|
||||
|
||||
switch (config.calculation) {
|
||||
case Calculations.Percentage:
|
||||
data = val / 100;
|
||||
data = (val / 100).toFixed(2);
|
||||
break;
|
||||
case Calculations.PercentageAvg:
|
||||
data = (val / 100).toFixed(2);
|
||||
break;
|
||||
case Calculations.ByteToKB:
|
||||
data = val / 1024;
|
||||
data = (val / 1024).toFixed(2);
|
||||
break;
|
||||
case Calculations.ByteToMB:
|
||||
data = val / 1024 / 1024;
|
||||
data = (val / 1024 / 1024).toFixed(2);
|
||||
break;
|
||||
case Calculations.ByteToGB:
|
||||
data = val / 1024 / 1024 / 1024;
|
||||
data = (val / 1024 / 1024 / 1024).toFixed(2);
|
||||
break;
|
||||
case Calculations.Apdex:
|
||||
data = val / 10000;
|
||||
break;
|
||||
case Calculations.ApdexAvg:
|
||||
data = val / 10000;
|
||||
break;
|
||||
case Calculations.ConvertSeconds:
|
||||
data = dayjs(val).format("YYYY-MM-DD HH:mm:ss");
|
||||
break;
|
||||
@@ -352,7 +392,7 @@ export function aggregation(val: number, config: any): number | string {
|
||||
data = data.toFixed(2);
|
||||
break;
|
||||
case Calculations.MsTos:
|
||||
data = val / 1000;
|
||||
data = (val / 1000).toFixed(2);
|
||||
break;
|
||||
default:
|
||||
data;
|
||||
|
@@ -21,19 +21,6 @@ limitations under the License. -->
|
||||
</router-view>
|
||||
</section>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ElMessage } from "element-plus";
|
||||
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||
|
||||
const appStore = useAppStoreWithOut();
|
||||
if (!appStore.utc) {
|
||||
const res = appStore.queryOAPTimeInfo();
|
||||
|
||||
if (res.errors) {
|
||||
ElMessage.error(res.errors);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.app-main {
|
||||
height: calc(100% - 40px);
|
||||
|
@@ -94,9 +94,6 @@ watch(
|
||||
}
|
||||
);
|
||||
async function getVersion() {
|
||||
if (appStore.version) {
|
||||
return;
|
||||
}
|
||||
const res = await appStore.fetchVersion();
|
||||
if (res.errors) {
|
||||
ElMessage.error(res.errors);
|
||||
|
@@ -41,7 +41,7 @@ limitations under the License. -->
|
||||
<el-icon class="menu-icons" :style="{ marginRight: '12px' }">
|
||||
<Icon size="lg" :iconName="menu.meta.icon" />
|
||||
</el-icon>
|
||||
<span :class="isCollapse ? 'collapse' : ''">
|
||||
<span class="title" :class="isCollapse ? 'collapse' : ''">
|
||||
{{ t(menu.meta.title) }}
|
||||
</span>
|
||||
</router-link>
|
||||
@@ -57,7 +57,7 @@ limitations under the License. -->
|
||||
:to="m.path"
|
||||
:exact="m.meta.exact || false"
|
||||
>
|
||||
<span>{{ t(m.meta.title) }}</span>
|
||||
<span class="title">{{ t(m.meta.title) }}</span>
|
||||
</router-link>
|
||||
</el-menu-item>
|
||||
</el-menu-item-group>
|
||||
@@ -82,7 +82,7 @@ limitations under the License. -->
|
||||
:to="menu.children[0].path"
|
||||
:exact="menu.meta.exact"
|
||||
>
|
||||
<span>{{ t(menu.meta.title) }}</span>
|
||||
<span class="title">{{ t(menu.meta.title) }}</span>
|
||||
</router-link>
|
||||
</template>
|
||||
</el-menu-item>
|
||||
@@ -109,14 +109,21 @@ import { ref } from "vue";
|
||||
import { useRouter, RouteRecordRaw } from "vue-router";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import Icon from "@/components/Icon.vue";
|
||||
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||
|
||||
const appStore = useAppStoreWithOut();
|
||||
const { t } = useI18n();
|
||||
const name = ref<any>(String(useRouter().currentRoute.value.name));
|
||||
const name = ref<string>(String(useRouter().currentRoute.value.name));
|
||||
const theme = ["VirtualMachine", "Kubernetes"].includes(name.value || "")
|
||||
? ref("light")
|
||||
: ref("black");
|
||||
const routes = ref<any>(useRouter().options.routes);
|
||||
const isCollapse = ref(false);
|
||||
const routes = ref<RouteRecordRaw[] | any>(useRouter().options.routes);
|
||||
if (/Android|webOS|iPhone|iPod|iPad|BlackBerry/i.test(navigator.userAgent)) {
|
||||
appStore.setIsMobile(true);
|
||||
} else {
|
||||
appStore.setIsMobile(false);
|
||||
}
|
||||
const isCollapse = ref(appStore.isMobile ? true : false);
|
||||
const controlMenu = () => {
|
||||
isCollapse.value = !isCollapse.value;
|
||||
};
|
||||
@@ -201,4 +208,11 @@ span.collapse {
|
||||
width: 100%;
|
||||
height: 60px;
|
||||
}
|
||||
|
||||
.title {
|
||||
display: inline-block;
|
||||
max-width: 110px;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
}
|
||||
</style>
|
||||
|
@@ -17,10 +17,12 @@
|
||||
import { createI18n } from "vue-i18n";
|
||||
import zh from "./lang/zh";
|
||||
import en from "./lang/en";
|
||||
import es from "./lang/es";
|
||||
|
||||
const messages = {
|
||||
en,
|
||||
zh,
|
||||
es,
|
||||
};
|
||||
|
||||
const savedLanguage = window.localStorage.getItem("language");
|
||||
|
@@ -111,8 +111,8 @@ const msg = {
|
||||
noRoot: "Please set a root dashboard for",
|
||||
noWidget: "Please add widgets.",
|
||||
rename: "Rename",
|
||||
deleteTitle: "Are you sure to delete this?",
|
||||
rootTitle: "Are you sure to set this?",
|
||||
deleteTitle: "Are you sure you want to delete this?",
|
||||
rootTitle: "Are you sure you want to set this?",
|
||||
selfObservability: "Self Observability",
|
||||
satellite: "Satellite",
|
||||
skyWalkingServer: "SkyWalking Server",
|
||||
@@ -131,6 +131,18 @@ const msg = {
|
||||
metricLabel: "Metric Label",
|
||||
showUnit: "Show Unit",
|
||||
noGraph: "No Graph",
|
||||
taskId: "Task ID",
|
||||
triggerType: "Trigger Type",
|
||||
targetType: "Target Type",
|
||||
ebpfTip: "Don't have a process for profiling",
|
||||
processSelect: "Click to select processes",
|
||||
container: "Container",
|
||||
limit: "Limit",
|
||||
page: "Page",
|
||||
interval: "Refresh Interval",
|
||||
pause: "Pause",
|
||||
begin: "Start",
|
||||
seconds: "Seconds",
|
||||
hourTip: "Select Hour",
|
||||
minuteTip: "Select Minute",
|
||||
secondTip: "Select Second",
|
||||
@@ -138,7 +150,7 @@ const msg = {
|
||||
yearSuffix: "Year",
|
||||
monthsHead: "Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec",
|
||||
months: "Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec",
|
||||
weeks: "Mon_Tue_Wed_Thu_Fir_Sat_Sun",
|
||||
weeks: "Mon_Tue_Wed_Thu_Fri_Sat_Sun",
|
||||
hello: "Hello",
|
||||
helloMessage: "Welcome Back, Apache SkyWalking APM System !",
|
||||
username: "Username",
|
||||
@@ -237,6 +249,10 @@ const msg = {
|
||||
defaultDepth: "Default Depth",
|
||||
traceTagsTip: `Only tags defined in the core/default/searchableTracesTags are searchable.
|
||||
Check more details on the Configuration Vocabulary page`,
|
||||
logTagsTip: `Only tags defined in the core/default/searchableLogsTags are searchable.
|
||||
Check more details on the Configuration Vocabulary page`,
|
||||
alarmTagsTip: `Only tags defined in the core/default/searchableAlarmTags are searchable.
|
||||
Check more details on the Configuration Vocabulary page`,
|
||||
tagsLink: "Configuration Vocabulary page",
|
||||
addTag: "Please input a tag",
|
||||
log: "Log",
|
||||
@@ -317,7 +333,7 @@ const msg = {
|
||||
addExcludingKeywordsOfContent: "Please input a keyword of excluding content",
|
||||
noticeTag: "Please press Enter after inputting a tag(key=value).",
|
||||
conditionNotice:
|
||||
"Notice: Please press Enter after inputting a tag, key of content, exclude key of content(key=value).",
|
||||
"Notice: Please press Enter after inputting a key of content, exclude key of content(key=value).",
|
||||
language: "Language",
|
||||
};
|
||||
export default msg;
|
||||
|
342
src/locales/lang/es.ts
Normal file
@@ -0,0 +1,342 @@
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
const msg = {
|
||||
general: "Servicio General",
|
||||
services: "Servicios",
|
||||
service: "Servicio",
|
||||
traces: "Trazas",
|
||||
metrics: "Métricas",
|
||||
serviceMesh: "Malla de Servicios",
|
||||
infrastructure: "Infraestructura",
|
||||
virtualMachine: "Máquina Virtual",
|
||||
dashboardNew: "Nuevo Panel",
|
||||
dashboardList: "Listado Paneles",
|
||||
logs: "Logs",
|
||||
events: "Eventos",
|
||||
alerts: "Alertas",
|
||||
settings: "Ajustes",
|
||||
dashboards: "Paneles",
|
||||
profiles: "Perfiles",
|
||||
database: "Base de Datos",
|
||||
serviceName: "Nombre Servicio",
|
||||
technologies: "Tecnologías",
|
||||
generalServicePanel: "Panel Servicio General",
|
||||
health: "Salud",
|
||||
groupName: "Nombre Grupo",
|
||||
topologies: "Topologías",
|
||||
dataPanel: "Plano de Datos",
|
||||
controlPanel: "Plano de Control",
|
||||
eventList: "Listado Eventos",
|
||||
newDashboard: "Crear panel nuevo",
|
||||
dashboardEdit: "Editar el panel",
|
||||
edit: "Editar",
|
||||
delete: "Eliminar",
|
||||
confirm: "Confirmar",
|
||||
layer: "Capa",
|
||||
endpoint: "Endpoint",
|
||||
instance: "Instancia",
|
||||
create: "Crear",
|
||||
loading: "Cargando",
|
||||
selectVisualization: "Visualiza tus métricas",
|
||||
visualization: "Visualizaciones",
|
||||
graphStyles: "Estilo de gráficas",
|
||||
widgetOptions: "Opciones widget",
|
||||
standardOptions: "Opciones estandar",
|
||||
max: "Máx",
|
||||
min: "Mín",
|
||||
plus: "Más",
|
||||
minus: "Menoss",
|
||||
multiply: "Multiplcar",
|
||||
divide: "Dividir",
|
||||
convertToMilliseconds: "Convertir Unix Timestamp(milisegundos)",
|
||||
convertToSeconds: "Convertir Unix Timestamp(segundos)",
|
||||
smooth: "Suabe",
|
||||
showSymbol: "Mostrar Símbolo",
|
||||
step: "Paso",
|
||||
showValues: "Mostrar Valores",
|
||||
fontSize: "Tamaño Fuente",
|
||||
showBackground: "Mostrar Fondo",
|
||||
areaOpacity: "Opacidad Área",
|
||||
editGraph: "Editar Opciones",
|
||||
dashboardName: "Selecciona Nombre del Panel",
|
||||
linkDashboard: "Nombre del panel relacionado con llamadas de la topología",
|
||||
linkServerMetrics:
|
||||
"Métricas de servidor relacionadas con llamadas de la topología",
|
||||
linkClientMetrics:
|
||||
"Métricas de cliente relacionadas con llamadas de la topología",
|
||||
nodeDashboard: "Nombre del panel relacionado con nodos de la topología",
|
||||
nodeMetrics: "Mêtricas relacionas con nodos de la topología",
|
||||
instanceDashboard: "Nombre del panel relacionado con instancias de servicio",
|
||||
endpointDashboard: "Nombre del panel relacionado con endpoints",
|
||||
callSettings: "Ajustes Llamada",
|
||||
nodeSettings: "Ajustes Nodo",
|
||||
conditions: "Condiciones",
|
||||
legendSettings: "Ajustes Leyenda",
|
||||
setLegend: "Poner Leyenda",
|
||||
backgroundColors: "Colores Fondo",
|
||||
fontColors: "Colores Fuente",
|
||||
iconTheme: "Tema Iconos",
|
||||
default: "Por Defecto",
|
||||
topSlow: "Top 5 lentos",
|
||||
topChildren: "Top 5 hijos",
|
||||
taskList: "Listado Tareas",
|
||||
sampledTraces: "Trazas Muestreadas",
|
||||
editTab: "Habilitar edición nombre pestanyas",
|
||||
label: "Nombre Servicio",
|
||||
id: "ID Servicio",
|
||||
setRoot: "Ponerlo a raíz",
|
||||
setNormal: "Ponerlo a normal",
|
||||
export: "Exportar Plantilla Panel",
|
||||
import: "Importar Plantilla Panel",
|
||||
yes: "Sí",
|
||||
no: "No",
|
||||
tableHeaderCol1: "Nombre de la primera columna de la tabla",
|
||||
tableHeaderCol2: "Nombre de la segunda columna de la tabla",
|
||||
showXAxis: "Mostrar Eje X",
|
||||
showYAxis: "Mostrar Eje Y",
|
||||
nameError: "El nombre del panel no puede ser duplicado",
|
||||
showGroup: "Mostrar Grupo",
|
||||
noRoot: "Por favor ponga la raíz del panel",
|
||||
noWidget: "Por favor añada widgets.",
|
||||
rename: "Renombrar",
|
||||
deleteTitle: "¿Está seguro que quiere eliminarlo?",
|
||||
rootTitle: "¿Está seguro que quiere establecerlo?",
|
||||
selfObservability: "Autoobservabilidad",
|
||||
satellite: "Satéllite",
|
||||
skyWalkingServer: "Servidor SkyWalking",
|
||||
functions: "Funciones",
|
||||
browser: "Navegador",
|
||||
linux: "Linux",
|
||||
editWarning: "Estás entrando en modo edición",
|
||||
viewWarning: "Estás entrando en modo visualización",
|
||||
virtualDatabase: "Base de Datos Virtual",
|
||||
reloadDashboards: "Recargar Panel",
|
||||
kubernetesService: "Servicio",
|
||||
kubernetesCluster: "Cluster",
|
||||
kubernetes: "Kubernetes",
|
||||
textUrl: "Hipervínculo de Texto",
|
||||
textAlign: "Alineación de Texto",
|
||||
metricLabel: "Etiqueta de Métrica",
|
||||
showUnit: "Mostrar Unidad",
|
||||
noGraph: "Ningún Gráfico",
|
||||
taskId: "ID Tarea",
|
||||
triggerType: "Tipo de Disparador",
|
||||
targetType: "Tipo de Objetivo",
|
||||
ebpfTip: "Le falta el proceso para perfilar",
|
||||
processSelect: "Click para seleccionar proceso",
|
||||
page: "Página",
|
||||
interval: "Intervalo de actualización",
|
||||
pause: "Pausa",
|
||||
begin: "Inicio",
|
||||
seconds: "Segundos",
|
||||
hourTip: "Seleccione Hora",
|
||||
minuteTip: "Seleccione Minuto",
|
||||
secondTip: "Seleccione Segundo",
|
||||
second: "s",
|
||||
yearSuffix: "Año",
|
||||
monthsHead: "Ene_Feb_Mar_Abr_May_Jun_Jul_Ago_Set_Oct_Nov_Dic",
|
||||
months: "Ene_Feb_Mar_Abr_May_Jun_Jul_Ago_Set_Oct_Nov_Dic",
|
||||
weeks: "Lun_Mar_Mier_Jue_Vie_Sáb_Dom",
|
||||
hello: "Hola",
|
||||
helloMessage: "Bienvenido de vuelta, Apache SkyWalking APM System !",
|
||||
username: "Usuario",
|
||||
password: "Contraseña",
|
||||
title: "Título",
|
||||
width: "Ancho",
|
||||
height: "Alto",
|
||||
dashboard: "Panel",
|
||||
topology: "Topología",
|
||||
trace: "Traza",
|
||||
alarm: "Alarmas",
|
||||
auto: "Auto",
|
||||
reload: "Recargar",
|
||||
version: "Versión",
|
||||
copy: "Copiar",
|
||||
reset: "Resetear",
|
||||
apply: "Aplicar",
|
||||
template: "Plantilla",
|
||||
cancel: "Cancelar",
|
||||
createTab: "Crear Pestanya",
|
||||
tabName: "Nombre de la Pestaña",
|
||||
detectPoint: "Detectar Punto",
|
||||
name: "Nombre",
|
||||
types: "Tipos",
|
||||
all: "Todo",
|
||||
endpoints: "Endpoints",
|
||||
cache: "Cache",
|
||||
serviceinstance: "InstanciaServicio",
|
||||
databaseaccess: "AccesoBaseDeDatos",
|
||||
servicerelation: "RelaciónServicio",
|
||||
serviceinstancerelation: "RelaciónInstanciaServicio",
|
||||
endpointrelation: "RelaciónEndpoint",
|
||||
status: "Estado",
|
||||
endpointName: "Nombre Endpoint",
|
||||
search: "Buscar",
|
||||
clear: "Limpiar",
|
||||
more: "Más",
|
||||
traceID: "ID Traza",
|
||||
range: "Rango",
|
||||
timeRange: "Rango de Tiempo",
|
||||
duration: "Duración",
|
||||
startTime: "Hora Inicio",
|
||||
start: "Incio",
|
||||
spans: "Lapso",
|
||||
spanInfo: "Info Lapso",
|
||||
spanType: "Tipo de Lapso",
|
||||
time: "Tiempo",
|
||||
tags: "Etiquetas",
|
||||
component: "Componente",
|
||||
table: "Tabla",
|
||||
list: "Lista",
|
||||
tree: "Árbol",
|
||||
filterScope: "Alcance de Filtro",
|
||||
searchKeyword: "Palabra Clave",
|
||||
quarterHourCutTip: "Últimos 15 mins",
|
||||
halfHourCutTip: "Últimos 30 mins",
|
||||
hourCutTip: "Última 1 hora",
|
||||
dayCutTip: "Último 1 día",
|
||||
weekCutTip: "Última 1 semana",
|
||||
monthCutTip: "Última 1 mes",
|
||||
serverZone: "Zona Horaria Servidor OAP",
|
||||
exportImage: "Exportar imagen",
|
||||
object: "Objecto",
|
||||
profile: "Perfil",
|
||||
newTask: "Nueva Tarea",
|
||||
monitorTime: "Tiempo Monitorización",
|
||||
monitorDuration: "Duración Monitorización",
|
||||
minThreshold: "Mínn Umbral Duración",
|
||||
dumpPeriod: "Volcar Periodo",
|
||||
createTask: "Crear Tarea",
|
||||
maxSamplingCount: "Máx Cantidad Mostreo",
|
||||
analyze: "Analizar",
|
||||
noData: "Ningún Dato",
|
||||
taskInfo: "Información Tarea",
|
||||
task: "Tarea",
|
||||
operationType: "Tipo Operación",
|
||||
operationTime: "Tiempo Operación",
|
||||
taskView: "Ver Tarea",
|
||||
includeChildren: "Incluir Hijos",
|
||||
excludeChildren: "Excluir Hijos",
|
||||
view: "Ver",
|
||||
timeTips: "Intervalo de tiempo no puede excedir 60 dias",
|
||||
entityType: "Tipo Entidad",
|
||||
maxItemNum: "Máx número artículos",
|
||||
unknownMetrics: "Métrica desconocida",
|
||||
labels: "Etiquetas",
|
||||
aggregation: "Cálculo",
|
||||
unit: "Unidad",
|
||||
labelsIndex: "Subíndice Etiqueta",
|
||||
group: "Grupo Servicio",
|
||||
browserView: "Navegador",
|
||||
sortOrder: "Orden de clasificación",
|
||||
chartType: "Tipo Gráfico",
|
||||
currentDepth: "Profundidad actual",
|
||||
showDepth: "Mostrar Selector Profundidad",
|
||||
defaultDepth: "Profundidad Por Defecto",
|
||||
traceTagsTip: `Solamente etiquetas definidas en core/default/searchableTracesTags pueden ser buscadas.
|
||||
Más información en la página de Vocabulario de Configuración`,
|
||||
logTagsTip: `Solamente etiquetas definidas en core/default/searchableLogsTags pueden ser buscadas.
|
||||
Más información en la página de Vocabulario de Configuración`,
|
||||
alarmTagsTip: `Solamente etiquetas definidas en core/default/searchableAlarmTags pueden ser buscadas.
|
||||
Más información en la página de Vocabulario de Configuración`,
|
||||
tagsLink: "Página de Vocabulario de Configuración",
|
||||
addTag: "Por favor introduzca una etiqueta",
|
||||
log: "Registro de Datos",
|
||||
logCategory: "Categoría Registro de Datos",
|
||||
errorCatalog: "Catálogo de Errores",
|
||||
logDetail: "Detalle Registro de Datos",
|
||||
timeReload: "Aviso: El intervalo de tiempo tiene que ser mayor que 0",
|
||||
errorInfo: "Info Error",
|
||||
stack: "Pila",
|
||||
serviceVersion: "Versión Servicio",
|
||||
errorPage: "Página de Error",
|
||||
category: "Categoría",
|
||||
grade: "Grado",
|
||||
relatedTraceLogs: "Registro de Datos Relacionados",
|
||||
setConditions: "Más Condiciones",
|
||||
metricName: "Seleccionar Nombre Métrica",
|
||||
keywordsOfContent: "Claves de Contenido",
|
||||
excludingKeywordsOfContent: "Excluir Claves de Contenido",
|
||||
return: "Volver",
|
||||
isError: "Error",
|
||||
contentType: "Tipo de Contenido",
|
||||
content: "Contenido",
|
||||
viewLogs: "Ver Registro de Datos",
|
||||
logsTagsTip: `Solamente etiquetas definidas en core/default/searchableLogsTags pueden ser buscadas.
|
||||
Más información en la página de Vocabulario de Configuración`,
|
||||
keywordsOfContentLogTips:
|
||||
"El almacenamiento actual del servidor SkyWalking OAP no lo soporta.",
|
||||
setEvent: "Establecer Evento",
|
||||
viewAttributes: "Ver",
|
||||
serviceEvents: "Eventos Servico",
|
||||
select: "Seleccionar",
|
||||
eventID: "ID Evento",
|
||||
eventName: "Nombre Evento",
|
||||
endTime: "Hora Finalización",
|
||||
instanceEvents: "Eventos Instancia",
|
||||
endpointEvents: "Eventos Endpoint",
|
||||
enableEvents: "Habilitar Eventos",
|
||||
disableEvents: "Deshabilitar Eventos",
|
||||
eventSeries: "Serie de Eventos",
|
||||
eventsType: "Tipo de Evento",
|
||||
eventsMessage: "Mensaje del Evento",
|
||||
eventsParameters: "Parámetro del Evento",
|
||||
eventDetail: "Detalle del Evento",
|
||||
value: "Valor",
|
||||
show: "Mostrar",
|
||||
hide: "Oculatr",
|
||||
statistics: "Estadísticas",
|
||||
message: "Mensaje",
|
||||
tooltipsContent: "Contenido de Información de Herramienta",
|
||||
alarmDetail: "Detalle Alarma",
|
||||
scope: "Alcance",
|
||||
destService: "Servicio Destinación",
|
||||
destServiceInstance: "Instancia Servicio Destinación",
|
||||
destEndpoint: "Endpoint Destinación",
|
||||
eventSource: "Fuente Envento",
|
||||
modalTitle: "Inspección",
|
||||
selectRedirectPage:
|
||||
"Quiere inspeccionar las Trazas or Registros de datos del servicio %s?",
|
||||
logAnalysis: "Lenguaje de Análisis de Registro de Datos",
|
||||
logDataBody: "Contenido del Registro de Datos",
|
||||
addType: "Por favor introduzca un tipo",
|
||||
traceContext: "Registro de datos con contexto de traza",
|
||||
traceSegmentId: "ID Segmento Traza",
|
||||
spanId: "ID Lapso",
|
||||
inputTraceSegmentId: "Por favor introduzca el ID del segmento de la traza",
|
||||
inputSpanId: "Por favor introduzca el ID del lapso",
|
||||
inputTraceId: "Por favor introduzca el ID de la traza",
|
||||
dsl: "Entrada de guión para LAL",
|
||||
logContentType: "Tipo del registro de datos",
|
||||
logRespContent: "Contenido Registro de Datos",
|
||||
analysis: "Análisis",
|
||||
waitLoading: "Cargando",
|
||||
dslEmpty: "Entrada de guión de LAL no puede estar vacio",
|
||||
logContentEmpty: "El contenido del registro de datos no puede estar vacio.",
|
||||
debug: "Debugar",
|
||||
addTraceID: "Por favor introduzca el ID de la traza",
|
||||
addTags: "Por favor introduzaca una etiqueta",
|
||||
addKeywordsOfContent: "Por favor introduzca una clave de contenido",
|
||||
addExcludingKeywordsOfContent:
|
||||
"Por favor introduzca una clave excluyente de contenido",
|
||||
noticeTag:
|
||||
"Por favor presione Intro después de introducir una etiqueta(clave=valor).",
|
||||
conditionNotice:
|
||||
"Aviso: Por favor presione Intro después de introducir una clave de contenido, excluir clave de contenido(clave=valor).",
|
||||
language: "Lenguaje",
|
||||
};
|
||||
export default msg;
|
@@ -129,6 +129,18 @@ const msg = {
|
||||
metricLabel: "指标标签",
|
||||
showUnit: "显示单位",
|
||||
noGraph: "无图表",
|
||||
taskId: "任务ID",
|
||||
triggerType: "触发类型",
|
||||
targetType: "目标类型",
|
||||
processSelect: "点击选择进程",
|
||||
ebpfTip: "没有进程可以分析",
|
||||
container: "容器",
|
||||
limit: "范围",
|
||||
page: "页面",
|
||||
interval: "刷新间隔时间",
|
||||
pause: "暂停",
|
||||
begin: "开始",
|
||||
seconds: "秒",
|
||||
hourTip: "选择小时",
|
||||
minuteTip: "选择分钟",
|
||||
secondTip: "选择秒数",
|
||||
@@ -238,6 +250,10 @@ const msg = {
|
||||
defaultDepth: "默认深度",
|
||||
traceTagsTip:
|
||||
"只有core/default/searchableTracesTags中定义的标记才可搜索。查看配置词汇表页面上的更多详细信息。",
|
||||
logTagsTip:
|
||||
"只有core/default/searchableTracesTags中定义的标记才可搜索。查看配置词汇表页面上的更多详细信息。",
|
||||
alarmTagsTip:
|
||||
"只有core/default/searchableTracesTags中定义的标记才可搜索。查看配置词汇表页面上的更多详细信息。",
|
||||
tagsLink: "配置词汇页",
|
||||
addTag: "请添加标签",
|
||||
logCategory: "日志类别",
|
||||
@@ -318,7 +334,7 @@ const msg = {
|
||||
addExcludingKeywordsOfContent: "请输入一个内容不包含的关键词",
|
||||
noticeTag: "请输入一个标签(key=value)之后回车",
|
||||
conditionNotice:
|
||||
"请输入一个标签、内容关键词或者内容不包含的关键词(key=value)之后回车",
|
||||
"请输入一个内容关键词或者内容不包含的关键词(key=value)之后回车",
|
||||
language: "语言",
|
||||
};
|
||||
export default msg;
|
||||
|
14
src/main.ts
@@ -20,14 +20,18 @@ import router from "./router";
|
||||
import { store } from "./store";
|
||||
import components from "@/components";
|
||||
import i18n from "./locales";
|
||||
import "element-plus/dist/index.css";
|
||||
import "./styles/index.scss";
|
||||
import ElementPlus from "element-plus";
|
||||
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||
import "./styles/index.ts";
|
||||
|
||||
const app = createApp(App);
|
||||
const appStore = useAppStoreWithOut();
|
||||
|
||||
app.use(ElementPlus, { size: "small", zIndex: 3000 });
|
||||
app.use(components);
|
||||
app.use(i18n);
|
||||
app.use(store);
|
||||
app.use(router).mount("#app");
|
||||
mountApp();
|
||||
|
||||
async function mountApp() {
|
||||
await appStore.queryOAPTimeInfo();
|
||||
app.use(router).mount("#app");
|
||||
}
|
||||
|
@@ -33,6 +33,7 @@ interface AppState {
|
||||
autoRefresh: boolean;
|
||||
pageTitle: string;
|
||||
version: string;
|
||||
isMobile: boolean;
|
||||
}
|
||||
|
||||
export const appStore = defineStore({
|
||||
@@ -51,6 +52,7 @@ export const appStore = defineStore({
|
||||
autoRefresh: false,
|
||||
pageTitle: "",
|
||||
version: "",
|
||||
isMobile: false,
|
||||
}),
|
||||
getters: {
|
||||
duration(): Duration {
|
||||
@@ -88,12 +90,9 @@ export const appStore = defineStore({
|
||||
this.duration.start.getMonth());
|
||||
break;
|
||||
}
|
||||
const utcArr = this.utc.split(":");
|
||||
const utcHour = isNaN(Number(utcArr[0])) ? 0 : Number(utcArr[0]);
|
||||
const utcMin = isNaN(Number(utcArr[1])) ? 0 : Number(utcArr[1]);
|
||||
const utcSpace =
|
||||
(utcHour + new Date().getTimezoneOffset() / 60) * 3600000 +
|
||||
utcMin * 60000;
|
||||
(this.utcHour + new Date().getTimezoneOffset() / 60) * 3600000 +
|
||||
this.utcMin * 60000;
|
||||
const startUnix: number = this.duration.start.getTime();
|
||||
const endUnix: number = this.duration.end.getTime();
|
||||
const timeIntervals: string[] = [];
|
||||
@@ -124,6 +123,9 @@ export const appStore = defineStore({
|
||||
this.utcHour = utcHour;
|
||||
this.utc = `${utcHour}:${utcMin}`;
|
||||
},
|
||||
setIsMobile(mode: boolean) {
|
||||
this.isMobile = mode;
|
||||
},
|
||||
setEventStack(funcs: (() => void)[]): void {
|
||||
this.eventStack = funcs;
|
||||
},
|
||||
@@ -155,6 +157,10 @@ export const appStore = defineStore({
|
||||
}
|
||||
this.utc = res.data.data.getTimeInfo.timezone / 100 + ":0";
|
||||
|
||||
const utcArr = this.utc.split(":");
|
||||
this.utcHour = isNaN(Number(utcArr[0])) ? 0 : Number(utcArr[0]);
|
||||
this.utcMin = isNaN(Number(utcArr[1])) ? 0 : Number(utcArr[1]);
|
||||
|
||||
return res.data;
|
||||
},
|
||||
async fetchVersion(): Promise<void> {
|
||||
|
@@ -20,10 +20,8 @@ import { LayoutConfig } from "@/types/dashboard";
|
||||
import graphql from "@/graphql";
|
||||
import query from "@/graphql/fetch";
|
||||
import { DashboardItem } from "@/types/dashboard";
|
||||
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||
import { useSelectorStore } from "@/store/modules/selectors";
|
||||
import { NewControl, TextConfig } from "../data";
|
||||
import { Duration } from "@/types/app";
|
||||
import { AxiosResponse } from "axios";
|
||||
import { ElMessage } from "element-plus";
|
||||
import { useI18n } from "vue-i18n";
|
||||
@@ -35,7 +33,6 @@ interface DashboardState {
|
||||
entity: string;
|
||||
layerId: string;
|
||||
activedGridItem: string;
|
||||
durationTime: Duration;
|
||||
selectorStore: any;
|
||||
showTopology: boolean;
|
||||
currentTabItems: LayoutConfig[];
|
||||
@@ -53,7 +50,6 @@ export const dashboardStore = defineStore({
|
||||
entity: "",
|
||||
layerId: "",
|
||||
activedGridItem: "",
|
||||
durationTime: useAppStoreWithOut().durationTime,
|
||||
selectorStore: useSelectorStore(),
|
||||
showTopology: false,
|
||||
currentTabItems: [],
|
||||
@@ -114,7 +110,13 @@ export const dashboardStore = defineStore({
|
||||
: 3,
|
||||
};
|
||||
}
|
||||
if (type === "Trace" || type === "Profile" || type === "Log") {
|
||||
if (
|
||||
type === "Trace" ||
|
||||
type === "Profile" ||
|
||||
type === "Log" ||
|
||||
type === "Ebpf" ||
|
||||
type === "DemandLog"
|
||||
) {
|
||||
newItem.h = 36;
|
||||
}
|
||||
if (type === "Text") {
|
||||
@@ -169,7 +171,13 @@ export const dashboardStore = defineStore({
|
||||
showDepth: true,
|
||||
};
|
||||
}
|
||||
if (type === "Trace" || type === "Profile" || type === "Log") {
|
||||
if (
|
||||
type === "Trace" ||
|
||||
type === "Profile" ||
|
||||
type === "Log" ||
|
||||
type === "DemandLog" ||
|
||||
type === "Ebpf"
|
||||
) {
|
||||
newItem.h = 32;
|
||||
}
|
||||
if (type === "Text") {
|
||||
|
126
src/store/modules/demand-log.ts
Normal file
@@ -0,0 +1,126 @@
|
||||
/**
|
||||
* 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 { Instance } from "@/types/selector";
|
||||
import { store } from "@/store";
|
||||
import graphql from "@/graphql";
|
||||
import { AxiosResponse } from "axios";
|
||||
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||
import { useSelectorStore } from "@/store/modules/selectors";
|
||||
import { Conditions, Log } from "@/types/demand-log";
|
||||
|
||||
interface DemandLogState {
|
||||
containers: Instance[];
|
||||
instances: Instance[];
|
||||
conditions: Conditions;
|
||||
selectorStore: any;
|
||||
logs: Log[];
|
||||
loadLogs: boolean;
|
||||
message: string;
|
||||
total: number;
|
||||
}
|
||||
|
||||
export const demandLogStore = defineStore({
|
||||
id: "demandLog",
|
||||
state: (): DemandLogState => ({
|
||||
containers: [{ label: "", value: "" }],
|
||||
instances: [{ value: "", label: "" }],
|
||||
conditions: {
|
||||
container: "",
|
||||
serviceInstanceId: "",
|
||||
duration: useAppStoreWithOut().durationTime,
|
||||
},
|
||||
selectorStore: useSelectorStore(),
|
||||
logs: [],
|
||||
loadLogs: false,
|
||||
message: "",
|
||||
total: 0,
|
||||
}),
|
||||
actions: {
|
||||
setLogCondition(data: Conditions) {
|
||||
this.conditions = { ...this.conditions, ...data };
|
||||
},
|
||||
setLogs(logs: Log[], message?: string) {
|
||||
this.logs = logs;
|
||||
this.message = message || "";
|
||||
},
|
||||
async getInstances(id: string) {
|
||||
const serviceId = this.selectorStore.currentService
|
||||
? this.selectorStore.currentService.id
|
||||
: id;
|
||||
const res: AxiosResponse = await graphql.query("queryInstances").params({
|
||||
serviceId,
|
||||
duration: useAppStoreWithOut().durationTime,
|
||||
});
|
||||
|
||||
if (res.data.errors) {
|
||||
return res.data;
|
||||
}
|
||||
this.instances = res.data.data.pods || [];
|
||||
return res.data;
|
||||
},
|
||||
async getContainers(serviceInstanceId: string) {
|
||||
if (!serviceInstanceId) {
|
||||
return new Promise((resolve) =>
|
||||
resolve({ errors: "No service instance" })
|
||||
);
|
||||
}
|
||||
const condition = {
|
||||
serviceInstanceId,
|
||||
};
|
||||
const res: AxiosResponse = await graphql
|
||||
.query("fetchContainers")
|
||||
.params({ condition });
|
||||
|
||||
if (res.data.errors) {
|
||||
return res.data;
|
||||
}
|
||||
if (res.data.data.containers.errorReason) {
|
||||
this.containers = [{ label: "", value: "" }];
|
||||
return res.data;
|
||||
}
|
||||
this.containers = res.data.data.containers.containers.map((d: string) => {
|
||||
return { label: d, value: d };
|
||||
});
|
||||
return res.data;
|
||||
},
|
||||
async getDemandLogs() {
|
||||
this.loadLogs = true;
|
||||
const res: AxiosResponse = await graphql
|
||||
.query("fetchDemandPodLogs")
|
||||
.params({ condition: this.conditions });
|
||||
this.loadLogs = false;
|
||||
if (res.data.errors) {
|
||||
return res.data;
|
||||
}
|
||||
if (res.data.data.logs.errorReason) {
|
||||
this.setLogs("", res.data.data.logs.errorReason);
|
||||
return res.data;
|
||||
}
|
||||
this.total = res.data.data.logs.logs.length;
|
||||
const logs = res.data.data.logs.logs
|
||||
.map((d: Log) => d.content)
|
||||
.join("\n");
|
||||
this.setLogs(logs);
|
||||
return res.data;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export function useDemandLogStore(): any {
|
||||
return demandLogStore(store);
|
||||
}
|
169
src/store/modules/ebpf.ts
Normal file
@@ -0,0 +1,169 @@
|
||||
/**
|
||||
* 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 { Option } from "@/types/app";
|
||||
import {
|
||||
EBPFTaskCreationRequest,
|
||||
EBPFProfilingSchedule,
|
||||
EBPFTaskList,
|
||||
AnalyzationTrees,
|
||||
} from "@/types/ebpf";
|
||||
import { store } from "@/store";
|
||||
import graphql from "@/graphql";
|
||||
import { AxiosResponse } from "axios";
|
||||
|
||||
interface EbpfStore {
|
||||
taskList: EBPFTaskList[];
|
||||
eBPFSchedules: EBPFProfilingSchedule[];
|
||||
currentSchedule: EBPFProfilingSchedule | Record<string, never>;
|
||||
analyzeTrees: AnalyzationTrees[];
|
||||
labels: Option[];
|
||||
couldProfiling: boolean;
|
||||
tip: string;
|
||||
selectedTask: Recordable<EBPFTaskList>;
|
||||
aggregateType: string;
|
||||
}
|
||||
|
||||
export const ebpfStore = defineStore({
|
||||
id: "eBPF",
|
||||
state: (): EbpfStore => ({
|
||||
taskList: [],
|
||||
eBPFSchedules: [],
|
||||
currentSchedule: {},
|
||||
analyzeTrees: [],
|
||||
labels: [{ value: "", label: "" }],
|
||||
couldProfiling: false,
|
||||
tip: "",
|
||||
selectedTask: {},
|
||||
aggregateType: "COUNT",
|
||||
}),
|
||||
actions: {
|
||||
setSelectedTask(task: EBPFTaskList) {
|
||||
this.selectedTask = task;
|
||||
},
|
||||
setCurrentSchedule(s: EBPFProfilingSchedule) {
|
||||
this.currentSchedule = s;
|
||||
},
|
||||
setAnalyzeTrees(tree: AnalyzationTrees[]) {
|
||||
this.analyzeTrees = tree;
|
||||
},
|
||||
async getCreateTaskData(serviceId: string) {
|
||||
const res: AxiosResponse = await graphql
|
||||
.query("getCreateTaskData")
|
||||
.params({ serviceId });
|
||||
|
||||
if (res.data.errors) {
|
||||
return res.data;
|
||||
}
|
||||
const json = res.data.data.createTaskData;
|
||||
this.couldProfiling = json.couldProfiling || false;
|
||||
this.labels = json.processLabels.map((d: string) => {
|
||||
return { label: d, value: d };
|
||||
});
|
||||
return res.data;
|
||||
},
|
||||
async createTask(param: EBPFTaskCreationRequest) {
|
||||
const res: AxiosResponse = await graphql
|
||||
.query("saveEBPFTask")
|
||||
.params({ request: param });
|
||||
|
||||
if (res.data.errors) {
|
||||
return res.data;
|
||||
}
|
||||
this.getTaskList(param.serviceId);
|
||||
return res.data;
|
||||
},
|
||||
async getTaskList(serviceId: string) {
|
||||
if (!serviceId) {
|
||||
return new Promise((resolve) => resolve({}));
|
||||
}
|
||||
const res: AxiosResponse = await graphql
|
||||
.query("getEBPFTasks")
|
||||
.params({ serviceId });
|
||||
|
||||
this.tip = "";
|
||||
if (res.data.errors) {
|
||||
return res.data;
|
||||
}
|
||||
this.taskList = res.data.data.queryEBPFTasks || [];
|
||||
if (!this.taskList.length) {
|
||||
return res.data;
|
||||
}
|
||||
this.getEBPFSchedules({ taskId: this.taskList[0].taskId });
|
||||
return res.data;
|
||||
},
|
||||
async getEBPFSchedules(params: { taskId: string }) {
|
||||
if (!params.taskId) {
|
||||
return new Promise((resolve) => resolve({}));
|
||||
}
|
||||
const res: AxiosResponse = await graphql
|
||||
.query("getEBPFSchedules")
|
||||
.params({ ...params });
|
||||
|
||||
if (res.data.errors) {
|
||||
this.eBPFSchedules = [];
|
||||
return res.data;
|
||||
}
|
||||
this.tip = "";
|
||||
const { eBPFSchedules } = res.data.data;
|
||||
|
||||
this.eBPFSchedules = eBPFSchedules;
|
||||
if (!eBPFSchedules.length) {
|
||||
this.eBPFSchedules = [];
|
||||
this.analyzeTrees = [];
|
||||
}
|
||||
return res.data;
|
||||
},
|
||||
async getEBPFAnalyze(params: {
|
||||
scheduleIdList: string[];
|
||||
timeRanges: Array<{ start: number; end: number }>;
|
||||
aggregateType: string;
|
||||
}) {
|
||||
this.aggregateType = params.aggregateType;
|
||||
if (!params.scheduleIdList.length) {
|
||||
return new Promise((resolve) => resolve({}));
|
||||
}
|
||||
if (!params.timeRanges.length) {
|
||||
return new Promise((resolve) => resolve({}));
|
||||
}
|
||||
const res: AxiosResponse = await graphql
|
||||
.query("getEBPFResult")
|
||||
.params(params);
|
||||
|
||||
if (res.data.errors) {
|
||||
this.analyzeTrees = [];
|
||||
return res.data;
|
||||
}
|
||||
const { analysisEBPFResult } = res.data.data;
|
||||
this.tip = analysisEBPFResult.tip;
|
||||
if (!analysisEBPFResult) {
|
||||
this.analyzeTrees = [];
|
||||
return res.data;
|
||||
}
|
||||
if (analysisEBPFResult.tip) {
|
||||
this.analyzeTrees = [];
|
||||
return res.data;
|
||||
}
|
||||
this.analyzeTrees = analysisEBPFResult.trees;
|
||||
return res.data;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export function useEbpfStore(): any {
|
||||
return ebpfStore(store);
|
||||
}
|
@@ -25,7 +25,6 @@ import { useAppStoreWithOut } from "@/store/modules/app";
|
||||
interface eventState {
|
||||
loading: boolean;
|
||||
events: Event[];
|
||||
total: number;
|
||||
services: Service[];
|
||||
instances: Instance[];
|
||||
endpoints: Endpoint[];
|
||||
@@ -37,13 +36,11 @@ export const eventStore = defineStore({
|
||||
state: (): eventState => ({
|
||||
loading: false,
|
||||
events: [],
|
||||
total: 0,
|
||||
services: [{ value: "", label: "All" }],
|
||||
instances: [{ value: "", label: "All" }],
|
||||
endpoints: [{ value: "", label: "All" }],
|
||||
condition: {
|
||||
time: useAppStoreWithOut().durationTime,
|
||||
paging: { pageNum: 1, pageSize: 15, needTotal: true },
|
||||
paging: { pageNum: 1, pageSize: 15 },
|
||||
},
|
||||
}),
|
||||
actions: {
|
||||
@@ -94,9 +91,12 @@ export const eventStore = defineStore({
|
||||
},
|
||||
async getEvents() {
|
||||
this.loading = true;
|
||||
const res: AxiosResponse = await graphql
|
||||
.query("queryEvents")
|
||||
.params({ condition: this.condition });
|
||||
const res: AxiosResponse = await graphql.query("queryEvents").params({
|
||||
condition: {
|
||||
...this.condition,
|
||||
time: useAppStoreWithOut().durationTime,
|
||||
},
|
||||
});
|
||||
this.loading = false;
|
||||
if (res.data.errors) {
|
||||
return res.data;
|
||||
@@ -115,7 +115,6 @@ export const eventStore = defineStore({
|
||||
return item;
|
||||
}
|
||||
);
|
||||
this.total = res.data.data.fetchEvents.total;
|
||||
}
|
||||
return res.data;
|
||||
},
|
||||
|
@@ -15,7 +15,6 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { defineStore } from "pinia";
|
||||
import { Duration } from "@/types/app";
|
||||
import { Instance, Endpoint, Service } from "@/types/selector";
|
||||
import { store } from "@/store";
|
||||
import graphql from "@/graphql";
|
||||
@@ -29,11 +28,9 @@ interface LogState {
|
||||
instances: Instance[];
|
||||
endpoints: Endpoint[];
|
||||
conditions: any;
|
||||
durationTime: Duration;
|
||||
selectorStore: any;
|
||||
supportQueryLogsByKeywords: boolean;
|
||||
logs: any[];
|
||||
logsTotal: number;
|
||||
loadLogs: boolean;
|
||||
}
|
||||
|
||||
@@ -45,13 +42,11 @@ export const logStore = defineStore({
|
||||
endpoints: [{ value: "0", label: "All" }],
|
||||
conditions: {
|
||||
queryDuration: useAppStoreWithOut().durationTime,
|
||||
paging: { pageNum: 1, pageSize: 15, needTotal: true },
|
||||
paging: { pageNum: 1, pageSize: 15 },
|
||||
},
|
||||
supportQueryLogsByKeywords: true,
|
||||
durationTime: useAppStoreWithOut().durationTime,
|
||||
selectorStore: useSelectorStore(),
|
||||
logs: [],
|
||||
logsTotal: 0,
|
||||
loadLogs: false,
|
||||
}),
|
||||
actions: {
|
||||
@@ -74,7 +69,7 @@ export const logStore = defineStore({
|
||||
: id;
|
||||
const res: AxiosResponse = await graphql.query("queryInstances").params({
|
||||
serviceId,
|
||||
duration: this.durationTime,
|
||||
duration: useAppStoreWithOut().durationTime,
|
||||
});
|
||||
|
||||
if (res.data.errors) {
|
||||
@@ -92,7 +87,7 @@ export const logStore = defineStore({
|
||||
: id;
|
||||
const res: AxiosResponse = await graphql.query("queryEndpoints").params({
|
||||
serviceId,
|
||||
duration: this.durationTime,
|
||||
duration: useAppStoreWithOut().durationTime,
|
||||
keyword: keyword || "",
|
||||
});
|
||||
if (res.data.errors) {
|
||||
@@ -134,7 +129,6 @@ export const logStore = defineStore({
|
||||
}
|
||||
|
||||
this.logs = res.data.data.queryLogs.logs;
|
||||
this.logsTotal = res.data.data.queryLogs.total;
|
||||
return res.data;
|
||||
},
|
||||
async getBrowserLogs() {
|
||||
@@ -148,7 +142,20 @@ export const logStore = defineStore({
|
||||
return res.data;
|
||||
}
|
||||
this.logs = res.data.data.queryBrowserErrorLogs.logs;
|
||||
this.logsTotal = res.data.data.queryBrowserErrorLogs.total;
|
||||
return res.data;
|
||||
},
|
||||
async getLogTagKeys() {
|
||||
const res: AxiosResponse = await graphql
|
||||
.query("queryLogTagKeys")
|
||||
.params({ duration: useAppStoreWithOut().durationTime });
|
||||
|
||||
return res.data;
|
||||
},
|
||||
async getLogTagValues(tagKey: string) {
|
||||
const res: AxiosResponse = await graphql
|
||||
.query("queryLogTagValues")
|
||||
.params({ tagKey, duration: useAppStoreWithOut().durationTime });
|
||||
|
||||
return res.data;
|
||||
},
|
||||
},
|
||||
|
@@ -15,8 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { defineStore } from "pinia";
|
||||
import { Duration } from "@/types/app";
|
||||
import { Service } from "@/types/selector";
|
||||
import { Endpoint } from "@/types/selector";
|
||||
import {
|
||||
TaskListItem,
|
||||
SegmentSpan,
|
||||
@@ -31,8 +30,8 @@ import { AxiosResponse } from "axios";
|
||||
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||
|
||||
interface ProfileState {
|
||||
services: Service[];
|
||||
durationTime: Duration;
|
||||
endpoints: Endpoint[];
|
||||
taskEndpoints: Endpoint[];
|
||||
condition: { serviceId: string; endpointName: string };
|
||||
taskList: TaskListItem[];
|
||||
segmentList: Trace[];
|
||||
@@ -47,8 +46,8 @@ interface ProfileState {
|
||||
export const profileStore = defineStore({
|
||||
id: "profile",
|
||||
state: (): ProfileState => ({
|
||||
services: [{ value: "0", label: "All" }],
|
||||
durationTime: useAppStoreWithOut().durationTime,
|
||||
endpoints: [{ value: "", label: "All" }],
|
||||
taskEndpoints: [{ value: "", label: "All" }],
|
||||
condition: { serviceId: "", endpointName: "" },
|
||||
taskList: [],
|
||||
segmentList: [],
|
||||
@@ -75,14 +74,28 @@ export const profileStore = defineStore({
|
||||
setHighlightTop() {
|
||||
this.highlightTop = !this.highlightTop;
|
||||
},
|
||||
async getServices(layer: string) {
|
||||
const res: AxiosResponse = await graphql.query("queryServices").params({
|
||||
layer,
|
||||
async getEndpoints(serviceId: string, keyword?: string) {
|
||||
const res: AxiosResponse = await graphql.query("queryEndpoints").params({
|
||||
serviceId,
|
||||
duration: useAppStoreWithOut().durationTime,
|
||||
keyword: keyword || "",
|
||||
});
|
||||
if (res.data.errors) {
|
||||
return res.data;
|
||||
}
|
||||
this.services = res.data.data.services;
|
||||
this.endpoints = [{ value: "", label: "All" }, ...res.data.data.pods];
|
||||
return res.data;
|
||||
},
|
||||
async getTaskEndpoints(serviceId: string, keyword?: string) {
|
||||
const res: AxiosResponse = await graphql.query("queryEndpoints").params({
|
||||
serviceId,
|
||||
duration: useAppStoreWithOut().durationTime,
|
||||
keyword: keyword || "",
|
||||
});
|
||||
if (res.data.errors) {
|
||||
return res.data;
|
||||
}
|
||||
this.taskEndpoints = [{ value: "", label: "All" }, ...res.data.data.pods];
|
||||
return res.data;
|
||||
},
|
||||
async getTaskList() {
|
||||
@@ -106,6 +119,9 @@ export const profileStore = defineStore({
|
||||
return res.data;
|
||||
},
|
||||
async getSegmentList(params: { taskID: string }) {
|
||||
if (!params.taskID) {
|
||||
return new Promise((resolve) => resolve({}));
|
||||
}
|
||||
const res: AxiosResponse = await graphql
|
||||
.query("getProfileTaskSegmentList")
|
||||
.params(params);
|
||||
@@ -132,6 +148,9 @@ export const profileStore = defineStore({
|
||||
return res.data;
|
||||
},
|
||||
async getSegmentSpans(params: { segmentId: string }) {
|
||||
if (!params.segmentId) {
|
||||
return new Promise((resolve) => resolve({}));
|
||||
}
|
||||
const res: AxiosResponse = await graphql
|
||||
.query("queryProfileSegment")
|
||||
.params(params);
|
||||
@@ -145,7 +164,13 @@ export const profileStore = defineStore({
|
||||
this.analyzeTrees = [];
|
||||
return res.data;
|
||||
}
|
||||
this.segmentSpans = segment.spans;
|
||||
this.segmentSpans = segment.spans.map((d: SegmentSpan) => {
|
||||
return {
|
||||
...d,
|
||||
segmentId: this.currentSegment.segmentId,
|
||||
traceId: this.currentSegment.traceIds[0],
|
||||
};
|
||||
});
|
||||
if (!(segment.spans && segment.spans.length)) {
|
||||
this.analyzeTrees = [];
|
||||
return res.data;
|
||||
@@ -158,6 +183,12 @@ export const profileStore = defineStore({
|
||||
segmentId: string;
|
||||
timeRanges: Array<{ start: number; end: number }>;
|
||||
}) {
|
||||
if (!params.segmentId) {
|
||||
return new Promise((resolve) => resolve({}));
|
||||
}
|
||||
if (!params.timeRanges.length) {
|
||||
return new Promise((resolve) => resolve({}));
|
||||
}
|
||||
const res: AxiosResponse = await graphql
|
||||
.query("getProfileAnalyze")
|
||||
.params(params);
|
||||
|
@@ -15,13 +15,11 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { defineStore } from "pinia";
|
||||
import { Duration } from "@/types/app";
|
||||
import { Service, Instance, Endpoint } from "@/types/selector";
|
||||
import { store } from "@/store";
|
||||
import graphql from "@/graphql";
|
||||
import { AxiosResponse } from "axios";
|
||||
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||
|
||||
interface SelectorState {
|
||||
services: Service[];
|
||||
destServices: Service[];
|
||||
@@ -31,7 +29,6 @@ interface SelectorState {
|
||||
currentDestService: Nullable<Service>;
|
||||
currentDestPod: Nullable<Instance | Endpoint>;
|
||||
destPods: Array<Instance | Endpoint>;
|
||||
durationTime: Duration;
|
||||
}
|
||||
|
||||
export const selectorStore = defineStore({
|
||||
@@ -45,7 +42,6 @@ export const selectorStore = defineStore({
|
||||
currentPod: null,
|
||||
currentDestService: null,
|
||||
currentDestPod: null,
|
||||
durationTime: useAppStoreWithOut().durationTime,
|
||||
}),
|
||||
actions: {
|
||||
setCurrentService(service: Nullable<Service>) {
|
||||
@@ -86,7 +82,7 @@ export const selectorStore = defineStore({
|
||||
}
|
||||
const res: AxiosResponse = await graphql.query("queryInstances").params({
|
||||
serviceId,
|
||||
duration: this.durationTime,
|
||||
duration: useAppStoreWithOut().durationTime,
|
||||
});
|
||||
if (!res.data.errors) {
|
||||
if (param && param.isRelation) {
|
||||
@@ -112,7 +108,7 @@ export const selectorStore = defineStore({
|
||||
}
|
||||
const res: AxiosResponse = await graphql.query("queryEndpoints").params({
|
||||
serviceId,
|
||||
duration: this.durationTime,
|
||||
duration: useAppStoreWithOut().durationTime,
|
||||
keyword: params.keyword || "",
|
||||
limit: params.limit,
|
||||
});
|
||||
|
@@ -75,7 +75,7 @@ export const topologyStore = defineStore({
|
||||
setTopology(data: { nodes: Node[]; calls: Call[] }) {
|
||||
const obj = {} as any;
|
||||
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]) {
|
||||
obj[next.id] = true;
|
||||
const s = services.filter((d: Service) => d.id === next.id)[0] || {};
|
||||
@@ -84,7 +84,7 @@ export const topologyStore = defineStore({
|
||||
}
|
||||
return prev;
|
||||
}, []);
|
||||
const calls = data.calls.reduce((prev: Call[], next: Call) => {
|
||||
const calls = (data.calls || []).reduce((prev: Call[], next: Call) => {
|
||||
if (!obj[next.id]) {
|
||||
obj[next.id] = true;
|
||||
next.value = next.value || 1;
|
||||
@@ -117,7 +117,7 @@ export const topologyStore = defineStore({
|
||||
async getDepthServiceTopology(serviceIds: string[], depth: number) {
|
||||
const res = await this.getServicesTopology(serviceIds);
|
||||
if (depth > 1) {
|
||||
const ids = res.nodes
|
||||
const ids = (res.nodes || [])
|
||||
.map((item: Node) => item.id)
|
||||
.filter((d: string) => !serviceIds.includes(d));
|
||||
if (!ids.length) {
|
||||
@@ -410,6 +410,9 @@ export const topologyStore = defineStore({
|
||||
const idsC = this.calls
|
||||
.filter((i: Call) => i.detectPoints.includes("CLIENT"))
|
||||
.map((b: Call) => b.id);
|
||||
if (!idsC.length) {
|
||||
return;
|
||||
}
|
||||
const param = await useQueryTopologyMetrics(linkClientMetrics, idsC);
|
||||
const res = await this.getCallClientMetrics(param);
|
||||
|
||||
@@ -425,6 +428,9 @@ export const topologyStore = defineStore({
|
||||
const idsS = this.calls
|
||||
.filter((i: Call) => i.detectPoints.includes("SERVER"))
|
||||
.map((b: Call) => b.id);
|
||||
if (!idsS.length) {
|
||||
return;
|
||||
}
|
||||
const param = await useQueryTopologyMetrics(linkServerMetrics, idsS);
|
||||
const res = await this.getCallServerMetrics(param);
|
||||
|
||||
@@ -438,6 +444,9 @@ export const topologyStore = defineStore({
|
||||
return;
|
||||
}
|
||||
const ids = this.nodes.map((d: Node) => d.id);
|
||||
if (!ids.length) {
|
||||
return;
|
||||
}
|
||||
const param = await useQueryTopologyMetrics(nodeMetrics, ids);
|
||||
const res = await this.getNodeMetricValue(param);
|
||||
|
||||
|
@@ -15,7 +15,6 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { defineStore } from "pinia";
|
||||
import { Duration } from "@/types/app";
|
||||
import { Instance, Endpoint, Service } from "@/types/selector";
|
||||
import { Trace, Span } from "@/types/trace";
|
||||
import { store } from "@/store";
|
||||
@@ -29,16 +28,10 @@ interface TraceState {
|
||||
instances: Instance[];
|
||||
endpoints: Endpoint[];
|
||||
traceList: Trace[];
|
||||
traceTotal: number;
|
||||
traceSpans: Span[];
|
||||
currentTrace: Trace | any;
|
||||
conditions: any;
|
||||
traceSpanLogs: any[];
|
||||
traceSpanLogsTotal: number;
|
||||
// traceListErrors: string;
|
||||
// traceSpanErrors: string;
|
||||
// traceSpanLogErrors: string;
|
||||
durationTime: Duration;
|
||||
selectorStore: any;
|
||||
}
|
||||
|
||||
@@ -50,22 +43,19 @@ export const traceStore = defineStore({
|
||||
endpoints: [{ value: "0", label: "All" }],
|
||||
traceList: [],
|
||||
traceSpans: [],
|
||||
traceTotal: 0,
|
||||
currentTrace: {},
|
||||
conditions: {
|
||||
queryDuration: useAppStoreWithOut().durationTime,
|
||||
traceState: "ALL",
|
||||
queryOrder: "BY_START_TIME",
|
||||
paging: { pageNum: 1, pageSize: 15, needTotal: true },
|
||||
paging: { pageNum: 1, pageSize: 20 },
|
||||
},
|
||||
traceSpanLogs: [],
|
||||
traceSpanLogsTotal: 0,
|
||||
durationTime: useAppStoreWithOut().durationTime,
|
||||
selectorStore: useSelectorStore(),
|
||||
}),
|
||||
actions: {
|
||||
setTraceCondition(data: any) {
|
||||
this.condition = { ...this.condition, ...data };
|
||||
this.conditions = { ...this.conditions, ...data };
|
||||
},
|
||||
setCurrentTrace(trace: Trace) {
|
||||
this.currentTrace = trace;
|
||||
@@ -89,16 +79,13 @@ export const traceStore = defineStore({
|
||||
: id;
|
||||
const res: AxiosResponse = await graphql.query("queryInstances").params({
|
||||
serviceId: serviceId,
|
||||
duration: this.durationTime,
|
||||
duration: useAppStoreWithOut().durationTime,
|
||||
});
|
||||
|
||||
if (res.data.errors) {
|
||||
return res.data;
|
||||
}
|
||||
this.instances = [
|
||||
{ value: "0", label: "All" },
|
||||
...res.data.data.pods,
|
||||
] || [{ value: " 0", label: "All" }];
|
||||
this.instances = [{ value: "0", label: "All" }, ...res.data.data.pods];
|
||||
return res.data;
|
||||
},
|
||||
async getEndpoints(id: string, keyword?: string) {
|
||||
@@ -107,27 +94,23 @@ export const traceStore = defineStore({
|
||||
: id;
|
||||
const res: AxiosResponse = await graphql.query("queryEndpoints").params({
|
||||
serviceId,
|
||||
duration: this.durationTime,
|
||||
duration: useAppStoreWithOut().durationTime,
|
||||
keyword: keyword || "",
|
||||
});
|
||||
if (res.data.errors) {
|
||||
return res.data;
|
||||
}
|
||||
this.endpoints = [
|
||||
{ value: "0", label: "All" },
|
||||
...res.data.data.pods,
|
||||
] || [{ value: "0", label: "All" }];
|
||||
this.endpoints = [{ value: "0", label: "All" }, ...res.data.data.pods];
|
||||
return res.data;
|
||||
},
|
||||
async getTraces() {
|
||||
const res: AxiosResponse = await graphql
|
||||
.query("queryTraces")
|
||||
.params({ condition: this.condition });
|
||||
.params({ condition: this.conditions });
|
||||
if (res.data.errors) {
|
||||
return res.data;
|
||||
}
|
||||
if (!res.data.data.data.traces.length) {
|
||||
this.traceTotal = 0;
|
||||
this.traceList = [];
|
||||
this.setCurrentTrace({});
|
||||
this.setTraceSpans([]);
|
||||
@@ -140,7 +123,6 @@ export const traceStore = defineStore({
|
||||
});
|
||||
return d;
|
||||
});
|
||||
this.traceTotal = res.data.data.data.total;
|
||||
this.setCurrentTrace(res.data.data.data.traces[0] || {});
|
||||
return res.data;
|
||||
},
|
||||
@@ -160,11 +142,23 @@ export const traceStore = defineStore({
|
||||
.params(params);
|
||||
if (res.data.errors) {
|
||||
this.traceSpanLogs = [];
|
||||
this.traceSpanLogsTotal = 0;
|
||||
return res.data;
|
||||
}
|
||||
this.traceSpanLogs = res.data.data.queryLogs.logs || [];
|
||||
this.traceSpanLogsTotal = res.data.data.queryLogs.total;
|
||||
return res.data;
|
||||
},
|
||||
async getTagKeys() {
|
||||
const res: AxiosResponse = await graphql
|
||||
.query("queryTraceTagKeys")
|
||||
.params({ duration: useAppStoreWithOut().durationTime });
|
||||
|
||||
return res.data;
|
||||
},
|
||||
async getTagValues(tagKey: string) {
|
||||
const res: AxiosResponse = await graphql
|
||||
.query("queryTraceTagValues")
|
||||
.params({ tagKey, duration: useAppStoreWithOut().durationTime });
|
||||
|
||||
return res.data;
|
||||
},
|
||||
},
|
||||
|
@@ -15,10 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
.show-xs,
|
||||
.show-sm,
|
||||
.show-md,
|
||||
.show-lg {
|
||||
.show-xs {
|
||||
display: none !important;
|
||||
}
|
||||
@media (max-width: 767px) {
|
||||
@@ -30,145 +27,6 @@
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
@media (min-width: 768px) and (max-width: 1023px) {
|
||||
.show-sm {
|
||||
display: block !important;
|
||||
}
|
||||
|
||||
.hide-sm {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
@media (min-width: 1024px) and (max-width: 1279px) {
|
||||
.show-md {
|
||||
display: block !important;
|
||||
}
|
||||
|
||||
.hide-md {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
@media (min-width: 1280px) {
|
||||
.show-lg {
|
||||
display: block !important;
|
||||
}
|
||||
|
||||
.hide-lg {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
.g-xs-1,
|
||||
.g-xs-2,
|
||||
.g-xs-3,
|
||||
.g-xs-4,
|
||||
.g-xs-5,
|
||||
.g-xs-6,
|
||||
.g-xs-7,
|
||||
.g-xs-8,
|
||||
.g-xs-9,
|
||||
.g-xs-10,
|
||||
.g-xs-11,
|
||||
.g-xs-12 {
|
||||
float: left;
|
||||
min-height: 1px;
|
||||
}
|
||||
|
||||
.g-xs-12 {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.g-xs-11 {
|
||||
width: 91.666%;
|
||||
}
|
||||
|
||||
.g-xs-10 {
|
||||
width: 83.333%;
|
||||
}
|
||||
|
||||
.g-xs-9 {
|
||||
width: 75%;
|
||||
}
|
||||
|
||||
.g-xs-8 {
|
||||
width: 66.666%;
|
||||
}
|
||||
|
||||
.g-xs-7 {
|
||||
width: 58.333%;
|
||||
}
|
||||
|
||||
.g-xs-6 {
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
.g-xs-5 {
|
||||
width: 41.666%;
|
||||
}
|
||||
|
||||
.g-xs-4 {
|
||||
width: 33.333%;
|
||||
}
|
||||
|
||||
.g-xs-3 {
|
||||
width: 25%;
|
||||
}
|
||||
|
||||
.g-xs-2 {
|
||||
width: 16.666%;
|
||||
}
|
||||
|
||||
.g-xs-1 {
|
||||
width: 8.333%;
|
||||
}
|
||||
|
||||
.g-xs-space-12 {
|
||||
margin-left: 100%;
|
||||
}
|
||||
|
||||
.g-xs-space-11 {
|
||||
margin-left: 91.666%;
|
||||
}
|
||||
|
||||
.g-xs-space-10 {
|
||||
margin-left: 83.333%;
|
||||
}
|
||||
|
||||
.g-xs-space-9 {
|
||||
margin-left: 75%;
|
||||
}
|
||||
|
||||
.g-xs-space-8 {
|
||||
margin-left: 66.666%;
|
||||
}
|
||||
|
||||
.g-xs-space-7 {
|
||||
margin-left: 58.333%;
|
||||
}
|
||||
|
||||
.g-xs-space-6 {
|
||||
margin-left: 50%;
|
||||
}
|
||||
|
||||
.g-xs-space-5 {
|
||||
margin-left: 41.666%;
|
||||
}
|
||||
|
||||
.g-xs-space-4 {
|
||||
margin-left: 33.333%;
|
||||
}
|
||||
|
||||
.g-xs-space-3 {
|
||||
margin-left: 25%;
|
||||
}
|
||||
|
||||
.g-xs-space-2 {
|
||||
margin-left: 16.666%;
|
||||
}
|
||||
|
||||
.g-xs-space-1 {
|
||||
margin-left: 8.333%;
|
||||
}
|
||||
@media (min-width: 768px) {
|
||||
.g-sm-1,
|
||||
.g-sm-2,
|
||||
@@ -233,278 +91,4 @@
|
||||
.g-sm-1 {
|
||||
width: 8.333%;
|
||||
}
|
||||
|
||||
.g-sm-space-12 {
|
||||
margin-left: 100%;
|
||||
}
|
||||
|
||||
.g-sm-space-11 {
|
||||
margin-left: 91.666%;
|
||||
}
|
||||
|
||||
.g-sm-space-10 {
|
||||
margin-left: 83.333%;
|
||||
}
|
||||
|
||||
.g-sm-space-9 {
|
||||
margin-left: 75%;
|
||||
}
|
||||
|
||||
.g-sm-space-8 {
|
||||
margin-left: 66.666%;
|
||||
}
|
||||
|
||||
.g-sm-space-7 {
|
||||
margin-left: 58.333%;
|
||||
}
|
||||
|
||||
.g-sm-space-6 {
|
||||
margin-left: 50%;
|
||||
}
|
||||
|
||||
.g-sm-space-5 {
|
||||
margin-left: 41.666%;
|
||||
}
|
||||
|
||||
.g-sm-space-4 {
|
||||
margin-left: 33.333%;
|
||||
}
|
||||
|
||||
.g-sm-space-3 {
|
||||
margin-left: 25%;
|
||||
}
|
||||
|
||||
.g-sm-space-2 {
|
||||
margin-left: 16.666%;
|
||||
}
|
||||
|
||||
.g-sm-space-1 {
|
||||
margin-left: 8.333%;
|
||||
}
|
||||
}
|
||||
@media (min-width: 1024px) {
|
||||
.g-md-1,
|
||||
.g-md-2,
|
||||
.g-md-3,
|
||||
.g-md-4,
|
||||
.g-md-5,
|
||||
.g-md-6,
|
||||
.g-md-7,
|
||||
.g-md-8,
|
||||
.g-md-9,
|
||||
.g-md-10,
|
||||
.g-md-11,
|
||||
.g-md-12 {
|
||||
float: left;
|
||||
min-height: 1px;
|
||||
}
|
||||
|
||||
.g-md-12 {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.g-md-11 {
|
||||
width: 91.666%;
|
||||
}
|
||||
|
||||
.g-md-10 {
|
||||
width: 83.333%;
|
||||
}
|
||||
|
||||
.g-md-9 {
|
||||
width: 75%;
|
||||
}
|
||||
|
||||
.g-md-8 {
|
||||
width: 66.666%;
|
||||
}
|
||||
|
||||
.g-md-7 {
|
||||
width: 58.333%;
|
||||
}
|
||||
|
||||
.g-md-6 {
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
.g-md-5 {
|
||||
width: 41.666%;
|
||||
}
|
||||
|
||||
.g-md-4 {
|
||||
width: 33.333%;
|
||||
}
|
||||
|
||||
.g-md-3 {
|
||||
width: 25%;
|
||||
}
|
||||
|
||||
.g-md-2 {
|
||||
width: 16.666%;
|
||||
}
|
||||
|
||||
.g-md-1 {
|
||||
width: 8.333%;
|
||||
}
|
||||
|
||||
.g-md-space-12 {
|
||||
margin-left: 100%;
|
||||
}
|
||||
|
||||
.g-md-space-11 {
|
||||
margin-left: 91.666%;
|
||||
}
|
||||
|
||||
.g-md-space-10 {
|
||||
margin-left: 83.333%;
|
||||
}
|
||||
|
||||
.g-md-space-9 {
|
||||
margin-left: 75%;
|
||||
}
|
||||
|
||||
.g-md-space-8 {
|
||||
margin-left: 66.666%;
|
||||
}
|
||||
|
||||
.g-md-space-7 {
|
||||
margin-left: 58.333%;
|
||||
}
|
||||
|
||||
.g-md-space-6 {
|
||||
margin-left: 50%;
|
||||
}
|
||||
|
||||
.g-md-space-5 {
|
||||
margin-left: 41.666%;
|
||||
}
|
||||
|
||||
.g-md-space-4 {
|
||||
margin-left: 33.333%;
|
||||
}
|
||||
|
||||
.g-md-space-3 {
|
||||
margin-left: 25%;
|
||||
}
|
||||
|
||||
.g-md-space-2 {
|
||||
margin-left: 16.666%;
|
||||
}
|
||||
|
||||
.g-md-space-1 {
|
||||
margin-left: 8.333%;
|
||||
}
|
||||
}
|
||||
@media (min-width: 1280px) {
|
||||
.g-lg-1,
|
||||
.g-lg-2,
|
||||
.g-lg-3,
|
||||
.g-lg-4,
|
||||
.g-lg-5,
|
||||
.g-lg-6,
|
||||
.g-lg-7,
|
||||
.g-lg-8,
|
||||
.g-lg-9,
|
||||
.g-lg-10,
|
||||
.g-lg-11,
|
||||
.g-lg-12 {
|
||||
float: left;
|
||||
min-height: 1px;
|
||||
}
|
||||
|
||||
.g-lg-12 {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.g-lg-11 {
|
||||
width: 91.666%;
|
||||
}
|
||||
|
||||
.g-lg-10 {
|
||||
width: 83.333%;
|
||||
}
|
||||
|
||||
.g-lg-9 {
|
||||
width: 75%;
|
||||
}
|
||||
|
||||
.g-lg-8 {
|
||||
width: 66.666%;
|
||||
}
|
||||
|
||||
.g-lg-7 {
|
||||
width: 58.333%;
|
||||
}
|
||||
|
||||
.g-lg-6 {
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
.g-lg-5 {
|
||||
width: 41.666%;
|
||||
}
|
||||
|
||||
.g-lg-4 {
|
||||
width: 33.333%;
|
||||
}
|
||||
|
||||
.g-lg-3 {
|
||||
width: 25%;
|
||||
}
|
||||
|
||||
.g-lg-2 {
|
||||
width: 16.666%;
|
||||
}
|
||||
|
||||
.g-lg-1 {
|
||||
width: 8.333%;
|
||||
}
|
||||
|
||||
.g-lg-space-12 {
|
||||
margin-left: 100%;
|
||||
}
|
||||
|
||||
.g-lg-space-11 {
|
||||
margin-left: 91.666%;
|
||||
}
|
||||
|
||||
.g-lg-space-10 {
|
||||
margin-left: 83.333%;
|
||||
}
|
||||
|
||||
.g-lg-space-9 {
|
||||
margin-left: 75%;
|
||||
}
|
||||
|
||||
.g-lg-space-8 {
|
||||
margin-left: 66.666%;
|
||||
}
|
||||
|
||||
.g-lg-space-7 {
|
||||
margin-left: 58.333%;
|
||||
}
|
||||
|
||||
.g-lg-space-6 {
|
||||
margin-left: 50%;
|
||||
}
|
||||
|
||||
.g-lg-space-5 {
|
||||
margin-left: 41.666%;
|
||||
}
|
||||
|
||||
.g-lg-space-4 {
|
||||
margin-left: 33.333%;
|
||||
}
|
||||
|
||||
.g-lg-space-3 {
|
||||
margin-left: 25%;
|
||||
}
|
||||
|
||||
.g-lg-space-2 {
|
||||
margin-left: 16.666%;
|
||||
}
|
||||
|
||||
.g-lg-space-1 {
|
||||
margin-left: 8.333%;
|
||||
}
|
||||
}
|
||||
|
22
src/styles/index.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* 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 "element-plus/es/components/message/style/css";
|
||||
import "element-plus/es/components/message-box/style/css";
|
||||
import "element-plus/es/components/notification/style/css";
|
||||
import "./grid.scss";
|
||||
import "./lib.scss";
|
||||
import "./reset.scss";
|
@@ -171,3 +171,21 @@
|
||||
color: #ddd;
|
||||
}
|
||||
}
|
||||
|
||||
.scroll_bar_style::-webkit-scrollbar {
|
||||
width: 9px;
|
||||
height: 4px;
|
||||
background-color: #eee;
|
||||
}
|
||||
|
||||
.scroll_bar_style::-webkit-scrollbar-track {
|
||||
background-color: #eee;
|
||||
border-radius: 3px;
|
||||
box-shadow: inset 0 0 6px #ccc;
|
||||
}
|
||||
|
||||
.scroll_bar_style::-webkit-scrollbar-thumb {
|
||||
border-radius: 3px;
|
||||
box-shadow: inset 0 0 6px #ccc;
|
||||
background-color: #aaa;
|
||||
}
|
||||
|
@@ -29,6 +29,7 @@ body {
|
||||
html,
|
||||
body {
|
||||
height: 100%;
|
||||
overflow-y: hidden;
|
||||
}
|
||||
|
||||
div,
|
||||
|
4
src/types/app.d.ts
vendored
@@ -28,3 +28,7 @@ export interface DurationTime {
|
||||
end: string;
|
||||
step: string;
|
||||
}
|
||||
export type Paging = {
|
||||
pageNum: number;
|
||||
pageSize: number;
|
||||
};
|
||||
|
52
src/types/auto-imports.d.ts
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
// Generated by 'unplugin-auto-import'
|
||||
// We suggest you to commit this file into source control
|
||||
declare global {
|
||||
const computed: typeof import('vue')['computed']
|
||||
const createApp: typeof import('vue')['createApp']
|
||||
const customRef: typeof import('vue')['customRef']
|
||||
const defineAsyncComponent: typeof import('vue')['defineAsyncComponent']
|
||||
const defineComponent: typeof import('vue')['defineComponent']
|
||||
const effectScope: typeof import('vue')['effectScope']
|
||||
const EffectScope: typeof import('vue')['EffectScope']
|
||||
const getCurrentInstance: typeof import('vue')['getCurrentInstance']
|
||||
const getCurrentScope: typeof import('vue')['getCurrentScope']
|
||||
const h: typeof import('vue')['h']
|
||||
const inject: typeof import('vue')['inject']
|
||||
const isReadonly: typeof import('vue')['isReadonly']
|
||||
const isRef: typeof import('vue')['isRef']
|
||||
const markRaw: typeof import('vue')['markRaw']
|
||||
const nextTick: typeof import('vue')['nextTick']
|
||||
const onActivated: typeof import('vue')['onActivated']
|
||||
const onBeforeMount: typeof import('vue')['onBeforeMount']
|
||||
const onBeforeUnmount: typeof import('vue')['onBeforeUnmount']
|
||||
const onBeforeUpdate: typeof import('vue')['onBeforeUpdate']
|
||||
const onDeactivated: typeof import('vue')['onDeactivated']
|
||||
const onErrorCaptured: typeof import('vue')['onErrorCaptured']
|
||||
const onMounted: typeof import('vue')['onMounted']
|
||||
const onRenderTracked: typeof import('vue')['onRenderTracked']
|
||||
const onRenderTriggered: typeof import('vue')['onRenderTriggered']
|
||||
const onScopeDispose: typeof import('vue')['onScopeDispose']
|
||||
const onServerPrefetch: typeof import('vue')['onServerPrefetch']
|
||||
const onUnmounted: typeof import('vue')['onUnmounted']
|
||||
const onUpdated: typeof import('vue')['onUpdated']
|
||||
const provide: typeof import('vue')['provide']
|
||||
const reactive: typeof import('vue')['reactive']
|
||||
const readonly: typeof import('vue')['readonly']
|
||||
const ref: typeof import('vue')['ref']
|
||||
const resolveComponent: typeof import('vue')['resolveComponent']
|
||||
const shallowReactive: typeof import('vue')['shallowReactive']
|
||||
const shallowReadonly: typeof import('vue')['shallowReadonly']
|
||||
const shallowRef: typeof import('vue')['shallowRef']
|
||||
const toRaw: typeof import('vue')['toRaw']
|
||||
const toRef: typeof import('vue')['toRef']
|
||||
const toRefs: typeof import('vue')['toRefs']
|
||||
const triggerRef: typeof import('vue')['triggerRef']
|
||||
const unref: typeof import('vue')['unref']
|
||||
const useAttrs: typeof import('vue')['useAttrs']
|
||||
const useCssModule: typeof import('vue')['useCssModule']
|
||||
const useCssVars: typeof import('vue')['useCssVars']
|
||||
const useSlots: typeof import('vue')['useSlots']
|
||||
const watch: typeof import('vue')['watch']
|
||||
const watchEffect: typeof import('vue')['watchEffect']
|
||||
}
|
||||
export {}
|
47
src/types/components.d.ts
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
// generated by unplugin-vue-components
|
||||
// We suggest you to commit this file into source control
|
||||
// Read more: https://github.com/vuejs/vue-next/pull/3399
|
||||
|
||||
declare module '@vue/runtime-core' {
|
||||
export interface GlobalComponents {
|
||||
DateCalendar: typeof import('./../components/DateCalendar.vue')['default']
|
||||
ElButton: typeof import('element-plus/es')['ElButton']
|
||||
ElCollapse: typeof import('element-plus/es')['ElCollapse']
|
||||
ElCollapseItem: typeof import('element-plus/es')['ElCollapseItem']
|
||||
ElDialog: typeof import('element-plus/es')['ElDialog']
|
||||
ElDropdown: typeof import('element-plus/es')['ElDropdown']
|
||||
ElDropdownItem: typeof import('element-plus/es')['ElDropdownItem']
|
||||
ElDropdownMenu: typeof import('element-plus/es')['ElDropdownMenu']
|
||||
ElIcon: typeof import('element-plus/es')['ElIcon']
|
||||
ElInput: typeof import('element-plus/es')['ElInput']
|
||||
ElInputNumber: typeof import('element-plus/es')['ElInputNumber']
|
||||
ElMenu: typeof import('element-plus/es')['ElMenu']
|
||||
ElMenuItem: typeof import('element-plus/es')['ElMenuItem']
|
||||
ElMenuItemGroup: typeof import('element-plus/es')['ElMenuItemGroup']
|
||||
ElOption: typeof import('element-plus/es')['ElOption']
|
||||
ElPagination: typeof import('element-plus/es')['ElPagination']
|
||||
ElPopconfirm: typeof import('element-plus/es')['ElPopconfirm']
|
||||
ElPopover: typeof import('element-plus/es')['ElPopover']
|
||||
ElProgress: typeof import('element-plus/es')['ElProgress']
|
||||
ElRadio: typeof import('element-plus/es')['ElRadio']
|
||||
ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup']
|
||||
ElSelect: typeof import('element-plus/es')['ElSelect']
|
||||
ElSlider: typeof import('element-plus/es')['ElSlider']
|
||||
ElSubMenu: typeof import('element-plus/es')['ElSubMenu']
|
||||
ElSwitch: typeof import('element-plus/es')['ElSwitch']
|
||||
ElTable: typeof import('element-plus/es')['ElTable']
|
||||
ElTableColumn: typeof import('element-plus/es')['ElTableColumn']
|
||||
ElTooltip: typeof import('element-plus/es')['ElTooltip']
|
||||
Graph: typeof import('./../components/Graph.vue')['default']
|
||||
Icon: typeof import('./../components/Icon.vue')['default']
|
||||
Loading: typeof import('element-plus/es')['ElLoadingDirective']
|
||||
Radio: typeof import('./../components/Radio.vue')['default']
|
||||
RouterLink: typeof import('vue-router')['RouterLink']
|
||||
RouterView: typeof import('vue-router')['RouterView']
|
||||
Selector: typeof import('./../components/Selector.vue')['default']
|
||||
SelectSingle: typeof import('./../components/SelectSingle.vue')['default']
|
||||
TimePicker: typeof import('./../components/TimePicker.vue')['default']
|
||||
}
|
||||
}
|
||||
|
||||
export { }
|
@@ -39,9 +39,9 @@ export interface LayoutConfig {
|
||||
}
|
||||
|
||||
export type MetricConfigOpt = {
|
||||
unit: string;
|
||||
label: string;
|
||||
calculation: string;
|
||||
unit?: string;
|
||||
label?: string;
|
||||
calculation?: string;
|
||||
labelsIndex: string;
|
||||
sortOrder: string;
|
||||
topN?: number;
|
||||
@@ -73,6 +73,7 @@ export interface LineConfig extends AreaConfig {
|
||||
showXAxis?: boolean;
|
||||
showYAxis?: boolean;
|
||||
smallTips?: boolean;
|
||||
showlabels?: boolean;
|
||||
}
|
||||
|
||||
export interface AreaConfig {
|
31
src/types/demand-log.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
* 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 { DurationTime } from "./app";
|
||||
|
||||
export interface Conditions {
|
||||
container: string;
|
||||
serviceInstanceId: string;
|
||||
duration: DurationTime;
|
||||
keywordsOfContent?: string[];
|
||||
excludingKeywordsOfContent?: string;
|
||||
}
|
||||
|
||||
export interface Log {
|
||||
content: string;
|
||||
timestamp: number;
|
||||
contentType: string;
|
||||
}
|
77
src/types/ebpf.d.ts
vendored
Normal file
@@ -0,0 +1,77 @@
|
||||
/**
|
||||
* 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 EBPFTaskCreationRequest {
|
||||
serviceId: string;
|
||||
processLabels: string[];
|
||||
startTime: number;
|
||||
duration: number;
|
||||
targetType: string;
|
||||
}
|
||||
|
||||
export interface EBPFTaskList {
|
||||
taskId: string;
|
||||
serviceName: string;
|
||||
serviceId: string;
|
||||
processLabels: string[];
|
||||
taskStartTime: number;
|
||||
fixedTriggerDuration: number;
|
||||
targetType: string;
|
||||
createTime: number;
|
||||
triggerType: string;
|
||||
}
|
||||
|
||||
export interface EBPFProfilingSchedule {
|
||||
scheduleId: string;
|
||||
taskId: string;
|
||||
process: Process;
|
||||
endTime: number;
|
||||
startTime: number;
|
||||
}
|
||||
|
||||
export type Process = {
|
||||
id: string;
|
||||
name: string;
|
||||
serviceId: string;
|
||||
serviceName: string;
|
||||
instanceId: string;
|
||||
instanceName: string;
|
||||
agentId: string;
|
||||
detectType: string;
|
||||
attributes: { name: string; value: string }[];
|
||||
labels: string[];
|
||||
};
|
||||
export type StackElement = {
|
||||
id: string;
|
||||
originId: string;
|
||||
name: string;
|
||||
parentId: string;
|
||||
symbol: string;
|
||||
dumpCount: number;
|
||||
stackType: string;
|
||||
value: number;
|
||||
children?: StackElement[];
|
||||
rateOfRoot?: string;
|
||||
rateOfParent: string;
|
||||
};
|
||||
export type AnalyzationTrees = {
|
||||
id: string;
|
||||
parentId: string;
|
||||
symbol: string;
|
||||
dumpCount: number;
|
||||
stackType: string;
|
||||
};
|
@@ -14,6 +14,4 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
@import "./grid.scss";
|
||||
@import "./lib.scss";
|
||||
@import "./reset.scss";
|
||||
declare module "monaco-editor";
|
1
src/types/selector.d.ts
vendored
@@ -26,7 +26,6 @@ export type Service = {
|
||||
export type Instance = {
|
||||
value: string;
|
||||
label: string;
|
||||
layer?: string;
|
||||
language?: string;
|
||||
instanceUUID?: string;
|
||||
attributes?: { name: string; value: string }[];
|
||||
|
9
src/types/trace.d.ts
vendored
@@ -46,8 +46,15 @@ export interface Span {
|
||||
children?: Span[];
|
||||
tags?: Array<Map<string, string>>;
|
||||
logs?: log[];
|
||||
parentSegmentId?: string;
|
||||
refs?: Ref[];
|
||||
}
|
||||
|
||||
export type Ref = {
|
||||
type: string;
|
||||
parentSegmentId: string;
|
||||
parentSpanId: number;
|
||||
traceId: string;
|
||||
};
|
||||
export interface log {
|
||||
time: number;
|
||||
data: Map<string, string>;
|
||||
|
@@ -77,16 +77,15 @@ import { Languages } from "@/constants/data";
|
||||
import Selector from "@/components/Selector.vue";
|
||||
|
||||
const { t, locale } = useI18n();
|
||||
const appStore = useAppStoreWithOut();
|
||||
const state = reactive<{ timer: ReturnType<typeof setInterval> | null }>({
|
||||
timer: null,
|
||||
});
|
||||
const lang = ref<string>(locale.value || "en");
|
||||
const autoTime = ref<number>(6);
|
||||
const auto = ref<boolean>(false);
|
||||
const appStore = useAppStoreWithOut();
|
||||
const utcArr = appStore.utc.split(":");
|
||||
const utcHour = ref<number>(isNaN(Number(utcArr[0])) ? 0 : Number(utcArr[0]));
|
||||
const utcMin = ref<number>(isNaN(Number(utcArr[1])) ? 0 : Number(utcArr[1]));
|
||||
const auto = ref<boolean>(appStore.autoRefresh || false);
|
||||
const utcHour = ref<number>(appStore.utcHour);
|
||||
const utcMin = ref<number>(appStore.utcMin);
|
||||
|
||||
appStore.setPageTitle("Setting");
|
||||
const handleReload = () => {
|
||||
@@ -195,10 +194,11 @@ const setUTCMin = () => {
|
||||
}
|
||||
|
||||
.label {
|
||||
width: 160px;
|
||||
width: 180px;
|
||||
display: inline-block;
|
||||
font-weight: 500;
|
||||
color: #000;
|
||||
line-height: 25px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@@ -29,6 +29,7 @@ limitations under the License. -->
|
||||
<div class="mr-10 ml-10">
|
||||
<span class="grey">{{ t("searchKeyword") }}: </span>
|
||||
<el-input
|
||||
size="small"
|
||||
v-model="keyword"
|
||||
class="alarm-tool-input"
|
||||
@change="refreshAlarms({ pageNum: 1 })"
|
||||
@@ -38,8 +39,8 @@ limitations under the License. -->
|
||||
<el-pagination
|
||||
v-model:currentPage="pageNum"
|
||||
v-model:page-size="pageSize"
|
||||
layout="prev, jumper, total, next"
|
||||
:total="alarmStore.total"
|
||||
layout="prev, pager, next"
|
||||
:total="total"
|
||||
@current-change="changePage"
|
||||
:pager-count="5"
|
||||
small
|
||||
@@ -54,7 +55,7 @@ limitations under the License. -->
|
||||
</nav>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref } from "vue";
|
||||
import { ref, computed } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import ConditionTags from "@/views/components/ConditionTags.vue";
|
||||
import { AlarmOptions } from "./data";
|
||||
@@ -69,6 +70,11 @@ const pageSize = 20;
|
||||
const entity = ref<string>("");
|
||||
const keyword = ref<string>("");
|
||||
const pageNum = ref<number>(1);
|
||||
const total = computed(() =>
|
||||
alarmStore.alarms.length === pageSize
|
||||
? pageSize * pageNum.value + 1
|
||||
: pageSize * pageNum.value
|
||||
);
|
||||
|
||||
refreshAlarms({ pageNum: 1 });
|
||||
|
||||
@@ -78,7 +84,6 @@ async function refreshAlarms(param: { pageNum: number; tagsMap?: any }) {
|
||||
paging: {
|
||||
pageNum: param.pageNum,
|
||||
pageSize,
|
||||
needTotal: true,
|
||||
},
|
||||
tags: param.tagsMap,
|
||||
};
|
||||
|
@@ -13,54 +13,99 @@ 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="flex-h" :class="{ light: theme === 'light' }">
|
||||
<div class="mr-5">
|
||||
<span class="sm grey" v-show="theme === 'dark'">{{ t("tags") }}: </span>
|
||||
<span
|
||||
class="trace-tags"
|
||||
:style="type === 'LOG' ? `min-width: 122px;` : ''"
|
||||
>
|
||||
<span class="selected" v-for="(item, index) in tagsList" :key="index">
|
||||
<span>{{ item }}</span>
|
||||
<span class="remove-icon" @click="removeTags(index)">×</span>
|
||||
</span>
|
||||
<div>
|
||||
<span class="grey">{{ t("tags") }}: </span>
|
||||
<span
|
||||
v-if="tagsList.length"
|
||||
class="trace-tags"
|
||||
:style="type === 'LOG' ? `min-width: 122px;` : ''"
|
||||
>
|
||||
<span class="selected" v-for="(item, index) in tagsList" :key="index">
|
||||
<span>{{ item }}</span>
|
||||
<span class="remove-icon" @click="removeTags(index)">×</span>
|
||||
</span>
|
||||
</span>
|
||||
<el-input
|
||||
v-if="type === 'ALARM'"
|
||||
size="small"
|
||||
v-model="tags"
|
||||
class="trace-new-tag"
|
||||
@change="addLabels"
|
||||
:placeholder="t('addTags')"
|
||||
/>
|
||||
<span v-else>
|
||||
<el-input
|
||||
size="small"
|
||||
v-model="tags"
|
||||
class="trace-new-tag"
|
||||
@change="addLabels"
|
||||
:placeholder="t('addTags')"
|
||||
@click="showClick"
|
||||
/>
|
||||
<span class="tags-tip">
|
||||
<a
|
||||
target="blank"
|
||||
href="https://github.com/apache/skywalking/blob/master/docs/en/setup/backend/configuration-vocabulary.md"
|
||||
>
|
||||
{{ t("tagsLink") }}
|
||||
</a>
|
||||
<el-tooltip :content="t('traceTagsTip')">
|
||||
<span>
|
||||
<Icon class="icon-help mr-5" iconName="help" size="middle" />
|
||||
</span>
|
||||
</el-tooltip>
|
||||
<b v-if="type !== 'LOG'">{{ t("noticeTag") }}</b>
|
||||
</span>
|
||||
</div>
|
||||
<el-dropdown
|
||||
ref="dropdownTag"
|
||||
trigger="contextmenu"
|
||||
:hide-on-click="false"
|
||||
style="margin: 20px 0 0 -130px"
|
||||
v-if="tagArr.length"
|
||||
>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item v-for="(item, index) in tagArr" :key="index">
|
||||
<span @click="selectTag(item)" class="tag-item">
|
||||
{{ item }}
|
||||
</span>
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
</span>
|
||||
<span
|
||||
class="tags-tip"
|
||||
:class="type !== 'ALARM' && tagArr.length ? 'link-tips' : ''"
|
||||
>
|
||||
<a
|
||||
target="blank"
|
||||
href="https://github.com/apache/skywalking/blob/master/docs/en/setup/backend/configuration-vocabulary.md"
|
||||
>
|
||||
{{ t("tagsLink") }}
|
||||
</a>
|
||||
<el-tooltip :content="t(tipsMap[type])">
|
||||
<span>
|
||||
<Icon class="icon-help mr-5" iconName="help" size="middle" />
|
||||
</span>
|
||||
</el-tooltip>
|
||||
<b v-if="type === 'AL'">{{ t("noticeTag") }}</b>
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref } from "vue";
|
||||
import { ref, watch } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { useTraceStore } from "@/store/modules/trace";
|
||||
import { useLogStore } from "@/store/modules/log";
|
||||
import { ElMessage } from "element-plus";
|
||||
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||
|
||||
/*global defineEmits, defineProps */
|
||||
/*global Nullable, defineEmits, defineProps */
|
||||
const emit = defineEmits(["update"]);
|
||||
defineProps({
|
||||
const props = defineProps({
|
||||
type: { type: String, default: "TRACE" },
|
||||
});
|
||||
const traceStore = useTraceStore();
|
||||
const logStore = useLogStore();
|
||||
const appStore = useAppStoreWithOut();
|
||||
const { t } = useI18n();
|
||||
const theme = ref<string>("dark");
|
||||
const tags = ref<string>("");
|
||||
const tagsList = ref<string[]>([]);
|
||||
const tagArr = ref<string[]>([]);
|
||||
const tagKeys = ref<string[]>([]);
|
||||
const tipsMap = {
|
||||
LOG: "logTagsTip",
|
||||
TRACE: "traceTagsTip",
|
||||
ALARM: "alarmTagsTip",
|
||||
};
|
||||
const dropdownTag = ref<Nullable<any>>(null);
|
||||
|
||||
fetchTagKeys();
|
||||
|
||||
function removeTags(index: number) {
|
||||
tagsList.value.splice(index, 1);
|
||||
@@ -84,6 +129,61 @@ function updateTags() {
|
||||
});
|
||||
emit("update", { tagsMap, tagsList: tagsList.value });
|
||||
}
|
||||
async function fetchTagKeys() {
|
||||
let resp: any = {};
|
||||
if (props.type === "TRACE") {
|
||||
resp = await traceStore.getTagKeys();
|
||||
} else {
|
||||
resp = await logStore.getLogTagKeys();
|
||||
}
|
||||
|
||||
if (resp.errors) {
|
||||
ElMessage.error(resp.errors);
|
||||
return;
|
||||
}
|
||||
tagArr.value = resp.data.tagKeys;
|
||||
tagKeys.value = resp.data.tagKeys;
|
||||
}
|
||||
|
||||
async function fetchTagValues() {
|
||||
const param = tags.value.split("=")[0];
|
||||
let resp: any = {};
|
||||
if (props.type === "TRACE") {
|
||||
resp = await traceStore.getTagValues(param);
|
||||
} else {
|
||||
resp = await logStore.getLogTagValues(param);
|
||||
}
|
||||
|
||||
if (resp.errors) {
|
||||
ElMessage.error(resp.errors);
|
||||
return;
|
||||
}
|
||||
tagArr.value = resp.data.tagValues;
|
||||
}
|
||||
|
||||
function selectTag(item: string) {
|
||||
if (tags.value.includes("=")) {
|
||||
tags.value += item;
|
||||
addLabels();
|
||||
tagArr.value = tagKeys.value;
|
||||
dropdownTag.value.handleClose();
|
||||
return;
|
||||
}
|
||||
tags.value = item + "=";
|
||||
fetchTagValues();
|
||||
}
|
||||
|
||||
function showClick() {
|
||||
if (dropdownTag.value) {
|
||||
dropdownTag.value.handleOpen();
|
||||
}
|
||||
}
|
||||
watch(
|
||||
() => appStore.durationTime,
|
||||
() => {
|
||||
fetchTagKeys();
|
||||
}
|
||||
);
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.trace-tags {
|
||||
@@ -110,7 +210,6 @@ function updateTags() {
|
||||
padding: 2px 5px;
|
||||
border-radius: 3px;
|
||||
width: 250px;
|
||||
margin-right: 3px;
|
||||
}
|
||||
|
||||
.remove-icon {
|
||||
@@ -119,10 +218,20 @@ function updateTags() {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.tag-item {
|
||||
display: inline-block;
|
||||
min-width: 210px;
|
||||
}
|
||||
|
||||
.tags-tip {
|
||||
color: #a7aebb;
|
||||
}
|
||||
|
||||
.link-tips {
|
||||
display: inline-block;
|
||||
margin-left: 130px;
|
||||
}
|
||||
|
||||
.light {
|
||||
color: #3d444f;
|
||||
|
||||
|
@@ -28,7 +28,7 @@ limitations under the License. -->
|
||||
</el-button>
|
||||
</template>
|
||||
</el-input>
|
||||
<el-button class="ml-10" size="small" @click="reloadTemplates">
|
||||
<el-button class="ml-10 reload-btn" size="small" @click="reloadTemplates">
|
||||
<Icon size="sm" iconName="retry" class="reload" />
|
||||
{{ t("reloadDashboards") }}
|
||||
</el-button>
|
||||
@@ -44,9 +44,10 @@ limitations under the License. -->
|
||||
:style="{ fontSize: '13px', width: '100%' }"
|
||||
v-loading="loading"
|
||||
ref="multipleTableRef"
|
||||
:default-sort="{ prop: 'name' }"
|
||||
:default-sort="{ prop: 'name', order: 'ascending' }"
|
||||
@selection-change="handleSelectionChange"
|
||||
height="637px"
|
||||
size="small"
|
||||
>
|
||||
<el-table-column type="selection" width="55" />
|
||||
<el-table-column prop="name" label="Name">
|
||||
@@ -145,9 +146,10 @@ import type { ElTable } from "element-plus";
|
||||
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||
import router from "@/router";
|
||||
import { DashboardItem } from "@/types/dashboard";
|
||||
import { DashboardItem, LayoutConfig } from "@/types/dashboard";
|
||||
import { saveFile, readFile } from "@/utils/file";
|
||||
import { EntityType } from "./data";
|
||||
import { isEmptyObject } from "@/utils/is";
|
||||
|
||||
/*global Nullable*/
|
||||
const { t } = useI18n();
|
||||
@@ -220,12 +222,77 @@ function exportTemplates() {
|
||||
const layout = JSON.parse(sessionStorage.getItem(key) || "{}");
|
||||
return layout;
|
||||
});
|
||||
for (const item of templates) {
|
||||
optimizeTemplate(item.configuration.children);
|
||||
}
|
||||
const name = `dashboards.json`;
|
||||
saveFile(templates, name);
|
||||
setTimeout(() => {
|
||||
multipleTableRef.value!.clearSelection();
|
||||
}, 2000);
|
||||
}
|
||||
function optimizeTemplate(
|
||||
children: (LayoutConfig & { moved?: boolean; standard?: unknown })[]
|
||||
) {
|
||||
for (const child of children || []) {
|
||||
delete child.moved;
|
||||
delete child.activedTabIndex;
|
||||
delete child.standard;
|
||||
if (isEmptyObject(child.graph)) {
|
||||
delete child.graph;
|
||||
}
|
||||
if (child.widget) {
|
||||
if (child.widget.title === "") {
|
||||
delete child.widget.title;
|
||||
}
|
||||
if (child.widget.tips === "") {
|
||||
delete child.widget.tips;
|
||||
}
|
||||
}
|
||||
if (isEmptyObject(child.widget)) {
|
||||
delete child.widget;
|
||||
}
|
||||
if (!(child.metrics && child.metrics.length && child.metrics[0])) {
|
||||
delete child.metrics;
|
||||
}
|
||||
if (
|
||||
!(child.metricTypes && child.metricTypes.length && child.metricTypes[0])
|
||||
) {
|
||||
delete child.metricTypes;
|
||||
}
|
||||
if (child.metricConfig && child.metricConfig.length) {
|
||||
child.metricConfig.forEach((c, index) => {
|
||||
if (!c.calculation) {
|
||||
delete c.calculation;
|
||||
}
|
||||
if (!c.unit) {
|
||||
delete c.unit;
|
||||
}
|
||||
if (!c.label) {
|
||||
delete c.label;
|
||||
}
|
||||
if (isEmptyObject(c)) {
|
||||
(child.metricConfig || []).splice(index, 1);
|
||||
}
|
||||
});
|
||||
}
|
||||
if (!(child.metricConfig && child.metricConfig.length)) {
|
||||
delete child.metricConfig;
|
||||
}
|
||||
if (child.type === "Tab") {
|
||||
for (const item of child.children || []) {
|
||||
optimizeTemplate(item.children);
|
||||
}
|
||||
}
|
||||
if (
|
||||
["Trace", "Topology", "Tab", "Profile", "Ebpf", "Log"].includes(
|
||||
child.type
|
||||
)
|
||||
) {
|
||||
delete child.widget;
|
||||
}
|
||||
}
|
||||
}
|
||||
function handleEdit(row: DashboardItem) {
|
||||
dashboardStore.setMode(true);
|
||||
dashboardStore.setEntity(row.entity);
|
||||
@@ -457,4 +524,9 @@ function changePage(pageIndex: number) {
|
||||
.reload {
|
||||
margin-right: 3px;
|
||||
}
|
||||
|
||||
.reload-btn {
|
||||
display: inline-block;
|
||||
margin-left: 10px;
|
||||
}
|
||||
</style>
|
||||
|
@@ -41,7 +41,6 @@ import { useDashboardStore } from "@/store/modules/dashboard";
|
||||
|
||||
const { t } = useI18n();
|
||||
const dashboardStore = useDashboardStore();
|
||||
const { selectedGrid } = dashboardStore;
|
||||
const widget = dashboardStore.selectedGrid.widget || {};
|
||||
const title = ref<string>(widget.title || "");
|
||||
const tips = ref<string>(widget.tips || "");
|
||||
@@ -51,6 +50,7 @@ function updateWidgetConfig(param: { [key: string]: string }) {
|
||||
if (!key) {
|
||||
return;
|
||||
}
|
||||
const { selectedGrid } = dashboardStore;
|
||||
const widget = {
|
||||
...dashboardStore.selectedGrid.widget,
|
||||
[key]: decodeURIComponent(param[key]),
|
||||
|
@@ -203,16 +203,13 @@ async function setMetricType(chart?: any) {
|
||||
}
|
||||
);
|
||||
const metrics: any = states.metricList.filter(
|
||||
(d: { value: string; type: string }) => {
|
||||
const index = states.metrics.findIndex((m: string) => m === d.value);
|
||||
if (index > -1) {
|
||||
return d;
|
||||
}
|
||||
}
|
||||
(d: { value: string; type: string }) => states.metrics.includes(d.value)
|
||||
);
|
||||
|
||||
if (metrics.length) {
|
||||
states.metrics = metrics.map((d: { value: string }) => d.value);
|
||||
// keep states.metrics index
|
||||
const m = metrics.map((d: { value: string }) => d.value);
|
||||
states.metrics = states.metrics.filter((d) => m.includes(d));
|
||||
} else {
|
||||
states.metrics = [""];
|
||||
states.metricTypes = [""];
|
||||
@@ -466,7 +463,7 @@ function setMetricConfig(index: number) {
|
||||
.chart-types {
|
||||
span {
|
||||
display: inline-block;
|
||||
padding: 5px 10px;
|
||||
padding: 2px 10px;
|
||||
border: 1px solid #ccc;
|
||||
background-color: #fff;
|
||||
border-right: 0;
|
||||
|
93
src/views/dashboard/controls/DemandLog.vue
Normal file
@@ -0,0 +1,93 @@
|
||||
<!-- 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="log-wrapper flex-v">
|
||||
<el-popover
|
||||
placement="bottom"
|
||||
trigger="click"
|
||||
:width="100"
|
||||
v-if="dashboardStore.editMode"
|
||||
>
|
||||
<template #reference>
|
||||
<span class="delete cp">
|
||||
<Icon iconName="ellipsis_v" size="middle" class="operation" />
|
||||
</span>
|
||||
</template>
|
||||
<div class="tools" @click="removeWidget">
|
||||
<span>{{ t("delete") }}</span>
|
||||
</div>
|
||||
</el-popover>
|
||||
<div class="header">
|
||||
<Header />
|
||||
</div>
|
||||
<Content />
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||
import Header from "../related/demand-log/Header.vue";
|
||||
import Content from "../related/demand-log/Content.vue";
|
||||
|
||||
/*global defineProps */
|
||||
const props = defineProps({
|
||||
data: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
activeIndex: { type: String, default: "" },
|
||||
});
|
||||
const { t } = useI18n();
|
||||
const dashboardStore = useDashboardStore();
|
||||
|
||||
function removeWidget() {
|
||||
dashboardStore.removeControls(props.data);
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.log-wrapper {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
font-size: 12px;
|
||||
position: relative;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.delete {
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
right: 3px;
|
||||
}
|
||||
|
||||
.header {
|
||||
padding: 10px;
|
||||
font-size: 12px;
|
||||
border-bottom: 1px solid #dcdfe6;
|
||||
min-width: 1024px;
|
||||
}
|
||||
|
||||
.tools {
|
||||
padding: 5px 0;
|
||||
color: #999;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
text-align: center;
|
||||
|
||||
&:hover {
|
||||
color: #409eff;
|
||||
background-color: #eee;
|
||||
}
|
||||
}
|
||||
</style>
|
95
src/views/dashboard/controls/Ebpf.vue
Normal file
@@ -0,0 +1,95 @@
|
||||
<!-- 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">
|
||||
<el-popover
|
||||
placement="bottom"
|
||||
trigger="click"
|
||||
:width="100"
|
||||
v-if="dashboardStore.editMode"
|
||||
>
|
||||
<template #reference>
|
||||
<span class="delete cp">
|
||||
<Icon iconName="ellipsis_v" size="middle" class="operation" />
|
||||
</span>
|
||||
</template>
|
||||
<div class="tools" @click="removeWidget">
|
||||
<span>{{ t("delete") }}</span>
|
||||
</div>
|
||||
</el-popover>
|
||||
<Header />
|
||||
<Content />
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import type { PropType } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||
import Header from "../related/ebpf/Header.vue";
|
||||
import Content from "../related/ebpf/Content.vue";
|
||||
|
||||
/*global defineProps */
|
||||
const props = defineProps({
|
||||
data: {
|
||||
type: Object as PropType<any>,
|
||||
default: () => ({ graph: {} }),
|
||||
},
|
||||
activeIndex: { type: String, default: "" },
|
||||
});
|
||||
const { t } = useI18n();
|
||||
const dashboardStore = useDashboardStore();
|
||||
|
||||
function removeWidget() {
|
||||
dashboardStore.removeControls(props.data);
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.profile-wrapper {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
font-size: 12px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.delete {
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
.trace {
|
||||
width: 100%;
|
||||
overflow: auto;
|
||||
}
|
||||
</style>
|
@@ -64,6 +64,7 @@ function removeWidget() {
|
||||
height: 100%;
|
||||
font-size: 12px;
|
||||
position: relative;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.delete {
|
||||
@@ -76,6 +77,7 @@ function removeWidget() {
|
||||
padding: 10px;
|
||||
font-size: 12px;
|
||||
border-bottom: 1px solid #dcdfe6;
|
||||
min-width: 1024px;
|
||||
}
|
||||
|
||||
.tools {
|
||||
@@ -93,6 +95,5 @@ function removeWidget() {
|
||||
|
||||
.log {
|
||||
width: 100%;
|
||||
overflow: auto;
|
||||
}
|
||||
</style>
|
||||
|
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License. -->
|
||||
<template>
|
||||
<div class="flex-h tab-header">
|
||||
<div class="tabs">
|
||||
<div class="tabs scroll_bar_style" @click="handleClick">
|
||||
<span
|
||||
v-for="(child, idx) in data.children || []"
|
||||
:key="idx"
|
||||
@@ -26,15 +26,15 @@ limitations under the License. -->
|
||||
v-model="child.name"
|
||||
placeholder="Please input"
|
||||
class="tab-name"
|
||||
:readonly="isNaN(editTabIndex)"
|
||||
:class="{ view: isNaN(editTabIndex) }"
|
||||
:readonly="isNaN(editTabIndex) && !canEditTabName"
|
||||
:class="{ view: !canEditTabName }"
|
||||
/>
|
||||
<Icon
|
||||
v-show="activeTabIndex === idx"
|
||||
size="sm"
|
||||
iconName="cancel"
|
||||
@click="deleteTabItem($event, idx)"
|
||||
v-if="dashboardStore.editMode"
|
||||
v-if="dashboardStore.editMode && canEditTabName"
|
||||
/>
|
||||
</span>
|
||||
<span class="tab-icons" v-if="dashboardStore.editMode">
|
||||
@@ -46,35 +46,21 @@ limitations under the License. -->
|
||||
</span>
|
||||
</div>
|
||||
<div class="operations" v-if="dashboardStore.editMode">
|
||||
<el-popover
|
||||
placement="bottom"
|
||||
trigger="click"
|
||||
:width="200"
|
||||
v-model:visible="showTools"
|
||||
>
|
||||
<template #reference>
|
||||
<span>
|
||||
<Icon
|
||||
iconName="ellipsis_v"
|
||||
size="middle"
|
||||
class="operation"
|
||||
@click="showTools = true"
|
||||
/>
|
||||
</span>
|
||||
<el-dropdown placement="bottom" trigger="click" :width="200">
|
||||
<span class="icon-operation">
|
||||
<Icon iconName="ellipsis_v" size="middle" />
|
||||
</span>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item @click="canEditTabName = true">
|
||||
<span class="edit-tab">{{ t("editTab") }}</span>
|
||||
</el-dropdown-item>
|
||||
<el-dropdown-item @click="removeTab">
|
||||
<span>{{ t("delete") }}</span>
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
<div
|
||||
class="tools"
|
||||
@click="
|
||||
canEditTabName = true;
|
||||
showTools = false;
|
||||
"
|
||||
>
|
||||
<span class="edit-tab">{{ t("editTab") }}</span>
|
||||
</div>
|
||||
<div class="tools" @click="removeTab">
|
||||
<span>{{ t("delete") }}</span>
|
||||
</div>
|
||||
</el-popover>
|
||||
</el-dropdown>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tab-layout" @click="handleClick">
|
||||
@@ -97,7 +83,7 @@ limitations under the License. -->
|
||||
:key="item.i"
|
||||
@click="clickTabGrid($event, item)"
|
||||
:class="{ active: activeTabWidget === item.i }"
|
||||
drag-ignore-from="svg.d3-trace-tree, .dragger, .micro-topo-chart"
|
||||
:drag-ignore-from="dragIgnoreFrom"
|
||||
>
|
||||
<component
|
||||
:is="item.type"
|
||||
@@ -122,6 +108,9 @@ import Trace from "./Trace.vue";
|
||||
import Profile from "./Profile.vue";
|
||||
import Log from "./Log.vue";
|
||||
import Text from "./Text.vue";
|
||||
import Ebpf from "./Ebpf.vue";
|
||||
import { dragIgnoreFrom } from "../data";
|
||||
import DemandLog from "./DemandLog.vue";
|
||||
|
||||
const props = {
|
||||
data: {
|
||||
@@ -132,7 +121,7 @@ const props = {
|
||||
};
|
||||
export default defineComponent({
|
||||
name: "Tab",
|
||||
components: { Topology, Widget, Trace, Profile, Log, Text },
|
||||
components: { Topology, Widget, Trace, Profile, Log, Text, Ebpf, DemandLog },
|
||||
props,
|
||||
setup(props) {
|
||||
const { t } = useI18n();
|
||||
@@ -142,7 +131,6 @@ export default defineComponent({
|
||||
const editTabIndex = ref<number>(NaN); // edit tab item name
|
||||
const canEditTabName = ref<boolean>(false);
|
||||
const needQuery = ref<boolean>(false);
|
||||
const showTools = ref<boolean>(false);
|
||||
const l = dashboardStore.layout.findIndex(
|
||||
(d: LayoutConfig) => d.i === props.data.i
|
||||
);
|
||||
@@ -246,8 +234,8 @@ export default defineComponent({
|
||||
editTabIndex,
|
||||
needQuery,
|
||||
canEditTabName,
|
||||
showTools,
|
||||
t,
|
||||
dragIgnoreFrom,
|
||||
};
|
||||
},
|
||||
});
|
||||
@@ -256,24 +244,30 @@ export default defineComponent({
|
||||
.tabs {
|
||||
height: 40px;
|
||||
color: #ccc;
|
||||
width: 100%;
|
||||
overflow-x: auto;
|
||||
white-space: nowrap;
|
||||
overflow-y: hidden;
|
||||
|
||||
span {
|
||||
display: inline-block;
|
||||
padding: 0 10px;
|
||||
margin: 0 10px;
|
||||
height: 40px;
|
||||
line-height: 40px;
|
||||
cursor: pointer;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.tab-name {
|
||||
max-width: 130px;
|
||||
max-width: 110px;
|
||||
height: 20px;
|
||||
line-height: 20px;
|
||||
outline: none;
|
||||
color: #333;
|
||||
font-style: normal;
|
||||
margin-right: 5px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.tab-icons {
|
||||
@@ -294,7 +288,10 @@ export default defineComponent({
|
||||
|
||||
span.active {
|
||||
border-bottom: 1px solid #409eff;
|
||||
color: #409eff;
|
||||
|
||||
.tab-name {
|
||||
color: #409eff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -306,6 +303,11 @@ export default defineComponent({
|
||||
padding-right: 10px;
|
||||
}
|
||||
|
||||
.icon-operation {
|
||||
display: inline-block;
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.tab-header {
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
@@ -339,17 +341,4 @@ export default defineComponent({
|
||||
padding-top: 30px;
|
||||
color: #888;
|
||||
}
|
||||
|
||||
.tools {
|
||||
padding: 5px 0;
|
||||
color: #999;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
text-align: center;
|
||||
|
||||
&:hover {
|
||||
color: #409eff;
|
||||
background-color: #eee;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@@ -105,6 +105,7 @@ function editConfig() {
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.tools {
|
||||
|
@@ -66,6 +66,7 @@ function removeWidget() {
|
||||
height: 100%;
|
||||
font-size: 12px;
|
||||
position: relative;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.delete {
|
||||
@@ -78,6 +79,7 @@ function removeWidget() {
|
||||
padding: 10px;
|
||||
font-size: 12px;
|
||||
border-bottom: 1px solid #dcdfe6;
|
||||
min-width: 1200px;
|
||||
}
|
||||
|
||||
.tools {
|
||||
@@ -96,5 +98,6 @@ function removeWidget() {
|
||||
.trace {
|
||||
width: 100%;
|
||||
overflow: auto;
|
||||
min-width: 1200px;
|
||||
}
|
||||
</style>
|
||||
|
@@ -21,5 +21,17 @@ import Trace from "./Trace.vue";
|
||||
import Profile from "./Profile.vue";
|
||||
import Log from "./Log.vue";
|
||||
import Text from "./Text.vue";
|
||||
import Ebpf from "./Ebpf.vue";
|
||||
import DemandLog from "./DemandLog.vue";
|
||||
|
||||
export default { Tab, Widget, Trace, Topology, Profile, Log, Text };
|
||||
export default {
|
||||
Tab,
|
||||
Widget,
|
||||
Trace,
|
||||
Topology,
|
||||
Profile,
|
||||
Log,
|
||||
Text,
|
||||
Ebpf,
|
||||
DemandLog,
|
||||
};
|
||||
|
@@ -14,6 +14,8 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
export const dragIgnoreFrom =
|
||||
"svg.d3-trace-tree, .dragger, .micro-topo-chart, .schedules";
|
||||
|
||||
export const PodsChartTypes = ["EndpointList", "InstanceList"];
|
||||
|
||||
@@ -181,8 +183,10 @@ export const ServiceTools = [
|
||||
{ name: "library_books", content: "Text", id: "addText" },
|
||||
{ name: "device_hub", content: "Topology", id: "addTopology" },
|
||||
{ name: "merge", content: "Trace", id: "addTrace" },
|
||||
{ name: "timeline", content: "Profile", id: "addProfile" },
|
||||
{ name: "timeline", content: "Trace Profiling", id: "addProfile" },
|
||||
{ name: "insert_chart", content: "eBPF Profiling", id: "addEbpf" },
|
||||
{ name: "assignment", content: "Log", id: "addLog" },
|
||||
{ name: "demand", content: "Add On Demand Log", id: "addDemandLog" },
|
||||
];
|
||||
export const InstanceTools = [
|
||||
{ name: "playlist_add", content: "Add Widget", id: "addWidget" },
|
||||
@@ -190,6 +194,7 @@ export const InstanceTools = [
|
||||
{ name: "library_books", content: "Add Text", id: "addText" },
|
||||
{ name: "merge", content: "Add Trace", id: "addTrace" },
|
||||
{ name: "assignment", content: "Add Log", id: "addLog" },
|
||||
{ name: "demand", content: "Add On Demand Log", id: "addDemandLog" },
|
||||
];
|
||||
export const EndpointTools = [
|
||||
{ name: "playlist_add", content: "Add Widget", id: "addWidget" },
|
||||
@@ -263,14 +268,17 @@ export const TextColors: { [key: string]: string } = {
|
||||
export const CalculationOpts = [
|
||||
{ label: "Percentage", value: "percentage" },
|
||||
{ label: "Apdex", value: "apdex" },
|
||||
{ label: "Avg-preview", value: "average" },
|
||||
{ label: "Percentage + Avg-preview", value: "percentageAvg" },
|
||||
{ label: "Apdex + Avg-preview", value: "apdexAvg" },
|
||||
{ label: "Byte to KB", value: "byteToKB" },
|
||||
{ label: "Byte to MB", value: "byteToMB" },
|
||||
{ label: "Byte to GB", value: "byteToGB" },
|
||||
{
|
||||
label: "Convert milliseconds to YYYY-MM-DD HH:mm:ss",
|
||||
label: "Milliseconds to YYYY-MM-DD HH:mm:ss",
|
||||
value: "convertMilliseconds",
|
||||
},
|
||||
{ label: "Convert seconds to YYYY-MM-DD HH:mm:ss", value: "convertSeconds" },
|
||||
{ label: "Seconds to YYYY-MM-DD HH:mm:ss", value: "convertSeconds" },
|
||||
{ label: "Precision is 2", value: "precision" },
|
||||
{ label: "Milliseconds to seconds", value: "msTos" },
|
||||
];
|
||||
|
@@ -17,11 +17,13 @@ limitations under the License. -->
|
||||
<div
|
||||
v-if="!isNaN(singleVal)"
|
||||
class="chart-card"
|
||||
:class="{ center: config.textAlign === 'center' }"
|
||||
:style="{ fontSize: `${config.fontSize}px`, textAlign: config.textAlign }"
|
||||
:style="{
|
||||
fontSize: `${config.fontSize}px`,
|
||||
justifyContent: config.textAlign || 'center',
|
||||
}"
|
||||
>
|
||||
{{ singleVal.toFixed(2) }}
|
||||
<span v-show="config.showUnit">
|
||||
<span class="unit" v-show="config.showUnit && unit">
|
||||
{{ decodeURIComponent(unit) }}
|
||||
</span>
|
||||
</div>
|
||||
@@ -53,25 +55,27 @@ const metricConfig = computed(() => props.config.metricConfig || []);
|
||||
const key = computed(() => Object.keys(props.data)[0]);
|
||||
const singleVal = computed(() => Number(props.data[key.value]));
|
||||
const unit = computed(
|
||||
() => metricConfig.value[0] && encodeURIComponent(metricConfig.value[0].unit)
|
||||
() =>
|
||||
metricConfig.value[0] &&
|
||||
encodeURIComponent(metricConfig.value[0].unit || "")
|
||||
);
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.chart-card {
|
||||
color: #333;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.center {
|
||||
box-sizing: border-box;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: horizontal;
|
||||
-webkit-box-pack: center;
|
||||
-webkit-box-align: center;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.no-data {
|
||||
height: 100%;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.unit {
|
||||
display: inline-block;
|
||||
margin-left: 2px;
|
||||
}
|
||||
</style>
|
||||
|
@@ -42,34 +42,11 @@ limitations under the License. -->
|
||||
</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
v-for="(metric, index) in colMetrics"
|
||||
:label="`${decodeURIComponent(
|
||||
getLabel(metric, index)
|
||||
)} ${decodeURIComponent(getUnit(index))}`"
|
||||
:key="metric + index"
|
||||
>
|
||||
<template #default="scope">
|
||||
<div class="chart">
|
||||
<Line
|
||||
v-if="config.metricTypes[index] === 'readMetricsValues'"
|
||||
:data="{ [metric]: scope.row[metric] }"
|
||||
:intervalTime="intervalTime"
|
||||
:config="{
|
||||
showXAxis: false,
|
||||
showYAxis: false,
|
||||
smallTips: true,
|
||||
showSymbol: true,
|
||||
}"
|
||||
/>
|
||||
<Card
|
||||
v-else
|
||||
:data="{ [metric]: scope.row[metric] }"
|
||||
:config="{ textAlign: 'left' }"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<ColumnGraph
|
||||
:intervalTime="intervalTime"
|
||||
:colMetrics="colMetrics"
|
||||
:config="config"
|
||||
/>
|
||||
</el-table>
|
||||
</div>
|
||||
</div>
|
||||
@@ -83,12 +60,11 @@ import { EndpointListConfig } from "@/types/dashboard";
|
||||
import { Endpoint } from "@/types/selector";
|
||||
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||
import { useQueryPodsMetrics, usePodsSource } from "@/hooks/useProcessor";
|
||||
import Line from "./Line.vue";
|
||||
import Card from "./Card.vue";
|
||||
import { EntityType } from "../data";
|
||||
import router from "@/router";
|
||||
import getDashboard from "@/hooks/useDashboardsSession";
|
||||
import { MetricConfigOpt } from "@/types/dashboard";
|
||||
import ColumnGraph from "./components/ColumnGraph.vue";
|
||||
|
||||
/*global defineProps */
|
||||
const props = defineProps({
|
||||
@@ -184,26 +160,6 @@ function clickEndpoint(scope: any) {
|
||||
async function searchList() {
|
||||
await queryEndpoints();
|
||||
}
|
||||
function getUnit(index: number) {
|
||||
const u =
|
||||
props.config.metricConfig &&
|
||||
props.config.metricConfig[index] &&
|
||||
props.config.metricConfig[index].unit;
|
||||
if (u) {
|
||||
return `(${encodeURIComponent(u)})`;
|
||||
}
|
||||
return encodeURIComponent("");
|
||||
}
|
||||
function getLabel(metric: string, index: number) {
|
||||
const label =
|
||||
props.config.metricConfig &&
|
||||
props.config.metricConfig[index] &&
|
||||
props.config.metricConfig[index].label;
|
||||
if (label) {
|
||||
return encodeURIComponent(label);
|
||||
}
|
||||
return encodeURIComponent(metric);
|
||||
}
|
||||
watch(
|
||||
() => [...(props.config.metricTypes || []), ...(props.config.metrics || [])],
|
||||
(data, old) => {
|
||||
|
@@ -42,35 +42,11 @@ limitations under the License. -->
|
||||
</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
v-for="(metric, index) in colMetrics"
|
||||
:label="`${decodeURIComponent(
|
||||
getLabel(metric, index)
|
||||
)} ${decodeURIComponent(getUnit(index))}`"
|
||||
:key="metric + index"
|
||||
min-width="120"
|
||||
>
|
||||
<template #default="scope">
|
||||
<div class="chart">
|
||||
<Line
|
||||
v-if="config.metricTypes[index] === 'readMetricsValues'"
|
||||
:data="metric ? { [metric]: scope.row[metric] } : {}"
|
||||
:intervalTime="intervalTime"
|
||||
:config="{
|
||||
showXAxis: false,
|
||||
showYAxis: false,
|
||||
smallTips: true,
|
||||
showSymbol: true,
|
||||
}"
|
||||
/>
|
||||
<Card
|
||||
v-else
|
||||
:data="{ [metric]: scope.row[metric] }"
|
||||
:config="{ textAlign: 'left' }"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<ColumnGraph
|
||||
:intervalTime="intervalTime"
|
||||
:colMetrics="colMetrics"
|
||||
:config="config"
|
||||
/>
|
||||
<el-table-column label="Attributes">
|
||||
<template #default="scope">
|
||||
<el-popover placement="left" :width="400" trigger="click">
|
||||
@@ -110,8 +86,6 @@ import { ref, watch, computed } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { ElMessage } from "element-plus";
|
||||
import type { PropType } from "vue";
|
||||
import Line from "./Line.vue";
|
||||
import Card from "./Card.vue";
|
||||
import { useSelectorStore } from "@/store/modules/selectors";
|
||||
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||
import { InstanceListConfig } from "@/types/dashboard";
|
||||
@@ -121,6 +95,7 @@ import { EntityType } from "../data";
|
||||
import router from "@/router";
|
||||
import getDashboard from "@/hooks/useDashboardsSession";
|
||||
import { MetricConfigOpt } from "@/types/dashboard";
|
||||
import ColumnGraph from "./components/ColumnGraph.vue";
|
||||
|
||||
/*global defineProps */
|
||||
const props = defineProps({
|
||||
@@ -236,28 +211,6 @@ function searchList() {
|
||||
queryInstanceMetrics(instances.value);
|
||||
}
|
||||
|
||||
function getUnit(index: number) {
|
||||
const u =
|
||||
props.config.metricConfig &&
|
||||
props.config.metricConfig[index] &&
|
||||
props.config.metricConfig[index].unit;
|
||||
if (u) {
|
||||
return `(${encodeURIComponent(u)})`;
|
||||
}
|
||||
return encodeURIComponent("");
|
||||
}
|
||||
|
||||
function getLabel(metric: string, index: number) {
|
||||
const label =
|
||||
props.config.metricConfig &&
|
||||
props.config.metricConfig[index] &&
|
||||
props.config.metricConfig[index].label;
|
||||
if (label) {
|
||||
return encodeURIComponent(label);
|
||||
}
|
||||
return encodeURIComponent(metric);
|
||||
}
|
||||
|
||||
watch(
|
||||
() => [...(props.config.metricTypes || []), ...(props.config.metrics || [])],
|
||||
(data, old) => {
|
||||
|
@@ -40,6 +40,7 @@ const props = defineProps({
|
||||
showXAxis: true,
|
||||
showYAxis: true,
|
||||
smallTips: false,
|
||||
showlabels: true,
|
||||
}),
|
||||
},
|
||||
});
|
||||
@@ -185,7 +186,8 @@ function getOption() {
|
||||
left: 0,
|
||||
right: 10,
|
||||
bottom: 5,
|
||||
containLabel: true,
|
||||
containLabel:
|
||||
props.config.showlabels === undefined ? true : props.config.showlabels,
|
||||
},
|
||||
xAxis: {
|
||||
type: "category",
|
||||
@@ -199,6 +201,7 @@ function getOption() {
|
||||
axisLabel: { color: "#9da5b2", fontSize: "11" },
|
||||
},
|
||||
yAxis: {
|
||||
show: props.config.showYAxis,
|
||||
type: "value",
|
||||
axisLine: { show: false },
|
||||
axisTick: { show: false },
|
||||
|
@@ -54,34 +54,11 @@ limitations under the License. -->
|
||||
</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
v-for="(metric, index) in colMetrics"
|
||||
:label="`${decodeURIComponent(
|
||||
getLabel(metric, index)
|
||||
)} ${decodeURIComponent(getUnit(index))}`"
|
||||
:key="metric + index"
|
||||
>
|
||||
<template #default="scope">
|
||||
<div class="chart">
|
||||
<Line
|
||||
v-if="config.metricTypes[index] === 'readMetricsValues'"
|
||||
:data="{ [metric]: scope.row[metric] }"
|
||||
:intervalTime="intervalTime"
|
||||
:config="{
|
||||
showXAxis: false,
|
||||
showYAxis: false,
|
||||
smallTips: true,
|
||||
showSymbol: true,
|
||||
}"
|
||||
/>
|
||||
<Card
|
||||
v-else
|
||||
:data="{ [metric]: scope.row[metric] }"
|
||||
:config="{ textAlign: 'left' }"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<ColumnGraph
|
||||
:intervalTime="intervalTime"
|
||||
:colMetrics="colMetrics"
|
||||
:config="config"
|
||||
/>
|
||||
</el-table>
|
||||
</div>
|
||||
<el-pagination
|
||||
@@ -102,8 +79,6 @@ import { watch, ref, computed } from "vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
import type { PropType } from "vue";
|
||||
import { ServiceListConfig } from "@/types/dashboard";
|
||||
import Line from "./Line.vue";
|
||||
import Card from "./Card.vue";
|
||||
import { useSelectorStore } from "@/store/modules/selectors";
|
||||
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||
import { Service } from "@/types/selector";
|
||||
@@ -112,6 +87,7 @@ import { EntityType } from "../data";
|
||||
import router from "@/router";
|
||||
import getDashboard from "@/hooks/useDashboardsSession";
|
||||
import { MetricConfigOpt } from "@/types/dashboard";
|
||||
import ColumnGraph from "./components/ColumnGraph.vue";
|
||||
|
||||
/*global defineProps */
|
||||
const props = defineProps({
|
||||
@@ -240,6 +216,7 @@ async function queryServiceMetrics(currentServices: Service[]) {
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
services.value = currentServices;
|
||||
}
|
||||
function objectSpanMethod(param: any): any {
|
||||
@@ -275,26 +252,6 @@ function searchList() {
|
||||
);
|
||||
setServices(services);
|
||||
}
|
||||
function getUnit(index: number) {
|
||||
const u =
|
||||
props.config.metricConfig &&
|
||||
props.config.metricConfig[index] &&
|
||||
props.config.metricConfig[index].unit;
|
||||
if (u) {
|
||||
return `(${encodeURIComponent(u)})`;
|
||||
}
|
||||
return encodeURIComponent("");
|
||||
}
|
||||
function getLabel(metric: string, index: number) {
|
||||
const label =
|
||||
props.config.metricConfig &&
|
||||
props.config.metricConfig[index] &&
|
||||
props.config.metricConfig[index].label;
|
||||
if (label) {
|
||||
return encodeURIComponent(label);
|
||||
}
|
||||
return encodeURIComponent(metric);
|
||||
}
|
||||
|
||||
watch(
|
||||
() => [...(props.config.metricTypes || []), ...(props.config.metrics || [])],
|
||||
@@ -318,10 +275,6 @@ watch(
|
||||
<style lang="scss" scoped>
|
||||
@import "./style.scss";
|
||||
|
||||
.chart {
|
||||
height: 60px;
|
||||
}
|
||||
|
||||
.inputs {
|
||||
width: 300px;
|
||||
}
|
||||
|
@@ -17,13 +17,13 @@ limitations under the License. -->
|
||||
<div class="top-list" v-if="available">
|
||||
<div class="chart-slow-i" v-for="(i, index) in data[key]" :key="index">
|
||||
<div class="ell tools flex-h">
|
||||
<div>
|
||||
<div class="desc">
|
||||
<span class="calls mr-10">{{ i.value }}</span>
|
||||
<span class="cp mr-20">
|
||||
{{ i.name }}
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<div class="copy">
|
||||
<Icon
|
||||
iconName="review-list"
|
||||
size="middle"
|
||||
@@ -103,6 +103,16 @@ function handleClick(i: string) {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.desc {
|
||||
flex-grow: 2;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.copy {
|
||||
width: 30px;
|
||||
}
|
||||
|
||||
.calls {
|
||||
font-size: 12px;
|
||||
padding: 0 5px;
|
||||
|
161
src/views/dashboard/graphs/components/ColumnGraph.vue
Normal file
@@ -0,0 +1,161 @@
|
||||
<!-- 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>
|
||||
<el-table-column
|
||||
v-for="(metric, index) in colMetrics"
|
||||
:label="`${decodeURIComponent(
|
||||
getLabel(metric, index)
|
||||
)} ${decodeURIComponent(getUnit(index))}`"
|
||||
:key="metric + index"
|
||||
>
|
||||
<template #default="scope">
|
||||
<div class="chart">
|
||||
<Line
|
||||
v-if="useListConfig(config, index).isLinear"
|
||||
:data="{
|
||||
[metric]: scope.row[metric] && scope.row[metric].values,
|
||||
}"
|
||||
:intervalTime="intervalTime"
|
||||
:config="{
|
||||
showXAxis: false,
|
||||
showYAxis: false,
|
||||
smallTips: true,
|
||||
showlabels: false,
|
||||
}"
|
||||
/>
|
||||
<span
|
||||
class="item flex-h"
|
||||
v-else-if="useListConfig(config, index).isAvg"
|
||||
>
|
||||
<el-popover placement="left" :width="400" trigger="click">
|
||||
<template #reference>
|
||||
<span class="trend">
|
||||
<Icon
|
||||
iconName="timeline"
|
||||
size="middle"
|
||||
style="color: #409eff"
|
||||
/>
|
||||
</span>
|
||||
</template>
|
||||
<div class="view-line">
|
||||
<Line
|
||||
:data="{
|
||||
[metric]: scope.row[metric] && scope.row[metric].values,
|
||||
}"
|
||||
:intervalTime="intervalTime"
|
||||
:config="{
|
||||
showXAxis: true,
|
||||
showYAxis: true,
|
||||
smallTips: false,
|
||||
showlabels: true,
|
||||
}"
|
||||
/>
|
||||
</div>
|
||||
</el-popover>
|
||||
<span class="value">
|
||||
<Card
|
||||
:data="{
|
||||
[metric]: scope.row[metric] && scope.row[metric].avg,
|
||||
}"
|
||||
:config="{ textAlign: 'left' }"
|
||||
/>
|
||||
</span>
|
||||
</span>
|
||||
<Card
|
||||
v-else
|
||||
:data="{ [metric]: scope.row[metric] }"
|
||||
:config="{ textAlign: 'left' }"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import type { PropType } from "vue";
|
||||
import { MetricConfigOpt } from "@/types/dashboard";
|
||||
import { useListConfig } from "@/hooks/useListConfig";
|
||||
import Line from "../Line.vue";
|
||||
import Card from "../Card.vue";
|
||||
|
||||
/*global defineProps */
|
||||
const props = defineProps({
|
||||
colMetrics: { type: Object },
|
||||
config: {
|
||||
type: Object as PropType<
|
||||
{
|
||||
i: string;
|
||||
metrics: string[];
|
||||
metricTypes: string[];
|
||||
} & { metricConfig: MetricConfigOpt[] }
|
||||
>,
|
||||
default: () => ({}),
|
||||
},
|
||||
intervalTime: { type: Array as PropType<string[]>, default: () => [] },
|
||||
});
|
||||
|
||||
function getUnit(index: string) {
|
||||
const i = Number(index);
|
||||
const u =
|
||||
props.config.metricConfig &&
|
||||
props.config.metricConfig[i] &&
|
||||
props.config.metricConfig[i].unit;
|
||||
if (u) {
|
||||
return `(${encodeURIComponent(u)})`;
|
||||
}
|
||||
return encodeURIComponent("");
|
||||
}
|
||||
function getLabel(metric: string, index: string) {
|
||||
const i = Number(index);
|
||||
const label =
|
||||
props.config.metricConfig &&
|
||||
props.config.metricConfig[i] &&
|
||||
props.config.metricConfig[i].label;
|
||||
if (label) {
|
||||
return encodeURIComponent(label);
|
||||
}
|
||||
return encodeURIComponent(metric);
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.chart {
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
.view-line {
|
||||
width: 380px;
|
||||
height: 200px;
|
||||
}
|
||||
|
||||
.item {
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.trend {
|
||||
width: 30px;
|
||||
display: inline-block;
|
||||
height: 100%;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.value {
|
||||
display: inline-block;
|
||||
flex-grow: 2;
|
||||
height: 100%;
|
||||
}
|
||||
</style>
|
@@ -29,9 +29,9 @@ limitations under the License. -->
|
||||
:h="item.h"
|
||||
:i="item.i"
|
||||
:key="item.i"
|
||||
@click="clickGrid(item)"
|
||||
@click="clickGrid(item, $event)"
|
||||
:class="{ active: dashboardStore.activedGridItem === item.i }"
|
||||
drag-ignore-from="svg.d3-trace-tree, .dragger, .micro-topo-chart"
|
||||
:drag-ignore-from="dragIgnoreFrom"
|
||||
>
|
||||
<component :is="item.type" :data="item" />
|
||||
</grid-item>
|
||||
@@ -45,6 +45,7 @@ import { useDashboardStore } from "@/store/modules/dashboard";
|
||||
import { useSelectorStore } from "@/store/modules/selectors";
|
||||
import { LayoutConfig } from "@/types/dashboard";
|
||||
import controls from "../controls/index";
|
||||
import { dragIgnoreFrom } from "../data";
|
||||
|
||||
export default defineComponent({
|
||||
name: "Layout",
|
||||
@@ -53,13 +54,14 @@ export default defineComponent({
|
||||
const { t } = useI18n();
|
||||
const dashboardStore = useDashboardStore();
|
||||
const selectorStore = useSelectorStore();
|
||||
// function layoutUpdatedEvent(newLayout: LayoutConfig[]) {
|
||||
// dashboardStore.setLayout(newLayout);
|
||||
// }
|
||||
function clickGrid(item: LayoutConfig) {
|
||||
|
||||
function clickGrid(item: LayoutConfig, event: Event) {
|
||||
dashboardStore.activeGridItem(item.i);
|
||||
dashboardStore.selectWidget(item);
|
||||
if (item.type === "Tab") {
|
||||
if (
|
||||
item.type === "Tab" &&
|
||||
(event.target as HTMLDivElement)?.className !== "tab-layout"
|
||||
) {
|
||||
dashboardStore.setActiveTabIndex(0);
|
||||
}
|
||||
}
|
||||
@@ -68,11 +70,13 @@ export default defineComponent({
|
||||
selectorStore.setCurrentService(null);
|
||||
selectorStore.setCurrentPod(null);
|
||||
dashboardStore.setEntity("");
|
||||
dashboardStore.setConfigPanel(false);
|
||||
});
|
||||
return {
|
||||
dashboardStore,
|
||||
clickGrid,
|
||||
t,
|
||||
dragIgnoreFrom,
|
||||
};
|
||||
},
|
||||
});
|
||||
|
@@ -78,9 +78,9 @@ limitations under the License. -->
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex-h tools" v-loading="loading">
|
||||
<div class="flex-h tools" v-loading="loading" v-if="!appStore.isMobile">
|
||||
<div class="tool-icons flex-h" v-if="dashboardStore.editMode">
|
||||
<el-dropdown content="Controls" placement="bottom">
|
||||
<el-dropdown content="Controls" placement="bottom" :persistent="false">
|
||||
<i>
|
||||
<Icon class="icon-btn" size="sm" iconName="control" />
|
||||
</i>
|
||||
@@ -217,12 +217,23 @@ async function setSelector() {
|
||||
return;
|
||||
}
|
||||
let currentService, currentDestService;
|
||||
for (const d of selectorStore.services) {
|
||||
if (d.id === String(params.serviceId)) {
|
||||
currentService = d;
|
||||
if (states.currentService) {
|
||||
for (const d of selectorStore.services) {
|
||||
if (d.value === states.currentService) {
|
||||
currentService = d;
|
||||
}
|
||||
if (d.value === states.currentDestService) {
|
||||
currentDestService = d;
|
||||
}
|
||||
}
|
||||
if (d.id === String(params.destServiceId)) {
|
||||
currentDestService = d;
|
||||
} else {
|
||||
for (const d of selectorStore.services) {
|
||||
if (d.id === String(params.serviceId)) {
|
||||
currentService = d;
|
||||
}
|
||||
if (d.id === String(params.destServiceId)) {
|
||||
currentDestService = d;
|
||||
}
|
||||
}
|
||||
}
|
||||
selectorStore.setCurrentService(currentService);
|
||||
@@ -244,9 +255,14 @@ async function setSourceSelector() {
|
||||
return;
|
||||
}
|
||||
const pod = params.podId || selectorStore.pods[0].id;
|
||||
const currentPod = selectorStore.pods.find(
|
||||
(d: { id: string }) => d.id === pod
|
||||
);
|
||||
let currentPod;
|
||||
if (states.currentPod) {
|
||||
currentPod = selectorStore.pods.find(
|
||||
(d: { label: string }) => d.label === states.currentPod
|
||||
);
|
||||
} else {
|
||||
currentPod = selectorStore.pods.find((d: { id: string }) => d.id === pod);
|
||||
}
|
||||
if (currentPod) {
|
||||
selectorStore.setCurrentPod(currentPod);
|
||||
states.currentPod = currentPod.label;
|
||||
@@ -267,9 +283,16 @@ async function setDestSelector() {
|
||||
return;
|
||||
}
|
||||
const destPod = params.destPodId || selectorStore.destPods[0].id;
|
||||
const currentDestPod = selectorStore.destPods.find(
|
||||
(d: { id: string }) => d.id === destPod
|
||||
);
|
||||
let currentDestPod = { label: "" };
|
||||
if (states.currentDestPod) {
|
||||
currentDestPod = selectorStore.pods.find(
|
||||
(d: { label: string }) => d.label === states.currentDestPod
|
||||
);
|
||||
} else {
|
||||
currentDestPod = selectorStore.destPods.find(
|
||||
(d: { id: string }) => d.id === destPod
|
||||
);
|
||||
}
|
||||
if (currentDestPod) {
|
||||
selectorStore.setCurrentDestPod(currentDestPod);
|
||||
states.currentDestPod = currentDestPod.label;
|
||||
@@ -291,19 +314,40 @@ async function getServices() {
|
||||
ElMessage.error(json.errors);
|
||||
return;
|
||||
}
|
||||
selectorStore.setCurrentService(
|
||||
selectorStore.services.length ? selectorStore.services[0] : null
|
||||
);
|
||||
selectorStore.setCurrentDestService(
|
||||
selectorStore.services.length ? selectorStore.services[1] : null
|
||||
);
|
||||
let s;
|
||||
if (states.currentService) {
|
||||
s = (selectorStore.services || []).find(
|
||||
(d: { label: string }) => d.label === states.currentService
|
||||
);
|
||||
} else {
|
||||
s = (selectorStore.services || []).find(
|
||||
(d: unknown, index: number) => index === 0
|
||||
);
|
||||
}
|
||||
selectorStore.setCurrentService(s || null);
|
||||
let d;
|
||||
if (states.currentService) {
|
||||
d = (selectorStore.services || []).find(
|
||||
(d: { label: string }) => d.label === states.currentDestService
|
||||
);
|
||||
} else {
|
||||
d = (selectorStore.services || []).find(
|
||||
(d: unknown, index: number) => index === 1
|
||||
);
|
||||
}
|
||||
selectorStore.setCurrentDestService(d || null);
|
||||
if (!selectorStore.currentService) {
|
||||
return;
|
||||
}
|
||||
states.currentService = selectorStore.currentService.value;
|
||||
const e = dashboardStore.entity.split("Relation")[0];
|
||||
if (
|
||||
[EntityType[2].value, EntityType[3].value].includes(dashboardStore.entity)
|
||||
[
|
||||
EntityType[2].value,
|
||||
EntityType[3].value,
|
||||
EntityType[5].value,
|
||||
EntityType[6].value,
|
||||
].includes(dashboardStore.entity)
|
||||
) {
|
||||
fetchPods(e, selectorStore.currentService.id, true);
|
||||
}
|
||||
@@ -322,7 +366,10 @@ async function changeService(service: any) {
|
||||
if (service[0]) {
|
||||
states.currentService = service[0].value;
|
||||
selectorStore.setCurrentService(service[0]);
|
||||
fetchPods(dashboardStore.entity, selectorStore.currentService.id, true);
|
||||
const e = dashboardStore.entity.split("Relation")[0];
|
||||
selectorStore.setCurrentPod(null);
|
||||
states.currentPod = "";
|
||||
fetchPods(e, selectorStore.currentService.id, true);
|
||||
} else {
|
||||
selectorStore.setCurrentService(null);
|
||||
}
|
||||
@@ -332,6 +379,9 @@ function changeDestService(service: any) {
|
||||
if (service[0]) {
|
||||
states.currentDestService = service[0].value;
|
||||
selectorStore.setCurrentDestService(service[0]);
|
||||
selectorStore.setCurrentDestPod(null);
|
||||
states.currentDestPod = "";
|
||||
fetchPods(dashboardStore.entity, selectorStore.currentDestService.id, true);
|
||||
} else {
|
||||
selectorStore.setCurrentDestService(null);
|
||||
}
|
||||
@@ -396,12 +446,18 @@ function setTabControls(id: string) {
|
||||
case "addProfile":
|
||||
dashboardStore.addTabControls("Profile");
|
||||
break;
|
||||
case "addEbpf":
|
||||
dashboardStore.addTabControls("Ebpf");
|
||||
break;
|
||||
case "addTopology":
|
||||
dashboardStore.addTabControls("Topology");
|
||||
break;
|
||||
case "addText":
|
||||
dashboardStore.addTabControls("Text");
|
||||
break;
|
||||
case "addDemandLog":
|
||||
dashboardStore.addTabControls("DemandLog");
|
||||
break;
|
||||
default:
|
||||
ElMessage.info("Don't support this control");
|
||||
break;
|
||||
@@ -422,6 +478,9 @@ function setControls(id: string) {
|
||||
case "addProfile":
|
||||
dashboardStore.addControl("Profile");
|
||||
break;
|
||||
case "addEbpf":
|
||||
dashboardStore.addControl("Ebpf");
|
||||
break;
|
||||
case "addLog":
|
||||
dashboardStore.addControl("Log");
|
||||
break;
|
||||
@@ -431,6 +490,9 @@ function setControls(id: string) {
|
||||
case "addText":
|
||||
dashboardStore.addControl("Text");
|
||||
break;
|
||||
case "addDemandLog":
|
||||
dashboardStore.addControl("DemandLog");
|
||||
break;
|
||||
default:
|
||||
dashboardStore.addControl("Widget");
|
||||
}
|
||||
@@ -447,18 +509,34 @@ async function fetchPods(
|
||||
case EntityType[2].value:
|
||||
resp = await selectorStore.getEndpoints({ serviceId, ...param });
|
||||
if (setPod) {
|
||||
selectorStore.setCurrentPod(
|
||||
selectorStore.pods.length ? selectorStore.pods[0] : null
|
||||
);
|
||||
let p;
|
||||
if (states.currentPod) {
|
||||
p = selectorStore.pods.find(
|
||||
(d: { label: unknown }) => d.label === states.currentPod
|
||||
);
|
||||
} else {
|
||||
p = selectorStore.pods.find(
|
||||
(d: unknown, index: number) => index === 0
|
||||
);
|
||||
}
|
||||
selectorStore.setCurrentPod(p || null);
|
||||
states.currentPod = selectorStore.currentPod.label;
|
||||
}
|
||||
break;
|
||||
case EntityType[3].value:
|
||||
resp = await selectorStore.getServiceInstances({ serviceId });
|
||||
if (setPod) {
|
||||
selectorStore.setCurrentPod(
|
||||
selectorStore.pods.length ? selectorStore.pods[0] : null
|
||||
);
|
||||
let p;
|
||||
if (states.currentPod) {
|
||||
p = selectorStore.pods.find(
|
||||
(d: { label: string }) => d.label === states.currentPod
|
||||
);
|
||||
} else {
|
||||
p = selectorStore.pods.find(
|
||||
(d: { label: string }, index: number) => index === 0
|
||||
);
|
||||
}
|
||||
selectorStore.setCurrentPod(p || null);
|
||||
states.currentPod = selectorStore.currentPod.label;
|
||||
}
|
||||
break;
|
||||
@@ -469,9 +547,17 @@ async function fetchPods(
|
||||
...param,
|
||||
});
|
||||
if (setPod) {
|
||||
selectorStore.setCurrentDestPod(
|
||||
selectorStore.destPods.length ? selectorStore.destPods[0] : null
|
||||
);
|
||||
let p;
|
||||
if (states.currentDestPod) {
|
||||
p = selectorStore.destPods.find(
|
||||
(d: { label: string }) => d.label === states.currentDestPod
|
||||
);
|
||||
} else {
|
||||
p = selectorStore.destPods.find(
|
||||
(d: { label: string }, index: number) => index === 0
|
||||
);
|
||||
}
|
||||
selectorStore.setCurrentDestPod(p || null);
|
||||
states.currentDestPod = selectorStore.currentDestPod.label;
|
||||
}
|
||||
break;
|
||||
@@ -481,9 +567,17 @@ async function fetchPods(
|
||||
isRelation: true,
|
||||
});
|
||||
if (setPod) {
|
||||
selectorStore.setCurrentDestPod(
|
||||
selectorStore.destPods.length ? selectorStore.destPods[0] : null
|
||||
);
|
||||
let p;
|
||||
if (states.currentDestPod) {
|
||||
p = selectorStore.destPods.find(
|
||||
(d: { label: string }) => d.label === states.currentDestPod
|
||||
);
|
||||
} else {
|
||||
p = selectorStore.destPods.find(
|
||||
(d: { label: string }, index: number) => index === 0
|
||||
);
|
||||
}
|
||||
selectorStore.setCurrentDestPod(p || null);
|
||||
states.currentDestPod = selectorStore.currentDestPod.label;
|
||||
}
|
||||
break;
|
||||
|
@@ -93,6 +93,8 @@ function setCurrentLog(log: any) {
|
||||
.log {
|
||||
font-size: 12px;
|
||||
height: 100%;
|
||||
border-bottom: 1px solid #eee;
|
||||
width: 100%;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
|
@@ -22,12 +22,12 @@ limitations under the License. -->
|
||||
<span v-else-if="item.label === 'tags'">
|
||||
{{ tags }}
|
||||
</span>
|
||||
<router-link
|
||||
<!-- <router-link
|
||||
v-else-if="item.label === 'traceId' && !noLink"
|
||||
:to="{ name: 'trace', query: { traceid: data[item.label] } }"
|
||||
>
|
||||
<span :class="noLink ? '' : 'blue'">{{ data[item.label] }}</span>
|
||||
</router-link>
|
||||
</router-link> -->
|
||||
<span v-else>{{ data[item.label] }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
99
src/views/dashboard/related/demand-log/Content.vue
Normal file
@@ -0,0 +1,99 @@
|
||||
<!-- 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>
|
||||
<span v-if="demandLogStore.message">{{ demandLogStore.message }}</span>
|
||||
<div
|
||||
v-else
|
||||
v-loading="demandLogStore.loadLogs"
|
||||
class="log-content"
|
||||
ref="logContent"
|
||||
style="width: calc(100% - 10px); height: calc(100% - 140px)"
|
||||
></div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, ref, onUnmounted, watch, toRaw } from "vue";
|
||||
import { useDemandLogStore } from "@/store/modules/demand-log";
|
||||
|
||||
/*global Nullable */
|
||||
const demandLogStore = useDemandLogStore();
|
||||
const monacoInstance = ref();
|
||||
const logContent = ref<Nullable<HTMLDivElement>>(null);
|
||||
|
||||
onMounted(() => {
|
||||
init();
|
||||
});
|
||||
async function init() {
|
||||
const monaco = await import("monaco-editor");
|
||||
setTimeout(() => {
|
||||
monacoInstanceGen(monaco);
|
||||
}, 500);
|
||||
window.addEventListener("resize", () => {
|
||||
editorLayout();
|
||||
});
|
||||
}
|
||||
function monacoInstanceGen(monaco: any) {
|
||||
monacoInstance.value = monaco.editor.create(logContent.value, {
|
||||
value: "",
|
||||
language: "text",
|
||||
wordWrap: true,
|
||||
minimap: { enabled: false },
|
||||
readonly: true,
|
||||
});
|
||||
toRaw(monacoInstance.value).updateOptions({ readOnly: true });
|
||||
editorLayout();
|
||||
}
|
||||
function editorLayout() {
|
||||
if (!logContent.value) {
|
||||
return;
|
||||
}
|
||||
const { width, height } = logContent.value.getBoundingClientRect();
|
||||
toRaw(monacoInstance.value).layout({
|
||||
height: height,
|
||||
width: width,
|
||||
});
|
||||
}
|
||||
onUnmounted(() => {
|
||||
if (!toRaw(monacoInstance.value)) {
|
||||
return;
|
||||
}
|
||||
toRaw(monacoInstance.value).dispose();
|
||||
monacoInstance.value = null;
|
||||
demandLogStore.setLogs("");
|
||||
});
|
||||
watch(
|
||||
() => demandLogStore.logs,
|
||||
() => {
|
||||
if (!toRaw(monacoInstance.value)) {
|
||||
return;
|
||||
}
|
||||
toRaw(monacoInstance.value).setValue(demandLogStore.logs);
|
||||
if (!demandLogStore.logs) {
|
||||
return;
|
||||
}
|
||||
setTimeout(() => {
|
||||
toRaw(monacoInstance.value).revealPosition({
|
||||
column: 1,
|
||||
lineNumber: demandLogStore.total,
|
||||
});
|
||||
}, 1000);
|
||||
}
|
||||
);
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.log-content {
|
||||
min-width: 600px;
|
||||
min-height: 400px;
|
||||
}
|
||||
</style>
|
433
src/views/dashboard/related/demand-log/Header.vue
Normal file
@@ -0,0 +1,433 @@
|
||||
<!-- 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="flex-h row">
|
||||
<div class="mr-5 mb-5" v-if="dashboardStore.entity !== EntityType[3].value">
|
||||
<span class="grey mr-5"> {{ t("instance") }}: </span>
|
||||
<Selector
|
||||
size="small"
|
||||
:value="state.instance.value"
|
||||
:options="demandLogStore.instances"
|
||||
placeholder="Select a instance"
|
||||
@change="changeField('instance', $event)"
|
||||
class="selectors"
|
||||
/>
|
||||
</div>
|
||||
<div class="mr-5 mb-5" v-if="state.container">
|
||||
<span class="grey mr-5">{{ t("container") }}:</span>
|
||||
<Selector
|
||||
size="small"
|
||||
:value="state.container.value"
|
||||
:options="demandLogStore.containers"
|
||||
placeholder="Select a container"
|
||||
@change="changeField('container', $event)"
|
||||
class="selectors"
|
||||
/>
|
||||
</div>
|
||||
<!-- <div class="mr-5">
|
||||
<span class="grey mr-5">{{ t("limit") }}:</span>
|
||||
<el-input-number
|
||||
v-model="limit"
|
||||
:min="1"
|
||||
:max="1000"
|
||||
size="small"
|
||||
controls-position="right"
|
||||
@change="changeField('limit', $event)"
|
||||
/>
|
||||
</div> -->
|
||||
<div class="mr-5">
|
||||
<span class="grey mr-5">{{ t("duration") }}:</span>
|
||||
<Selector
|
||||
size="small"
|
||||
:value="state.duration.value"
|
||||
:options="TimeRanges"
|
||||
placeholder="Select a time range"
|
||||
@change="changeField('duration', $event)"
|
||||
class="duration-range"
|
||||
/>
|
||||
</div>
|
||||
<div class="mr-5">
|
||||
<span class="grey mr-5">{{ t("interval") }}:</span>
|
||||
<Selector
|
||||
size="small"
|
||||
:value="state.interval.value"
|
||||
:options="IntervalOpts"
|
||||
@change="changeField('interval', $event)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex-h row">
|
||||
<div class="mr-5">
|
||||
<span class="mr-5 grey">{{ t("keywordsOfContent") }}:</span>
|
||||
<span class="log-tags">
|
||||
<span
|
||||
class="selected"
|
||||
v-for="(item, index) in keywordsOfContent"
|
||||
:key="`keywordsOfContent${index}`"
|
||||
>
|
||||
<span>{{ item }}</span>
|
||||
<span class="remove-icon" @click="removeContent(index)">×</span>
|
||||
</span>
|
||||
</span>
|
||||
<el-input
|
||||
size="small"
|
||||
class="inputs-max"
|
||||
:placeholder="t('addKeywordsOfContent')"
|
||||
v-model="contentStr"
|
||||
@change="addLabels('keywordsOfContent')"
|
||||
/>
|
||||
</div>
|
||||
<div class="mr-5">
|
||||
<span class="grey mr-5"> {{ t("excludingKeywordsOfContent") }}: </span>
|
||||
<span class="log-tags">
|
||||
<span
|
||||
class="selected"
|
||||
v-for="(item, index) in excludingKeywordsOfContent"
|
||||
:key="`excludingKeywordsOfContent${index}`"
|
||||
>
|
||||
<span>{{ item }}</span>
|
||||
<span class="remove-icon" @click="removeExcludeContent(index)">
|
||||
×
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
<el-input
|
||||
class="inputs-max"
|
||||
size="small"
|
||||
:placeholder="t('addExcludingKeywordsOfContent')"
|
||||
v-model="excludingContentStr"
|
||||
@change="addLabels('excludingKeywordsOfContent')"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex-h row btn-row">
|
||||
<el-button
|
||||
class="search-btn mt-10"
|
||||
size="small"
|
||||
type="primary"
|
||||
@click="runInterval"
|
||||
:disabled="disabled"
|
||||
>
|
||||
<Icon
|
||||
size="middle"
|
||||
iconName="retry"
|
||||
:loading="!!intervalFn"
|
||||
class="mr-5"
|
||||
/>
|
||||
{{ intervalFn ? t("pause") : t("start") }}
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref, reactive, watch, onMounted, onUnmounted } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { useDemandLogStore } from "@/store/modules/demand-log";
|
||||
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||
import { useSelectorStore } from "@/store/modules/selectors";
|
||||
import { ElMessage } from "element-plus";
|
||||
import { EntityType } from "../../data";
|
||||
import { TimeRanges, IntervalOpts } from "./data";
|
||||
import getLocalTime from "@/utils/localtime";
|
||||
import dateFormatStep from "@/utils/dateFormat";
|
||||
|
||||
const { t } = useI18n();
|
||||
const appStore = useAppStoreWithOut();
|
||||
const selectorStore = useSelectorStore();
|
||||
const dashboardStore = useDashboardStore();
|
||||
const demandLogStore = useDemandLogStore();
|
||||
const keywordsOfContent = ref<string[]>([]);
|
||||
const excludingKeywordsOfContent = ref<string[]>([]);
|
||||
const contentStr = ref<string>("");
|
||||
const excludingContentStr = ref<string>("");
|
||||
// const limit = ref<number>(20);
|
||||
const state = reactive<any>({
|
||||
instance: { value: "", label: "" },
|
||||
container: { value: "", label: "" },
|
||||
duration: { label: "From 30 minutes ago", value: 1800 },
|
||||
interval: { label: "30 seconds", value: 30 },
|
||||
});
|
||||
const disabled = ref<boolean>(true);
|
||||
/*global Nullable */
|
||||
const intervalFn = ref<Nullable<any>>(null);
|
||||
|
||||
onMounted(() => {
|
||||
fetchSelectors();
|
||||
});
|
||||
|
||||
async function fetchSelectors() {
|
||||
if (dashboardStore.entity !== EntityType[3].value) {
|
||||
await getInstances();
|
||||
}
|
||||
getContainers();
|
||||
if (intervalFn.value) {
|
||||
clearTimer();
|
||||
}
|
||||
}
|
||||
async function getContainers() {
|
||||
if (
|
||||
!(
|
||||
state.instance.id ||
|
||||
(selectorStore.currentPod && selectorStore.currentPod.id)
|
||||
)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
const resp = await demandLogStore.getContainers(
|
||||
state.instance.id || selectorStore.currentPod.id
|
||||
);
|
||||
if (resp.errors) {
|
||||
disabled.value = true;
|
||||
ElMessage.error(resp.errors);
|
||||
return;
|
||||
}
|
||||
if (resp.data.containers.errorReason) {
|
||||
disabled.value = true;
|
||||
ElMessage.warning(resp.data.containers.errorReason);
|
||||
return;
|
||||
}
|
||||
if (demandLogStore.containers.length) {
|
||||
state.container = demandLogStore.containers[0];
|
||||
disabled.value = false;
|
||||
}
|
||||
}
|
||||
async function getInstances() {
|
||||
const resp = await demandLogStore.getInstances();
|
||||
if (resp.errors) {
|
||||
ElMessage.error(resp.errors);
|
||||
return;
|
||||
}
|
||||
state.instance = demandLogStore.instances[0];
|
||||
}
|
||||
function runInterval() {
|
||||
if (intervalFn.value) {
|
||||
clearTimer();
|
||||
return;
|
||||
}
|
||||
searchLogs();
|
||||
if (state.interval.value === 0) {
|
||||
return;
|
||||
}
|
||||
intervalFn.value = setInterval(searchLogs, state.interval.value * 1000);
|
||||
setTimeout(() => {
|
||||
clearTimer();
|
||||
}, state.duration.value * 1000);
|
||||
}
|
||||
function searchLogs() {
|
||||
let instance = "";
|
||||
if (dashboardStore.entity === EntityType[3].value) {
|
||||
instance = selectorStore.currentPod.id;
|
||||
}
|
||||
const serviceInstanceId =
|
||||
instance || (state.instance && state.instance.id) || "";
|
||||
demandLogStore.setLogCondition({
|
||||
serviceInstanceId,
|
||||
container: state.container.value,
|
||||
duration: rangeTime(),
|
||||
keywordsOfContent: keywordsOfContent.value.length
|
||||
? keywordsOfContent.value
|
||||
: undefined,
|
||||
excludingKeywordsOfContent: excludingKeywordsOfContent.value.length
|
||||
? excludingKeywordsOfContent.value
|
||||
: undefined,
|
||||
});
|
||||
if (!serviceInstanceId) {
|
||||
return;
|
||||
}
|
||||
queryLogs();
|
||||
}
|
||||
|
||||
function rangeTime() {
|
||||
{
|
||||
const times = {
|
||||
start: getLocalTime(
|
||||
appStore.utc,
|
||||
new Date(new Date().getTime() - state.duration.value * 1000)
|
||||
),
|
||||
end: getLocalTime(appStore.utc, new Date()),
|
||||
step: "SECOND",
|
||||
};
|
||||
return {
|
||||
start: dateFormatStep(times.start, times.step, false),
|
||||
end: dateFormatStep(times.end, times.step, false),
|
||||
step: times.step,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
async function queryLogs() {
|
||||
const res = await demandLogStore.getDemandLogs();
|
||||
if (res && res.errors) {
|
||||
ElMessage.error(res.errors);
|
||||
}
|
||||
}
|
||||
function changeField(type: string, opt: any) {
|
||||
clearTimer();
|
||||
// if (["limit"].includes(type)) {
|
||||
// state[type] = opt;
|
||||
// return;
|
||||
// }
|
||||
state[type] = opt[0];
|
||||
if (type === "instance") {
|
||||
getContainers();
|
||||
}
|
||||
}
|
||||
function removeContent(index: number) {
|
||||
const keywordsOfContentList = keywordsOfContent.value || [];
|
||||
keywordsOfContentList.splice(index, 1);
|
||||
demandLogStore.setLogCondition({
|
||||
keywordsOfContent: keywordsOfContentList,
|
||||
});
|
||||
contentStr.value = "";
|
||||
clearTimer();
|
||||
}
|
||||
function addLabels(type: string) {
|
||||
if (type === "keywordsOfContent" && !contentStr.value) {
|
||||
return;
|
||||
}
|
||||
if (type === "excludingKeywordsOfContent" && !excludingContentStr.value) {
|
||||
return;
|
||||
}
|
||||
if (type === "keywordsOfContent") {
|
||||
keywordsOfContent.value.push(contentStr.value);
|
||||
demandLogStore.setLogCondition({
|
||||
[type]: keywordsOfContent.value,
|
||||
});
|
||||
contentStr.value = "";
|
||||
} else if (type === "excludingKeywordsOfContent") {
|
||||
excludingKeywordsOfContent.value.push(excludingContentStr.value);
|
||||
demandLogStore.setLogCondition({
|
||||
[type]: excludingKeywordsOfContent.value,
|
||||
});
|
||||
excludingContentStr.value = "";
|
||||
}
|
||||
clearTimer();
|
||||
}
|
||||
function removeExcludeContent(index: number) {
|
||||
excludingKeywordsOfContent.value.splice(index, 1);
|
||||
demandLogStore.setLogCondition({
|
||||
excludingKeywordsOfContent: excludingKeywordsOfContent.value,
|
||||
});
|
||||
excludingContentStr.value = "";
|
||||
clearTimer();
|
||||
}
|
||||
function clearTimer() {
|
||||
if (!intervalFn.value) {
|
||||
return;
|
||||
}
|
||||
clearInterval(intervalFn.value);
|
||||
intervalFn.value = null;
|
||||
}
|
||||
onUnmounted(() => {
|
||||
clearTimer();
|
||||
});
|
||||
watch(
|
||||
() => selectorStore.currentService,
|
||||
() => {
|
||||
if (dashboardStore.entity === EntityType[0].value) {
|
||||
fetchSelectors();
|
||||
demandLogStore.setLogs("");
|
||||
}
|
||||
}
|
||||
);
|
||||
watch(
|
||||
() => [selectorStore.currentPod],
|
||||
() => {
|
||||
if (dashboardStore.entity === EntityType[3].value) {
|
||||
fetchSelectors();
|
||||
demandLogStore.setLogs("");
|
||||
}
|
||||
}
|
||||
);
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.inputs {
|
||||
width: 120px;
|
||||
}
|
||||
|
||||
.row {
|
||||
margin-bottom: 5px;
|
||||
position: relative;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.inputs-max {
|
||||
width: 270px;
|
||||
}
|
||||
|
||||
.traceId {
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
.search-btn {
|
||||
cursor: pointer;
|
||||
width: 120px;
|
||||
}
|
||||
|
||||
.tips {
|
||||
color: #888;
|
||||
}
|
||||
|
||||
.log-tag {
|
||||
width: 30%;
|
||||
border-style: unset;
|
||||
outline: 0;
|
||||
border: 1px solid #ccc;
|
||||
height: 30px;
|
||||
padding: 0 5px;
|
||||
}
|
||||
|
||||
.log-tags {
|
||||
padding: 1px 5px 0 0;
|
||||
border-radius: 3px;
|
||||
height: 24px;
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.selected {
|
||||
display: inline-block;
|
||||
padding: 0 3px;
|
||||
border-radius: 3px;
|
||||
overflow: hidden;
|
||||
color: #3d444f;
|
||||
border: 1px dashed #aaa;
|
||||
font-size: 12px;
|
||||
margin: 0 2px;
|
||||
}
|
||||
|
||||
.remove-icon {
|
||||
display: inline-block;
|
||||
margin-left: 3px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.selectors {
|
||||
width: 250px;
|
||||
}
|
||||
|
||||
.duration-range {
|
||||
width: 210px;
|
||||
}
|
||||
|
||||
.btn-row {
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.help {
|
||||
color: #999;
|
||||
cursor: pointer;
|
||||
}
|
||||
</style>
|
37
src/views/dashboard/related/demand-log/data.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* 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 const TimeRanges = [
|
||||
{ label: "From 5 seconds ago -- Now", value: 5 },
|
||||
{ label: "From 10 seconds ago -- Now", value: 10 },
|
||||
{ label: "From 15 seconds ago -- Now", value: 15 },
|
||||
{ label: "From 30 seconds ago -- Now", value: 30 },
|
||||
{ label: "From 45 seconds ago -- Now", value: 45 },
|
||||
{ label: "From 1 minute ago -- Now", value: 60 },
|
||||
{ label: "From 5 minutes ago -- Now", value: 300 },
|
||||
{ label: "From 15 minutes ago -- Now", value: 900 },
|
||||
{ label: "From 30 minutes ago -- Now", value: 1800 },
|
||||
];
|
||||
export const IntervalOpts = [
|
||||
{ label: "None", value: 0 },
|
||||
{ label: "5 seconds", value: 5 },
|
||||
{ label: "10 seconds", value: 10 },
|
||||
{ label: "15 seconds", value: 15 },
|
||||
{ label: "30 seconds", value: 30 },
|
||||
{ label: "45 seconds", value: 45 },
|
||||
{ label: "1 minute", value: 60 },
|
||||
];
|
58
src/views/dashboard/related/ebpf/Content.vue
Normal file
@@ -0,0 +1,58 @@
|
||||
<!-- 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="flex-h content">
|
||||
<TaskList />
|
||||
<div class="vis-graph ml-5">
|
||||
<div class="schedules">
|
||||
<EBPFSchedules />
|
||||
</div>
|
||||
<div class="item">
|
||||
<EBPFStack />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import TaskList from "./components/TaskList.vue";
|
||||
import EBPFSchedules from "./components/EBPFSchedules.vue";
|
||||
import EBPFStack from "./components/EBPFStack.vue";
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.content {
|
||||
height: calc(100% - 30px);
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.vis-graph {
|
||||
height: 100%;
|
||||
flex-grow: 2;
|
||||
min-width: 700px;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.item {
|
||||
width: 100%;
|
||||
overflow: auto;
|
||||
height: calc(100% - 100px);
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
.schedules {
|
||||
height: 90px;
|
||||
border-bottom: 1px solid #ccc;
|
||||
padding-right: 10px;
|
||||
}
|
||||
</style>
|
104
src/views/dashboard/related/ebpf/Header.vue
Normal file
@@ -0,0 +1,104 @@
|
||||
<!-- 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="flex-h header">
|
||||
<div class="title">eBPF Profiling</div>
|
||||
<el-button type="primary" size="small" @click="createTask">
|
||||
{{ t("newTask") }}
|
||||
</el-button>
|
||||
</div>
|
||||
<el-dialog
|
||||
v-model="newTask"
|
||||
:destroy-on-close="true"
|
||||
fullscreen
|
||||
@closed="newTask = false"
|
||||
>
|
||||
<NewTask @close="newTask = false" />
|
||||
</el-dialog>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref, watch } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { useEbpfStore } from "@/store/modules/ebpf";
|
||||
import { useSelectorStore } from "@/store/modules/selectors";
|
||||
import { ElMessage } from "element-plus";
|
||||
import NewTask from "./components/NewTask.vue";
|
||||
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||
import { EntityType } from "../../data";
|
||||
|
||||
const ebpfStore = useEbpfStore();
|
||||
const appStore = useAppStoreWithOut();
|
||||
const selectorStore = useSelectorStore();
|
||||
const dashboardStore = useDashboardStore();
|
||||
const { t } = useI18n();
|
||||
const newTask = ref<boolean>(false);
|
||||
|
||||
searchTasks();
|
||||
|
||||
async function searchTasks() {
|
||||
const serviceId =
|
||||
(selectorStore.currentService && selectorStore.currentService.id) || "";
|
||||
const res = await ebpfStore.getTaskList(serviceId);
|
||||
|
||||
if (res.errors) {
|
||||
ElMessage.error(res.errors);
|
||||
}
|
||||
}
|
||||
|
||||
async function createTask() {
|
||||
if (!selectorStore.currentService) {
|
||||
return;
|
||||
}
|
||||
newTask.value = true;
|
||||
ebpfStore.getCreateTaskData(selectorStore.currentService.id);
|
||||
}
|
||||
|
||||
watch(
|
||||
() => selectorStore.currentService,
|
||||
() => {
|
||||
searchTasks();
|
||||
}
|
||||
);
|
||||
watch(
|
||||
() => appStore.durationTime,
|
||||
() => {
|
||||
if (dashboardStore.entity === EntityType[1].value) {
|
||||
searchTasks();
|
||||
}
|
||||
}
|
||||
);
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.header {
|
||||
padding: 5px 20px 5px 10px;
|
||||
font-size: 12px;
|
||||
border-bottom: 1px solid #dcdfe6;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.name {
|
||||
width: 270px;
|
||||
}
|
||||
|
||||
.new-btn {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-weight: bold;
|
||||
line-height: 24px;
|
||||
}
|
||||
</style>
|
280
src/views/dashboard/related/ebpf/components/EBPFSchedules.vue
Normal file
@@ -0,0 +1,280 @@
|
||||
<!-- 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="filters">
|
||||
<div class="mb-10 flex-h">
|
||||
<Selector
|
||||
:value="selectedLabels"
|
||||
:options="labels"
|
||||
size="small"
|
||||
placeholder="Please select labels"
|
||||
@change="changeLabels"
|
||||
class="inputs mr-10"
|
||||
:multiple="true"
|
||||
/>
|
||||
<div class="mr-5 duration" v-if="duration.length">
|
||||
<span>{{ duration[0] }}</span>
|
||||
<span> ~ </span>
|
||||
<span>{{ duration[1] }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex-h">
|
||||
<Selector
|
||||
v-if="ebpfStore.selectedTask.targetType === 'OFF_CPU'"
|
||||
:value="aggregateType"
|
||||
:options="AggregateTypes"
|
||||
size="small"
|
||||
placeholder="Please select a type"
|
||||
@change="changeAggregateType"
|
||||
class="selector mr-10"
|
||||
/>
|
||||
<el-popover
|
||||
placement="bottom"
|
||||
:width="680"
|
||||
trigger="click"
|
||||
:persistent="false"
|
||||
>
|
||||
<template #reference>
|
||||
<el-button type="primary" size="small">
|
||||
{{ t("processSelect") }}
|
||||
</el-button>
|
||||
</template>
|
||||
<el-input
|
||||
v-model="searchText"
|
||||
placeholder="Please input name"
|
||||
class="input-with-search"
|
||||
size="small"
|
||||
@change="searchProcesses(0)"
|
||||
>
|
||||
<template #append>
|
||||
<el-button size="small">
|
||||
<Icon size="sm" iconName="search" />
|
||||
</el-button>
|
||||
</template>
|
||||
</el-input>
|
||||
<el-table
|
||||
:data="currentProcesses"
|
||||
ref="multipleTableRef"
|
||||
@selection-change="handleSelectionChange"
|
||||
>
|
||||
<el-table-column type="selection" width="55" />
|
||||
<el-table-column
|
||||
v-for="(h, index) of TableHeader"
|
||||
:property="h.property"
|
||||
:label="h.label"
|
||||
:key="index"
|
||||
width="150"
|
||||
/>
|
||||
<el-table-column width="300" label="Attributes">
|
||||
<template #default="scope">
|
||||
{{ scope.row.attributes.map((d: {name: string, value: string}) => `${d.name}=${d.value}`).join("; ") }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<el-pagination
|
||||
class="pagination"
|
||||
background
|
||||
small
|
||||
layout="prev, pager, next"
|
||||
:page-size="pageSize"
|
||||
:total="processes.length"
|
||||
@current-change="changePage"
|
||||
@prev-click="changePage"
|
||||
@next-click="changePage"
|
||||
/>
|
||||
</el-popover>
|
||||
<el-button type="primary" size="small" @click="analyzeEBPF">
|
||||
{{ t("analyze") }}
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref, watch } from "vue";
|
||||
import dayjs from "dayjs";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { Option } from "@/types/app";
|
||||
import { TableHeader, AggregateTypes } from "./data";
|
||||
import { useEbpfStore } from "@/store/modules/ebpf";
|
||||
import { EBPFProfilingSchedule, Process } from "@/types/ebpf";
|
||||
import { ElMessage, ElTable } from "element-plus";
|
||||
|
||||
const { t } = useI18n();
|
||||
const ebpfStore = useEbpfStore();
|
||||
const pageSize = 5;
|
||||
const multipleTableRef = ref<InstanceType<typeof ElTable>>();
|
||||
const selectedProcesses = ref<string[]>([]);
|
||||
const labels = ref<Option[]>([{ label: "All", value: "0" }]);
|
||||
const processes = ref<Process[]>([]);
|
||||
const currentProcesses = ref<Process[]>([]);
|
||||
const selectedLabels = ref<string[]>(["0"]);
|
||||
const searchText = ref<string>("");
|
||||
const aggregateType = ref<string>(AggregateTypes[0].value);
|
||||
const duration = ref<string[]>([]);
|
||||
const dateFormat = (date: number, pattern = "YYYY-MM-DD HH:mm:ss") =>
|
||||
dayjs(date).format(pattern);
|
||||
|
||||
function changeLabels(opt: any[]) {
|
||||
const arr = opt.map((d) => d.value);
|
||||
selectedLabels.value = arr;
|
||||
}
|
||||
|
||||
function changeAggregateType(opt: any[]) {
|
||||
aggregateType.value = opt[0].value;
|
||||
ebpfStore.setAnalyzeTrees([]);
|
||||
}
|
||||
|
||||
const handleSelectionChange = (arr: Process[]) => {
|
||||
selectedProcesses.value = arr.map((d: Process) => d.id);
|
||||
};
|
||||
|
||||
async function analyzeEBPF() {
|
||||
let arr: string[] = selectedLabels.value;
|
||||
if (selectedLabels.value.includes("0")) {
|
||||
arr = labels.value.map((d: Option) => d.value);
|
||||
}
|
||||
const ranges: { start: number; end: number }[] = [];
|
||||
const scheduleIdList = ebpfStore.eBPFSchedules.flatMap(
|
||||
(d: EBPFProfilingSchedule) => {
|
||||
const l = d.process.labels.find((d: string) => arr.includes(d));
|
||||
const i = selectedProcesses.value.includes(d.process.id);
|
||||
if (l || i) {
|
||||
ranges.push({
|
||||
start: d.startTime,
|
||||
end: d.endTime,
|
||||
});
|
||||
return d.scheduleId;
|
||||
}
|
||||
}
|
||||
);
|
||||
let timeRanges: { start: number; end: number }[] = [];
|
||||
for (const r of ranges) {
|
||||
if (timeRanges.length) {
|
||||
for (const t of timeRanges) {
|
||||
if (r.start > t.start && r.start < t.end) {
|
||||
if (r.end > t.end) {
|
||||
t.end = r.end;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
timeRanges.push(r);
|
||||
}
|
||||
}
|
||||
const res = await ebpfStore.getEBPFAnalyze({
|
||||
scheduleIdList,
|
||||
timeRanges,
|
||||
aggregateType: aggregateType.value,
|
||||
});
|
||||
if (res.data && res.data.errors) {
|
||||
ElMessage.error(res.data.errors);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
function getSchedules() {
|
||||
labels.value = [{ label: "All", value: "0" }];
|
||||
selectedLabels.value = ["0"];
|
||||
processes.value = [];
|
||||
const ranges = ebpfStore.eBPFSchedules.map((d: EBPFProfilingSchedule) => {
|
||||
for (const l of d.process.labels) {
|
||||
labels.value.push({ label: l, value: l });
|
||||
}
|
||||
processes.value.push(d.process);
|
||||
return [d.startTime / 10000, d.endTime / 10000];
|
||||
});
|
||||
if (ranges.length) {
|
||||
const arr = ranges.flat(1);
|
||||
const min = Math.min(...arr);
|
||||
const max = Math.max(...arr);
|
||||
duration.value = [dateFormat(min * 10000), dateFormat(max * 10000)];
|
||||
} else {
|
||||
duration.value = [];
|
||||
}
|
||||
searchProcesses(0);
|
||||
analyzeEBPF();
|
||||
}
|
||||
|
||||
function changePage(pageIndex: number) {
|
||||
searchProcesses(pageIndex);
|
||||
}
|
||||
|
||||
function searchProcesses(pageIndex: number) {
|
||||
const arr = processes.value.filter(
|
||||
(d: {
|
||||
name: string;
|
||||
instanceName: string;
|
||||
attributes: { name: string; value: string }[];
|
||||
}) =>
|
||||
d.name.includes(searchText.value) ||
|
||||
d.instanceName.includes(searchText.value) ||
|
||||
searchAttribute(d.attributes, searchText.value)
|
||||
);
|
||||
currentProcesses.value = arr.filter(
|
||||
(d, index: number) =>
|
||||
(pageIndex - 1 || 0) * pageSize <= index &&
|
||||
pageSize * (pageIndex || 1) > index
|
||||
);
|
||||
}
|
||||
|
||||
function searchAttribute(
|
||||
attributes: { name: string; value: string }[],
|
||||
text: string
|
||||
) {
|
||||
const item = attributes.find(
|
||||
(d: { name: string; value: string }) => d.name === "command_line"
|
||||
);
|
||||
|
||||
if (!item) {
|
||||
return false;
|
||||
}
|
||||
return item.value.includes(text);
|
||||
}
|
||||
|
||||
watch(
|
||||
() => ebpfStore.eBPFSchedules,
|
||||
() => {
|
||||
getSchedules();
|
||||
}
|
||||
);
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.filters {
|
||||
margin: 5px 0;
|
||||
width: 100%;
|
||||
min-width: 560px;
|
||||
}
|
||||
|
||||
.inputs {
|
||||
width: 400px;
|
||||
}
|
||||
|
||||
.input-with-search {
|
||||
width: 650px;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.pagination {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.selector {
|
||||
width: 120px;
|
||||
}
|
||||
|
||||
.duration {
|
||||
line-height: 30px;
|
||||
}
|
||||
</style>
|
212
src/views/dashboard/related/ebpf/components/EBPFStack.vue
Normal file
@@ -0,0 +1,212 @@
|
||||
<!-- 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 id="graph-stack" ref="graph">
|
||||
<span class="tip" v-show="ebpfStore.tip">{{ ebpfStore.tip }}</span>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref, watch } from "vue";
|
||||
import * as d3 from "d3";
|
||||
import d3tip from "d3-tip";
|
||||
import { flamegraph } from "d3-flame-graph";
|
||||
import { useEbpfStore } from "@/store/modules/ebpf";
|
||||
import { StackElement } from "@/types/ebpf";
|
||||
import { AggregateTypes } from "./data";
|
||||
import "d3-flame-graph/dist/d3-flamegraph.css";
|
||||
|
||||
/*global Nullable*/
|
||||
const ebpfStore = useEbpfStore();
|
||||
const stackTree = ref<Nullable<StackElement>>(null);
|
||||
const selectStack = ref<Nullable<StackElement>>(null);
|
||||
const graph = ref<Nullable<HTMLDivElement>>(null);
|
||||
const flameChart = ref<any>(null);
|
||||
const min = ref<number>(1);
|
||||
const max = ref<number>(1);
|
||||
|
||||
function drawGraph() {
|
||||
if (flameChart.value) {
|
||||
flameChart.value.destroy();
|
||||
}
|
||||
if (!ebpfStore.analyzeTrees.length) {
|
||||
return (stackTree.value = null);
|
||||
}
|
||||
const root: StackElement = {
|
||||
parentId: "0",
|
||||
originId: "1",
|
||||
name: "Virtual Root",
|
||||
children: [],
|
||||
value: 0,
|
||||
id: "1",
|
||||
symbol: "Virtual Root",
|
||||
dumpCount: 0,
|
||||
stackType: "",
|
||||
rateOfRoot: "",
|
||||
rateOfParent: "",
|
||||
};
|
||||
countRange();
|
||||
for (const tree of ebpfStore.analyzeTrees) {
|
||||
const ele = processTree(tree.elements);
|
||||
root.children && root.children.push(ele);
|
||||
}
|
||||
const param = (root.children || []).reduce(
|
||||
(prev: number[], curr: StackElement) => {
|
||||
prev[0] += curr.value;
|
||||
prev[1] += curr.dumpCount;
|
||||
return prev;
|
||||
},
|
||||
[0, 0]
|
||||
);
|
||||
root.value = param[0];
|
||||
root.dumpCount = param[1];
|
||||
stackTree.value = root;
|
||||
const width = (graph.value && graph.value.getBoundingClientRect().width) || 0;
|
||||
const w = width < 800 ? 802 : width;
|
||||
flameChart.value = flamegraph()
|
||||
.width(w - 15)
|
||||
.cellHeight(18)
|
||||
.transitionDuration(750)
|
||||
.minFrameSize(1)
|
||||
.transitionEase(d3.easeCubic as any)
|
||||
.sort(true)
|
||||
.title("")
|
||||
.selfValue(false)
|
||||
.inverted(true)
|
||||
.onClick((d: { data: StackElement }) => {
|
||||
selectStack.value = d.data;
|
||||
})
|
||||
.setColorMapper((d, originalColor) =>
|
||||
d.highlight ? "#6aff8f" : originalColor
|
||||
);
|
||||
const tip = (d3tip as any)()
|
||||
.attr("class", "d3-tip")
|
||||
.direction("w")
|
||||
.html((d: { data: StackElement } & { parent: { data: StackElement } }) => {
|
||||
const name = d.data.name.replace("<", "<").replace(">", ">");
|
||||
const valStr =
|
||||
ebpfStore.aggregateType === AggregateTypes[0].value
|
||||
? `<div class="mb-5">Dump Count: ${d.data.dumpCount}</div>`
|
||||
: `<div class="mb-5">Duration: ${d.data.dumpCount} ns</div>`;
|
||||
const rateOfParent =
|
||||
(d.parent &&
|
||||
`<div class="mb-5">Percentage Of Selected: ${
|
||||
(
|
||||
(d.data.dumpCount /
|
||||
((selectStack.value && selectStack.value.dumpCount) ||
|
||||
root.dumpCount)) *
|
||||
100
|
||||
).toFixed(3) + "%"
|
||||
}</div>`) ||
|
||||
"";
|
||||
const rateOfRoot = `<div class="mb-5">Percentage Of Root: ${
|
||||
((d.data.dumpCount / root.dumpCount) * 100).toFixed(3) + "%"
|
||||
}</div>`;
|
||||
return `<div class="mb-5 name">Symbol: ${name}</div>${valStr}${rateOfParent}${rateOfRoot}`;
|
||||
})
|
||||
.style("max-width", "500px");
|
||||
flameChart.value.tooltip(tip);
|
||||
d3.select("#graph-stack").datum(stackTree.value).call(flameChart.value);
|
||||
}
|
||||
|
||||
function countRange() {
|
||||
const list = [];
|
||||
for (const tree of ebpfStore.analyzeTrees) {
|
||||
for (const ele of tree.elements) {
|
||||
list.push(ele.dumpCount);
|
||||
}
|
||||
}
|
||||
max.value = Math.max(...list);
|
||||
min.value = Math.min(...list);
|
||||
}
|
||||
|
||||
function processTree(arr: StackElement[]) {
|
||||
const copyArr = (window as any).structuredClone(arr);
|
||||
const obj: any = {};
|
||||
let res = null;
|
||||
for (const item of copyArr) {
|
||||
item.parentId = String(Number(item.parentId) + 1);
|
||||
item.originId = String(Number(item.id) + 1);
|
||||
item.name = item.symbol;
|
||||
delete item.id;
|
||||
obj[item.originId] = item;
|
||||
}
|
||||
const scale = d3.scaleLinear().domain([min.value, max.value]).range([1, 200]);
|
||||
|
||||
for (const item of copyArr) {
|
||||
if (item.parentId === "1") {
|
||||
const val = Number(scale(item.dumpCount).toFixed(4));
|
||||
res = item;
|
||||
res.value = val;
|
||||
}
|
||||
for (const key in obj) {
|
||||
if (item.originId === obj[key].parentId) {
|
||||
const val = Number(scale(obj[key].dumpCount).toFixed(4));
|
||||
|
||||
obj[key].value = val;
|
||||
if (item.children) {
|
||||
item.children.push(obj[key]);
|
||||
} else {
|
||||
item.children = [obj[key]];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
treeForeach([res], (node: StackElement) => {
|
||||
if (node.children) {
|
||||
let val = 0;
|
||||
for (const child of node.children) {
|
||||
val = child.value + val;
|
||||
}
|
||||
node.value = node.value < val ? val : node.value;
|
||||
}
|
||||
});
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
function treeForeach(tree: StackElement[], func: (node: StackElement) => void) {
|
||||
for (const data of tree) {
|
||||
data.children && treeForeach(data.children, func);
|
||||
func(data);
|
||||
}
|
||||
return tree;
|
||||
}
|
||||
|
||||
watch(
|
||||
() => ebpfStore.analyzeTrees,
|
||||
() => {
|
||||
drawGraph();
|
||||
}
|
||||
);
|
||||
</script>
|
||||
<style>
|
||||
#graph-stack {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.tip {
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
color: red;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.name {
|
||||
word-wrap: break-word;
|
||||
}
|
||||
</style>
|
168
src/views/dashboard/related/ebpf/components/NewTask.vue
Normal file
@@ -0,0 +1,168 @@
|
||||
<!-- 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="ebpf-task" v-if="eBPFStore.couldProfiling">
|
||||
<div>
|
||||
<div class="label">{{ t("labels") }}</div>
|
||||
<Selector
|
||||
class="profile-input"
|
||||
size="small"
|
||||
:value="labels"
|
||||
:options="eBPFStore.labels"
|
||||
placeholder="Select labels"
|
||||
:multiple="true"
|
||||
@change="changeLabel"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<div class="label">{{ t("targetType") }}</div>
|
||||
<Selector
|
||||
class="profile-input"
|
||||
size="small"
|
||||
:value="type"
|
||||
:options="TargetTypes"
|
||||
placeholder="Select a type"
|
||||
:isRemote="true"
|
||||
@change="changeType"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<div class="label">{{ t("monitorTime") }}</div>
|
||||
<div>
|
||||
<Radio
|
||||
:value="monitorTime"
|
||||
:options="InitTaskField.monitorTimeEn"
|
||||
@change="changeMonitorTime"
|
||||
/>
|
||||
<span class="date">
|
||||
<TimePicker
|
||||
:value="time"
|
||||
position="bottom"
|
||||
format="YYYY-MM-DD HH:mm:ss"
|
||||
@input="changeTimeRange"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="label">{{ t("monitorDuration") }}</div>
|
||||
<el-input
|
||||
class="profile-input"
|
||||
v-model="monitorDuration"
|
||||
size="small"
|
||||
placeholder="none"
|
||||
type="number"
|
||||
:min="1"
|
||||
:max="60"
|
||||
/>
|
||||
Min
|
||||
</div>
|
||||
<div>
|
||||
<el-button @click="createTask" type="primary" class="create-task-btn">
|
||||
{{ t("createTask") }}
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else>{{ t("ebpfTip") }}</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { useEbpfStore } from "@/store/modules/ebpf";
|
||||
import { useSelectorStore } from "@/store/modules/selectors";
|
||||
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||
import { ElMessage } from "element-plus";
|
||||
import { InitTaskField, TargetTypes } from "./data";
|
||||
|
||||
/* global defineEmits */
|
||||
const emits = defineEmits(["close"]);
|
||||
const eBPFStore = useEbpfStore();
|
||||
const selectorStore = useSelectorStore();
|
||||
const appStore = useAppStoreWithOut();
|
||||
const { t } = useI18n();
|
||||
const labels = ref<string[]>([]);
|
||||
const type = ref<string>(TargetTypes[0].value);
|
||||
const monitorTime = ref<string>(InitTaskField.monitorTimeEn[0].value);
|
||||
const monitorDuration = ref<number>(10);
|
||||
const time = ref<Date>(appStore.durationRow.start);
|
||||
const disabled = ref<boolean>(false);
|
||||
|
||||
function changeMonitorTime(opt: string) {
|
||||
monitorTime.value = opt;
|
||||
}
|
||||
|
||||
function changeLabel(opt: any[]) {
|
||||
labels.value = opt.map((d) => d.value);
|
||||
}
|
||||
|
||||
function changeType(opt: any[]) {
|
||||
type.value = opt[0].value;
|
||||
}
|
||||
|
||||
async function createTask() {
|
||||
if (disabled.value) {
|
||||
return;
|
||||
}
|
||||
disabled.value = true;
|
||||
const date = monitorTime.value === "0" ? new Date() : time.value;
|
||||
const params = {
|
||||
serviceId: selectorStore.currentService.id,
|
||||
processLabels: labels.value,
|
||||
startTime: date.getTime(),
|
||||
duration: monitorDuration.value * 60,
|
||||
targetType: type.value,
|
||||
};
|
||||
const res = await eBPFStore.createTask(params);
|
||||
if (res.errors) {
|
||||
ElMessage.error(res.errors);
|
||||
return;
|
||||
}
|
||||
disabled.value = false;
|
||||
if (!res.data.createTaskData.status) {
|
||||
ElMessage.error(res.data.createTaskData.errorReason);
|
||||
return;
|
||||
}
|
||||
ElMessage.success("Task created successfully");
|
||||
emits("close");
|
||||
}
|
||||
function changeTimeRange(val: Date) {
|
||||
time.value = val;
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.ebpf-task {
|
||||
margin: 0 auto;
|
||||
width: 400px;
|
||||
}
|
||||
|
||||
.date {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.label {
|
||||
margin-top: 10px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.profile-input {
|
||||
width: 300px;
|
||||
}
|
||||
|
||||
.create-task-btn {
|
||||
width: 300px;
|
||||
margin-top: 50px;
|
||||
}
|
||||
</style>
|
207
src/views/dashboard/related/ebpf/components/TaskList.vue
Normal file
@@ -0,0 +1,207 @@
|
||||
<!-- 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-task-list flex-v">
|
||||
<div class="profile-task-wrapper flex-v">
|
||||
<div class="profile-t-tool flex-h">{{ t("taskList") }}</div>
|
||||
<div class="profile-t-wrapper">
|
||||
<div class="no-data" v-show="!ebpfStore.taskList.length">
|
||||
{{ t("noData") }}
|
||||
</div>
|
||||
<table class="profile-t">
|
||||
<tr
|
||||
class="profile-tr cp"
|
||||
v-for="(i, index) in ebpfStore.taskList"
|
||||
@click="changeTask(i)"
|
||||
:key="index"
|
||||
>
|
||||
<td
|
||||
class="profile-td"
|
||||
:class="{
|
||||
selected: selectedTask.taskId === i.taskId,
|
||||
}"
|
||||
>
|
||||
<div class="ell">
|
||||
<span>
|
||||
{{
|
||||
i.targetType +
|
||||
": " +
|
||||
(i.processLabels.length
|
||||
? i.processLabels.join(" ")
|
||||
: `All Processes`)
|
||||
}}
|
||||
</span>
|
||||
<a class="profile-btn r" @click="viewDetail = true">
|
||||
<Icon iconName="view" size="middle" />
|
||||
</a>
|
||||
</div>
|
||||
<div class="grey ell sm">
|
||||
<span class="mr-10 sm">{{ dateFormat(i.taskStartTime) }}</span>
|
||||
<span class="mr-10 sm">
|
||||
{{
|
||||
dateFormat(i.taskStartTime + i.fixedTriggerDuration * 1000)
|
||||
}}
|
||||
</span>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<el-dialog
|
||||
v-model="viewDetail"
|
||||
:destroy-on-close="true"
|
||||
fullscreen
|
||||
@closed="viewDetail = false"
|
||||
>
|
||||
<div class="profile-detail flex-v">
|
||||
<div>
|
||||
<h5 class="mb-10">{{ t("task") }}.</h5>
|
||||
<div class="mb-10 clear item">
|
||||
<span class="g-sm-4 grey">{{ t("taskId") }}:</span>
|
||||
<span class="g-sm-8 wba">
|
||||
{{ selectedTask.taskId }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="mb-10 clear item">
|
||||
<span class="g-sm-4 grey">{{ t("service") }}:</span>
|
||||
<span class="g-sm-8 wba">{{ selectedTask.serviceName }}</span>
|
||||
</div>
|
||||
<div class="mb-10 clear item">
|
||||
<span class="g-sm-4 grey">{{ t("labels") }}:</span>
|
||||
<span class="g-sm-8 wba">
|
||||
{{ selectedTask.processLabels.join(";") }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="mb-10 clear item">
|
||||
<span class="g-sm-4 grey">{{ t("monitorTime") }}:</span>
|
||||
<span class="g-sm-8 wba">
|
||||
{{ dateFormat(selectedTask.taskStartTime) }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="mb-10 clear item">
|
||||
<span class="g-sm-4 grey">{{ t("monitorDuration") }}:</span>
|
||||
<span class="g-sm-8 wba">
|
||||
{{ selectedTask.fixedTriggerDuration / 60 }} min
|
||||
</span>
|
||||
</div>
|
||||
<div class="mb-10 clear item">
|
||||
<span class="g-sm-4 grey">{{ t("triggerType") }}:</span>
|
||||
<span class="g-sm-8 wba">{{ selectedTask.triggerType }}</span>
|
||||
</div>
|
||||
<div class="mb-10 clear item">
|
||||
<span class="g-sm-4 grey">{{ t("targetType") }}:</span>
|
||||
<span class="g-sm-8 wba">{{ selectedTask.targetType }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref, watch } from "vue";
|
||||
import dayjs from "dayjs";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { useEbpfStore } from "@/store/modules/ebpf";
|
||||
import { EBPFTaskList } from "@/types/ebpf";
|
||||
import { ElMessage } from "element-plus";
|
||||
|
||||
const { t } = useI18n();
|
||||
const ebpfStore = useEbpfStore();
|
||||
const dateFormat = (date: number, pattern = "YYYY-MM-DD HH:mm:ss") =>
|
||||
dayjs(date).format(pattern);
|
||||
const selectedTask = ref<EBPFTaskList | Record<string, never>>({});
|
||||
const viewDetail = ref<boolean>(false);
|
||||
|
||||
async function changeTask(item: EBPFTaskList) {
|
||||
selectedTask.value = item;
|
||||
ebpfStore.setSelectedTask(item);
|
||||
const res = await ebpfStore.getEBPFSchedules({
|
||||
taskId: item.taskId,
|
||||
});
|
||||
if (res.errors) {
|
||||
ElMessage.error(res.errors);
|
||||
}
|
||||
}
|
||||
watch(
|
||||
() => ebpfStore.taskList,
|
||||
() => {
|
||||
selectedTask.value = ebpfStore.taskList[0] || {};
|
||||
ebpfStore.setSelectedTask(selectedTask.value);
|
||||
}
|
||||
);
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.profile-task-list {
|
||||
width: 300px;
|
||||
height: calc(100% - 10px);
|
||||
overflow: auto;
|
||||
border-right: 1px solid rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.item span {
|
||||
height: 21px;
|
||||
}
|
||||
|
||||
.profile-td {
|
||||
padding: 5px 10px;
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.07);
|
||||
|
||||
&.selected {
|
||||
background-color: #ededed;
|
||||
}
|
||||
}
|
||||
|
||||
.no-data {
|
||||
text-align: center;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.profile-t-wrapper {
|
||||
overflow: auto;
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.profile-t {
|
||||
width: 100%;
|
||||
border-spacing: 0;
|
||||
table-layout: fixed;
|
||||
flex-grow: 1;
|
||||
position: relative;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.profile-tr {
|
||||
&:hover {
|
||||
background-color: rgba(0, 0, 0, 0.04);
|
||||
}
|
||||
}
|
||||
|
||||
.profile-t-tool {
|
||||
padding: 5px 10px;
|
||||
font-weight: bold;
|
||||
border-right: 1px solid rgba(0, 0, 0, 0.07);
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.07);
|
||||
background: #f3f4f9;
|
||||
}
|
||||
|
||||
.profile-btn {
|
||||
color: #3d444f;
|
||||
padding: 1px 3px;
|
||||
border-radius: 2px;
|
||||
font-size: 12px;
|
||||
float: right;
|
||||
}
|
||||
</style>
|