mirror of
https://github.com/apache/skywalking-booster-ui.git
synced 2025-05-01 15:53:05 +00:00
feat: Implement the eBPF profile widget on dashboard (#72)
This commit is contained in:
parent
393885324b
commit
8a07b1d804
314
package-lock.json
generated
314
package-lock.json
generated
@ -10,11 +10,13 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"axios": "^0.24.0",
|
"axios": "^0.24.0",
|
||||||
"d3": "^7.3.0",
|
"d3": "^7.3.0",
|
||||||
|
"d3-flame-graph": "^4.1.3",
|
||||||
"d3-tip": "^0.9.1",
|
"d3-tip": "^0.9.1",
|
||||||
"echarts": "^5.2.2",
|
"echarts": "^5.2.2",
|
||||||
"element-plus": "^2.0.2",
|
"element-plus": "^2.0.2",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"pinia": "^2.0.5",
|
"pinia": "^2.0.5",
|
||||||
|
"vis-timeline": "^7.5.1",
|
||||||
"vue": "^3.0.0",
|
"vue": "^3.0.0",
|
||||||
"vue-grid-layout": "^3.0.0-beta1",
|
"vue-grid-layout": "^3.0.0-beta1",
|
||||||
"vue-i18n": "^9.1.9",
|
"vue-i18n": "^9.1.9",
|
||||||
@ -1810,6 +1812,18 @@
|
|||||||
"ms": "^2.1.1"
|
"ms": "^2.1.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@egjs/hammerjs": {
|
||||||
|
"version": "2.0.17",
|
||||||
|
"resolved": "https://registry.npmjs.org/@egjs/hammerjs/-/hammerjs-2.0.17.tgz",
|
||||||
|
"integrity": "sha512-XQsZgjm2EcVUiZQf11UBJQfmZeEmOW8DpI1gsFeln6w0ae0ii4dMQEQ0kjl6DspdWX1aGY1/loyXnP0JS06e/A==",
|
||||||
|
"peer": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@types/hammerjs": "^2.0.36"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.8.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@element-plus/icons-vue": {
|
"node_modules/@element-plus/icons-vue": {
|
||||||
"version": "0.2.7",
|
"version": "0.2.7",
|
||||||
"resolved": "https://registry.npmjs.org/@element-plus/icons-vue/-/icons-vue-0.2.7.tgz",
|
"resolved": "https://registry.npmjs.org/@element-plus/icons-vue/-/icons-vue-0.2.7.tgz",
|
||||||
@ -3299,6 +3313,12 @@
|
|||||||
"@types/node": "*"
|
"@types/node": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/hammerjs": {
|
||||||
|
"version": "2.0.41",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/hammerjs/-/hammerjs-2.0.41.tgz",
|
||||||
|
"integrity": "sha512-ewXv/ceBaJprikMcxCmWU1FKyMAQ2X7a9Gtmzw8fcg2kIePI1crERDM818W+XYrxqdBBOdlf2rm137bU+BltCA==",
|
||||||
|
"peer": true
|
||||||
|
},
|
||||||
"node_modules/@types/http-proxy": {
|
"node_modules/@types/http-proxy": {
|
||||||
"version": "1.17.8",
|
"version": "1.17.8",
|
||||||
"resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.8.tgz",
|
"resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.8.tgz",
|
||||||
@ -7881,8 +7901,7 @@
|
|||||||
"node_modules/component-emitter": {
|
"node_modules/component-emitter": {
|
||||||
"version": "1.3.0",
|
"version": "1.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz",
|
||||||
"integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==",
|
"integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"node_modules/compressible": {
|
"node_modules/compressible": {
|
||||||
"version": "2.0.18",
|
"version": "2.0.18",
|
||||||
@ -8694,6 +8713,12 @@
|
|||||||
"node": ">=4"
|
"node": ">=4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/cssfilter": {
|
||||||
|
"version": "0.0.10",
|
||||||
|
"resolved": "https://registry.npmjs.org/cssfilter/-/cssfilter-0.0.10.tgz",
|
||||||
|
"integrity": "sha1-xtJnJjKi5cg+AT5oZKQs6N79IK4=",
|
||||||
|
"peer": true
|
||||||
|
},
|
||||||
"node_modules/cssnano": {
|
"node_modules/cssnano": {
|
||||||
"version": "4.1.11",
|
"version": "4.1.11",
|
||||||
"resolved": "https://registry.npmjs.org/cssnano/-/cssnano-4.1.11.tgz",
|
"resolved": "https://registry.npmjs.org/cssnano/-/cssnano-4.1.11.tgz",
|
||||||
@ -9104,6 +9129,16 @@
|
|||||||
"node": ">=0.8"
|
"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": {
|
"node_modules/d3": {
|
||||||
"version": "7.3.0",
|
"version": "7.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/d3/-/d3-7.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/d3/-/d3-7.3.0.tgz",
|
||||||
@ -9306,6 +9341,21 @@
|
|||||||
"node": ">=12"
|
"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": {
|
"node_modules/d3-force": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/d3-force/-/d3-force-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/d3-force/-/d3-force-3.0.0.tgz",
|
||||||
@ -16412,6 +16462,12 @@
|
|||||||
"node": ">=0.6.0"
|
"node": ">=0.6.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/keycharm": {
|
||||||
|
"version": "0.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/keycharm/-/keycharm-0.4.0.tgz",
|
||||||
|
"integrity": "sha512-TyQTtsabOVv3MeOpR92sIKk/br9wxS+zGj4BG7CR8YbK4jM3tyIBaF0zhzeBUMx36/Q/iQLOKKOT+3jOQtemRQ==",
|
||||||
|
"peer": true
|
||||||
|
},
|
||||||
"node_modules/killable": {
|
"node_modules/killable": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/killable/-/killable-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/killable/-/killable-1.0.1.tgz",
|
||||||
@ -18203,7 +18259,6 @@
|
|||||||
"version": "2.24.0",
|
"version": "2.24.0",
|
||||||
"resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz",
|
"resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz",
|
||||||
"integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==",
|
"integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==",
|
||||||
"dev": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "*"
|
"node": "*"
|
||||||
}
|
}
|
||||||
@ -21672,6 +21727,15 @@
|
|||||||
"node": ">= 6"
|
"node": ">= 6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/propagating-hammerjs": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/propagating-hammerjs/-/propagating-hammerjs-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-PH3zG5whbSxMocphXJzVtvKr+vWAgfkqVvtuwjSJ/apmEACUoiw6auBAT5HYXpZOR0eGcTAfYG5Yl8h91O5Elg==",
|
||||||
|
"peer": true,
|
||||||
|
"peerDependencies": {
|
||||||
|
"@egjs/hammerjs": "^2.0.17"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/proto-list": {
|
"node_modules/proto-list": {
|
||||||
"version": "1.2.4",
|
"version": "1.2.4",
|
||||||
"resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz",
|
"resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz",
|
||||||
@ -22411,6 +22475,16 @@
|
|||||||
"request": "^2.34"
|
"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": {
|
"node_modules/require-directory": {
|
||||||
"version": "2.1.1",
|
"version": "2.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
|
||||||
@ -23746,15 +23820,6 @@
|
|||||||
"ms": "^2.1.1"
|
"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": {
|
"node_modules/sort-keys": {
|
||||||
"version": "1.1.2",
|
"version": "1.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz",
|
||||||
@ -26807,13 +26872,11 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/uuid": {
|
"node_modules/uuid": {
|
||||||
"version": "3.4.0",
|
"version": "8.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
|
||||||
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==",
|
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
|
||||||
"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": {
|
"bin": {
|
||||||
"uuid": "bin/uuid"
|
"uuid": "dist/bin/uuid"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/v8-compile-cache": {
|
"node_modules/v8-compile-cache": {
|
||||||
@ -26871,6 +26934,59 @@
|
|||||||
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
|
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/vis-data": {
|
||||||
|
"version": "7.1.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/vis-data/-/vis-data-7.1.4.tgz",
|
||||||
|
"integrity": "sha512-usy+ePX1XnArNvJ5BavQod7YRuGQE1pjFl+pu7IS6rCom2EBoG0o1ZzCqf3l5US6MW51kYkLR+efxRbnjxNl7w==",
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"peer": true,
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/visjs"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"uuid": "^7.0.0 || ^8.0.0",
|
||||||
|
"vis-util": "^4.0.0 || ^5.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/vis-timeline": {
|
||||||
|
"version": "7.5.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/vis-timeline/-/vis-timeline-7.5.1.tgz",
|
||||||
|
"integrity": "sha512-XZMHHbA8xm9/Y/iu3mE9MT7J5tfWgbdsW+PmqrgINU2QRX24AiqifNHZHV4YYzeJstiTSOg9Gs5qRkxQ0BvZJw==",
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/visjs"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@egjs/hammerjs": "^2.0.0",
|
||||||
|
"component-emitter": "^1.3.0",
|
||||||
|
"keycharm": "^0.3.0 || ^0.4.0",
|
||||||
|
"moment": "^2.24.0",
|
||||||
|
"propagating-hammerjs": "^1.4.0 || ^2.0.0",
|
||||||
|
"uuid": "^3.4.0 || ^7.0.0 || ^8.0.0",
|
||||||
|
"vis-data": "^6.3.0 || ^7.0.0",
|
||||||
|
"vis-util": "^3.0.0 || ^4.0.0 || ^5.0.0",
|
||||||
|
"xss": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/vis-util": {
|
||||||
|
"version": "5.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/vis-util/-/vis-util-5.0.3.tgz",
|
||||||
|
"integrity": "sha512-Wf9STUcFrDzK4/Zr7B6epW2Kvm3ORNWF+WiwEz2dpf5RdWkLUXFSbLcuB88n1W6tCdFwVN+v3V4/Xmn9PeL39g==",
|
||||||
|
"peer": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/visjs"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@egjs/hammerjs": "^2.0.0",
|
||||||
|
"component-emitter": "^1.3.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/vm-browserify": {
|
"node_modules/vm-browserify": {
|
||||||
"version": "1.1.2",
|
"version": "1.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz",
|
||||||
@ -28266,6 +28382,16 @@
|
|||||||
"node": ">= 6"
|
"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": {
|
"node_modules/webpack-merge": {
|
||||||
"version": "4.2.2",
|
"version": "4.2.2",
|
||||||
"resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-4.2.2.tgz",
|
"resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-4.2.2.tgz",
|
||||||
@ -28709,6 +28835,28 @@
|
|||||||
"integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==",
|
"integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/xss": {
|
||||||
|
"version": "1.0.11",
|
||||||
|
"resolved": "https://registry.npmjs.org/xss/-/xss-1.0.11.tgz",
|
||||||
|
"integrity": "sha512-EimjrjThZeK2MO7WKR9mN5ZC1CSqivSl55wvUK5EtU6acf0rzEE1pN+9ZDrFXJ82BRp3JL38pPE6S4o/rpp1zQ==",
|
||||||
|
"peer": true,
|
||||||
|
"dependencies": {
|
||||||
|
"commander": "^2.20.3",
|
||||||
|
"cssfilter": "0.0.10"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"xss": "bin/xss"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/xss/node_modules/commander": {
|
||||||
|
"version": "2.20.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
|
||||||
|
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
|
||||||
|
"peer": true
|
||||||
|
},
|
||||||
"node_modules/xtend": {
|
"node_modules/xtend": {
|
||||||
"version": "4.0.2",
|
"version": "4.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
|
||||||
@ -30163,6 +30311,15 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@egjs/hammerjs": {
|
||||||
|
"version": "2.0.17",
|
||||||
|
"resolved": "https://registry.npmjs.org/@egjs/hammerjs/-/hammerjs-2.0.17.tgz",
|
||||||
|
"integrity": "sha512-XQsZgjm2EcVUiZQf11UBJQfmZeEmOW8DpI1gsFeln6w0ae0ii4dMQEQ0kjl6DspdWX1aGY1/loyXnP0JS06e/A==",
|
||||||
|
"peer": true,
|
||||||
|
"requires": {
|
||||||
|
"@types/hammerjs": "^2.0.36"
|
||||||
|
}
|
||||||
|
},
|
||||||
"@element-plus/icons-vue": {
|
"@element-plus/icons-vue": {
|
||||||
"version": "0.2.7",
|
"version": "0.2.7",
|
||||||
"resolved": "https://registry.npmjs.org/@element-plus/icons-vue/-/icons-vue-0.2.7.tgz",
|
"resolved": "https://registry.npmjs.org/@element-plus/icons-vue/-/icons-vue-0.2.7.tgz",
|
||||||
@ -31426,6 +31583,12 @@
|
|||||||
"@types/node": "*"
|
"@types/node": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@types/hammerjs": {
|
||||||
|
"version": "2.0.41",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/hammerjs/-/hammerjs-2.0.41.tgz",
|
||||||
|
"integrity": "sha512-ewXv/ceBaJprikMcxCmWU1FKyMAQ2X7a9Gtmzw8fcg2kIePI1crERDM818W+XYrxqdBBOdlf2rm137bU+BltCA==",
|
||||||
|
"peer": true
|
||||||
|
},
|
||||||
"@types/http-proxy": {
|
"@types/http-proxy": {
|
||||||
"version": "1.17.8",
|
"version": "1.17.8",
|
||||||
"resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.8.tgz",
|
"resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.8.tgz",
|
||||||
@ -35117,8 +35280,7 @@
|
|||||||
"component-emitter": {
|
"component-emitter": {
|
||||||
"version": "1.3.0",
|
"version": "1.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz",
|
||||||
"integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==",
|
"integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"compressible": {
|
"compressible": {
|
||||||
"version": "2.0.18",
|
"version": "2.0.18",
|
||||||
@ -35759,6 +35921,12 @@
|
|||||||
"integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==",
|
"integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"cssfilter": {
|
||||||
|
"version": "0.0.10",
|
||||||
|
"resolved": "https://registry.npmjs.org/cssfilter/-/cssfilter-0.0.10.tgz",
|
||||||
|
"integrity": "sha1-xtJnJjKi5cg+AT5oZKQs6N79IK4=",
|
||||||
|
"peer": true
|
||||||
|
},
|
||||||
"cssnano": {
|
"cssnano": {
|
||||||
"version": "4.1.11",
|
"version": "4.1.11",
|
||||||
"resolved": "https://registry.npmjs.org/cssnano/-/cssnano-4.1.11.tgz",
|
"resolved": "https://registry.npmjs.org/cssnano/-/cssnano-4.1.11.tgz",
|
||||||
@ -36098,6 +36266,12 @@
|
|||||||
"psl": "^1.1.24",
|
"psl": "^1.1.24",
|
||||||
"punycode": "^1.4.1"
|
"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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -36249,6 +36423,21 @@
|
|||||||
"d3-dsv": "1 - 3"
|
"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": {
|
"d3-force": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/d3-force/-/d3-force-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/d3-force/-/d3-force-3.0.0.tgz",
|
||||||
@ -41825,6 +42014,12 @@
|
|||||||
"verror": "1.10.0"
|
"verror": "1.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"keycharm": {
|
||||||
|
"version": "0.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/keycharm/-/keycharm-0.4.0.tgz",
|
||||||
|
"integrity": "sha512-TyQTtsabOVv3MeOpR92sIKk/br9wxS+zGj4BG7CR8YbK4jM3tyIBaF0zhzeBUMx36/Q/iQLOKKOT+3jOQtemRQ==",
|
||||||
|
"peer": true
|
||||||
|
},
|
||||||
"killable": {
|
"killable": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/killable/-/killable-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/killable/-/killable-1.0.1.tgz",
|
||||||
@ -43211,8 +43406,7 @@
|
|||||||
"moment": {
|
"moment": {
|
||||||
"version": "2.24.0",
|
"version": "2.24.0",
|
||||||
"resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz",
|
"resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz",
|
||||||
"integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==",
|
"integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"move-concurrently": {
|
"move-concurrently": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
@ -45877,6 +46071,13 @@
|
|||||||
"sisteransi": "^1.0.5"
|
"sisteransi": "^1.0.5"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"propagating-hammerjs": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/propagating-hammerjs/-/propagating-hammerjs-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-PH3zG5whbSxMocphXJzVtvKr+vWAgfkqVvtuwjSJ/apmEACUoiw6auBAT5HYXpZOR0eGcTAfYG5Yl8h91O5Elg==",
|
||||||
|
"peer": true,
|
||||||
|
"requires": {}
|
||||||
|
},
|
||||||
"proto-list": {
|
"proto-list": {
|
||||||
"version": "1.2.4",
|
"version": "1.2.4",
|
||||||
"resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz",
|
"resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz",
|
||||||
@ -46435,6 +46636,14 @@
|
|||||||
"tough-cookie": "~2.5.0",
|
"tough-cookie": "~2.5.0",
|
||||||
"tunnel-agent": "^0.6.0",
|
"tunnel-agent": "^0.6.0",
|
||||||
"uuid": "^3.3.2"
|
"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": {
|
"request-progress": {
|
||||||
@ -47531,14 +47740,6 @@
|
|||||||
"faye-websocket": "^0.11.3",
|
"faye-websocket": "^0.11.3",
|
||||||
"uuid": "^8.3.2",
|
"uuid": "^8.3.2",
|
||||||
"websocket-driver": "^0.7.4"
|
"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": {
|
"sockjs-client": {
|
||||||
@ -49976,10 +50177,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"uuid": {
|
"uuid": {
|
||||||
"version": "3.4.0",
|
"version": "8.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
|
||||||
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==",
|
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"v8-compile-cache": {
|
"v8-compile-cache": {
|
||||||
"version": "2.3.0",
|
"version": "2.3.0",
|
||||||
@ -50028,6 +50228,26 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"vis-data": {
|
||||||
|
"version": "7.1.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/vis-data/-/vis-data-7.1.4.tgz",
|
||||||
|
"integrity": "sha512-usy+ePX1XnArNvJ5BavQod7YRuGQE1pjFl+pu7IS6rCom2EBoG0o1ZzCqf3l5US6MW51kYkLR+efxRbnjxNl7w==",
|
||||||
|
"peer": true,
|
||||||
|
"requires": {}
|
||||||
|
},
|
||||||
|
"vis-timeline": {
|
||||||
|
"version": "7.5.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/vis-timeline/-/vis-timeline-7.5.1.tgz",
|
||||||
|
"integrity": "sha512-XZMHHbA8xm9/Y/iu3mE9MT7J5tfWgbdsW+PmqrgINU2QRX24AiqifNHZHV4YYzeJstiTSOg9Gs5qRkxQ0BvZJw==",
|
||||||
|
"requires": {}
|
||||||
|
},
|
||||||
|
"vis-util": {
|
||||||
|
"version": "5.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/vis-util/-/vis-util-5.0.3.tgz",
|
||||||
|
"integrity": "sha512-Wf9STUcFrDzK4/Zr7B6epW2Kvm3ORNWF+WiwEz2dpf5RdWkLUXFSbLcuB88n1W6tCdFwVN+v3V4/Xmn9PeL39g==",
|
||||||
|
"peer": true,
|
||||||
|
"requires": {}
|
||||||
|
},
|
||||||
"vm-browserify": {
|
"vm-browserify": {
|
||||||
"version": "1.1.2",
|
"version": "1.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz",
|
||||||
@ -51307,6 +51527,14 @@
|
|||||||
"requires": {
|
"requires": {
|
||||||
"ansi-colors": "^3.0.0",
|
"ansi-colors": "^3.0.0",
|
||||||
"uuid": "^3.3.2"
|
"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": {
|
"webpack-merge": {
|
||||||
@ -51531,6 +51759,24 @@
|
|||||||
"integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==",
|
"integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"xss": {
|
||||||
|
"version": "1.0.11",
|
||||||
|
"resolved": "https://registry.npmjs.org/xss/-/xss-1.0.11.tgz",
|
||||||
|
"integrity": "sha512-EimjrjThZeK2MO7WKR9mN5ZC1CSqivSl55wvUK5EtU6acf0rzEE1pN+9ZDrFXJ82BRp3JL38pPE6S4o/rpp1zQ==",
|
||||||
|
"peer": true,
|
||||||
|
"requires": {
|
||||||
|
"commander": "^2.20.3",
|
||||||
|
"cssfilter": "0.0.10"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"commander": {
|
||||||
|
"version": "2.20.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
|
||||||
|
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
|
||||||
|
"peer": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"xtend": {
|
"xtend": {
|
||||||
"version": "4.0.2",
|
"version": "4.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
|
||||||
|
@ -12,11 +12,13 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"axios": "^0.24.0",
|
"axios": "^0.24.0",
|
||||||
"d3": "^7.3.0",
|
"d3": "^7.3.0",
|
||||||
|
"d3-flame-graph": "^4.1.3",
|
||||||
"d3-tip": "^0.9.1",
|
"d3-tip": "^0.9.1",
|
||||||
"echarts": "^5.2.2",
|
"echarts": "^5.2.2",
|
||||||
"element-plus": "^2.0.2",
|
"element-plus": "^2.0.2",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"pinia": "^2.0.5",
|
"pinia": "^2.0.5",
|
||||||
|
"vis-timeline": "^7.5.1",
|
||||||
"vue": "^3.0.0",
|
"vue": "^3.0.0",
|
||||||
"vue-grid-layout": "^3.0.0-beta1",
|
"vue-grid-layout": "^3.0.0-beta1",
|
||||||
"vue-i18n": "^9.1.9",
|
"vue-i18n": "^9.1.9",
|
||||||
|
17
src/assets/icons/insert_chart.svg
Normal file
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 |
15
src/assets/icons/view.svg
Normal file
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 |
@ -32,7 +32,7 @@ interface Option {
|
|||||||
const emit = defineEmits(["change"]);
|
const emit = defineEmits(["change"]);
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
options: {
|
options: {
|
||||||
type: Array as PropType<(Option & { disabled: boolean })[]>,
|
type: Array as PropType<Option[]>,
|
||||||
default: () => [],
|
default: () => [],
|
||||||
},
|
},
|
||||||
value: {
|
value: {
|
||||||
@ -44,7 +44,7 @@ const props = defineProps({
|
|||||||
|
|
||||||
const selected = ref<string>(props.value);
|
const selected = ref<string>(props.value);
|
||||||
|
|
||||||
function checked(opt: string) {
|
function checked(opt: unknown) {
|
||||||
emit("change", opt);
|
emit("change", opt);
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -58,7 +58,7 @@ const props = defineProps({
|
|||||||
},
|
},
|
||||||
size: { type: null, default: "default" },
|
size: { type: null, default: "default" },
|
||||||
placeholder: {
|
placeholder: {
|
||||||
type: [String, Number] as PropType<string | number>,
|
type: [String, undefined] as PropType<string>,
|
||||||
default: "Select a option",
|
default: "Select a option",
|
||||||
},
|
},
|
||||||
borderRadius: { type: Number, default: 3 },
|
borderRadius: { type: Number, default: 3 },
|
||||||
|
@ -14,13 +14,13 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
import type { App } from "vue";
|
||||||
import Icon from "./Icon.vue";
|
import Icon from "./Icon.vue";
|
||||||
import TimePicker from "./TimePicker.vue";
|
import TimePicker from "./TimePicker.vue";
|
||||||
import Selector from "./Selector.vue";
|
import Selector from "./Selector.vue";
|
||||||
import Graph from "./Graph.vue";
|
import Graph from "./Graph.vue";
|
||||||
import Radio from "./Radio.vue";
|
import Radio from "./Radio.vue";
|
||||||
import SelectSingle from "./SelectSingle.vue";
|
import SelectSingle from "./SelectSingle.vue";
|
||||||
import type { App } from "vue";
|
|
||||||
import VueGridLayout from "vue-grid-layout";
|
import VueGridLayout from "vue-grid-layout";
|
||||||
|
|
||||||
const components: { [key: string]: any } = {
|
const components: { [key: string]: any } = {
|
||||||
|
93
src/graphql/fragments/ebpf.ts
Normal file
93
src/graphql/fragments/ebpf.ts
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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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!, $duration: Duration!",
|
||||||
|
query: `
|
||||||
|
eBPFSchedules: queryEBPFProfilingSchedules(taskId: $taskId, duration: $duration) {
|
||||||
|
scheduleId
|
||||||
|
taskId
|
||||||
|
process {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
serviceId
|
||||||
|
serviceName
|
||||||
|
instanceId
|
||||||
|
instanceName
|
||||||
|
layer
|
||||||
|
agentId
|
||||||
|
detectType
|
||||||
|
attributes {
|
||||||
|
name
|
||||||
|
value
|
||||||
|
}
|
||||||
|
labels
|
||||||
|
}
|
||||||
|
startTime
|
||||||
|
endTime
|
||||||
|
}`,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const analysisEBPFResult = {
|
||||||
|
variable:
|
||||||
|
"$scheduleIdList: [ID!]!, $timeRanges: [EBPFProfilingAnalyzeTimeRange!]!",
|
||||||
|
query: `
|
||||||
|
analysisEBPFResult: analysisEBPFProfilingResult(scheduleIdList: $scheduleIdList, timeRanges: $timeRanges) {
|
||||||
|
tip
|
||||||
|
trees {
|
||||||
|
elements {
|
||||||
|
id
|
||||||
|
parentId
|
||||||
|
symbol
|
||||||
|
stackType
|
||||||
|
dumpCount
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}`,
|
||||||
|
};
|
@ -25,6 +25,7 @@ import * as log from "./query/log";
|
|||||||
import * as profile from "./query/profile";
|
import * as profile from "./query/profile";
|
||||||
import * as alarm from "./query/alarm";
|
import * as alarm from "./query/alarm";
|
||||||
import * as event from "./query/event";
|
import * as event from "./query/event";
|
||||||
|
import * as ebpf from "./query/ebpf";
|
||||||
|
|
||||||
const query: { [key: string]: string } = {
|
const query: { [key: string]: string } = {
|
||||||
...app,
|
...app,
|
||||||
@ -36,6 +37,7 @@ const query: { [key: string]: string } = {
|
|||||||
...profile,
|
...profile,
|
||||||
...alarm,
|
...alarm,
|
||||||
...event,
|
...event,
|
||||||
|
...ebpf,
|
||||||
};
|
};
|
||||||
class Graphql {
|
class Graphql {
|
||||||
private queryData = "";
|
private queryData = "";
|
||||||
|
34
src/graphql/query/ebpf.ts
Normal file
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}}`;
|
@ -131,6 +131,11 @@ const msg = {
|
|||||||
metricLabel: "Metric Label",
|
metricLabel: "Metric Label",
|
||||||
showUnit: "Show Unit",
|
showUnit: "Show Unit",
|
||||||
noGraph: "No Graph",
|
noGraph: "No Graph",
|
||||||
|
taskId: "Task ID",
|
||||||
|
triggerType: "Trigger Type",
|
||||||
|
targetType: "Target Type",
|
||||||
|
ebpfTip: "Don't have process could profiling",
|
||||||
|
processSelect: "Click to select processes",
|
||||||
hourTip: "Select Hour",
|
hourTip: "Select Hour",
|
||||||
minuteTip: "Select Minute",
|
minuteTip: "Select Minute",
|
||||||
secondTip: "Select Second",
|
secondTip: "Select Second",
|
||||||
|
@ -129,6 +129,11 @@ const msg = {
|
|||||||
metricLabel: "指标标签",
|
metricLabel: "指标标签",
|
||||||
showUnit: "显示单位",
|
showUnit: "显示单位",
|
||||||
noGraph: "无图表",
|
noGraph: "无图表",
|
||||||
|
taskId: "任务ID",
|
||||||
|
triggerType: "触发类型",
|
||||||
|
targetType: "目标类型",
|
||||||
|
processSelect: "点击选择进程",
|
||||||
|
ebpfTip: "没有进程可以分析",
|
||||||
hourTip: "选择小时",
|
hourTip: "选择小时",
|
||||||
minuteTip: "选择分钟",
|
minuteTip: "选择分钟",
|
||||||
secondTip: "选择秒数",
|
secondTip: "选择秒数",
|
||||||
|
@ -20,7 +20,7 @@ import router from "./router";
|
|||||||
import { store } from "./store";
|
import { store } from "./store";
|
||||||
import components from "@/components";
|
import components from "@/components";
|
||||||
import i18n from "./locales";
|
import i18n from "./locales";
|
||||||
import "./styles/index.scss";
|
import "./styles/index.ts";
|
||||||
|
|
||||||
const app = createApp(App);
|
const app = createApp(App);
|
||||||
|
|
||||||
|
@ -114,7 +114,12 @@ export const dashboardStore = defineStore({
|
|||||||
: 3,
|
: 3,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if (type === "Trace" || type === "Profile" || type === "Log") {
|
if (
|
||||||
|
type === "Trace" ||
|
||||||
|
type === "Profile" ||
|
||||||
|
type === "Log" ||
|
||||||
|
type === "Ebpf"
|
||||||
|
) {
|
||||||
newItem.h = 36;
|
newItem.h = 36;
|
||||||
}
|
}
|
||||||
if (type === "Text") {
|
if (type === "Text") {
|
||||||
|
153
src/store/modules/ebpf.ts
Normal file
153
src/store/modules/ebpf.ts
Normal file
@ -0,0 +1,153 @@
|
|||||||
|
/**
|
||||||
|
* 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 { Duration, Option } from "@/types/app";
|
||||||
|
import {
|
||||||
|
EBPFTaskCreationRequest,
|
||||||
|
EBPFProfilingSchedule,
|
||||||
|
EBPFTaskList,
|
||||||
|
AnalyzationTrees,
|
||||||
|
} from "@/types/ebpf";
|
||||||
|
import { Trace, Span } from "@/types/trace";
|
||||||
|
import { store } from "@/store";
|
||||||
|
import graphql from "@/graphql";
|
||||||
|
import { AxiosResponse } from "axios";
|
||||||
|
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||||
|
|
||||||
|
interface EbpfStore {
|
||||||
|
durationTime: Duration;
|
||||||
|
taskList: EBPFTaskList[];
|
||||||
|
eBPFSchedules: EBPFProfilingSchedule[];
|
||||||
|
currentSchedule: EBPFProfilingSchedule | Record<string, never>;
|
||||||
|
analyzeTrees: AnalyzationTrees[];
|
||||||
|
labels: Option[];
|
||||||
|
couldProfiling: boolean;
|
||||||
|
tip: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ebpfStore = defineStore({
|
||||||
|
id: "eBPF",
|
||||||
|
state: (): EbpfStore => ({
|
||||||
|
durationTime: useAppStoreWithOut().durationTime,
|
||||||
|
taskList: [],
|
||||||
|
eBPFSchedules: [],
|
||||||
|
currentSchedule: {},
|
||||||
|
analyzeTrees: [],
|
||||||
|
labels: [{ value: "", label: "" }],
|
||||||
|
couldProfiling: false,
|
||||||
|
tip: "",
|
||||||
|
}),
|
||||||
|
actions: {
|
||||||
|
setCurrentSpan(span: Span) {
|
||||||
|
this.currentSpan = span;
|
||||||
|
},
|
||||||
|
setCurrentSchedule(s: Trace) {
|
||||||
|
this.currentSchedule = s;
|
||||||
|
},
|
||||||
|
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) {
|
||||||
|
const res: AxiosResponse = await graphql
|
||||||
|
.query("getEBPFTasks")
|
||||||
|
.params({ serviceId });
|
||||||
|
|
||||||
|
this.tip = "";
|
||||||
|
if (res.data.errors) {
|
||||||
|
return res.data;
|
||||||
|
}
|
||||||
|
this.taskList = res.data.data.queryEBPFTasks.reverse() || [];
|
||||||
|
if (!this.taskList.length) {
|
||||||
|
return res.data;
|
||||||
|
}
|
||||||
|
this.getEBPFSchedules({ taskId: this.taskList[0].taskId });
|
||||||
|
return res.data;
|
||||||
|
},
|
||||||
|
async getEBPFSchedules(params: { taskId: string; duration?: Duration }) {
|
||||||
|
const duration = useAppStoreWithOut().durationTime;
|
||||||
|
const res: AxiosResponse = await graphql
|
||||||
|
.query("getEBPFSchedules")
|
||||||
|
.params({ ...params, duration });
|
||||||
|
|
||||||
|
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 }>;
|
||||||
|
}) {
|
||||||
|
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[0].elements;
|
||||||
|
return res.data;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export function useEbpfStore(): any {
|
||||||
|
return ebpfStore(store);
|
||||||
|
}
|
@ -16,7 +16,7 @@
|
|||||||
*/
|
*/
|
||||||
import { defineStore } from "pinia";
|
import { defineStore } from "pinia";
|
||||||
import { Duration } from "@/types/app";
|
import { Duration } from "@/types/app";
|
||||||
import { Service } from "@/types/selector";
|
import { Endpoint } from "@/types/selector";
|
||||||
import {
|
import {
|
||||||
TaskListItem,
|
TaskListItem,
|
||||||
SegmentSpan,
|
SegmentSpan,
|
||||||
@ -31,7 +31,8 @@ import { AxiosResponse } from "axios";
|
|||||||
import { useAppStoreWithOut } from "@/store/modules/app";
|
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||||
|
|
||||||
interface ProfileState {
|
interface ProfileState {
|
||||||
services: Service[];
|
endpoints: Endpoint[];
|
||||||
|
taskEndpoints: Endpoint[];
|
||||||
durationTime: Duration;
|
durationTime: Duration;
|
||||||
condition: { serviceId: string; endpointName: string };
|
condition: { serviceId: string; endpointName: string };
|
||||||
taskList: TaskListItem[];
|
taskList: TaskListItem[];
|
||||||
@ -47,7 +48,8 @@ interface ProfileState {
|
|||||||
export const profileStore = defineStore({
|
export const profileStore = defineStore({
|
||||||
id: "profile",
|
id: "profile",
|
||||||
state: (): ProfileState => ({
|
state: (): ProfileState => ({
|
||||||
services: [{ value: "0", label: "All" }],
|
endpoints: [{ value: "", label: "All" }],
|
||||||
|
taskEndpoints: [{ value: "", label: "All" }],
|
||||||
durationTime: useAppStoreWithOut().durationTime,
|
durationTime: useAppStoreWithOut().durationTime,
|
||||||
condition: { serviceId: "", endpointName: "" },
|
condition: { serviceId: "", endpointName: "" },
|
||||||
taskList: [],
|
taskList: [],
|
||||||
@ -75,14 +77,28 @@ export const profileStore = defineStore({
|
|||||||
setHighlightTop() {
|
setHighlightTop() {
|
||||||
this.highlightTop = !this.highlightTop;
|
this.highlightTop = !this.highlightTop;
|
||||||
},
|
},
|
||||||
async getServices(layer: string) {
|
async getEndpoints(serviceId: string, keyword?: string) {
|
||||||
const res: AxiosResponse = await graphql.query("queryServices").params({
|
const res: AxiosResponse = await graphql.query("queryEndpoints").params({
|
||||||
layer,
|
serviceId,
|
||||||
|
duration: this.durationTime,
|
||||||
|
keyword: keyword || "",
|
||||||
});
|
});
|
||||||
if (res.data.errors) {
|
if (res.data.errors) {
|
||||||
return res.data;
|
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: this.durationTime,
|
||||||
|
keyword: keyword || "",
|
||||||
|
});
|
||||||
|
if (res.data.errors) {
|
||||||
|
return res.data;
|
||||||
|
}
|
||||||
|
this.taskEndpoints = [{ value: "", label: "All" }, ...res.data.data.pods];
|
||||||
return res.data;
|
return res.data;
|
||||||
},
|
},
|
||||||
async getTaskList() {
|
async getTaskList() {
|
||||||
|
@ -95,10 +95,7 @@ export const traceStore = defineStore({
|
|||||||
if (res.data.errors) {
|
if (res.data.errors) {
|
||||||
return res.data;
|
return res.data;
|
||||||
}
|
}
|
||||||
this.instances = [
|
this.instances = [{ value: "0", label: "All" }, ...res.data.data.pods];
|
||||||
{ value: "0", label: "All" },
|
|
||||||
...res.data.data.pods,
|
|
||||||
] || [{ value: " 0", label: "All" }];
|
|
||||||
return res.data;
|
return res.data;
|
||||||
},
|
},
|
||||||
async getEndpoints(id: string, keyword?: string) {
|
async getEndpoints(id: string, keyword?: string) {
|
||||||
@ -113,10 +110,7 @@ export const traceStore = defineStore({
|
|||||||
if (res.data.errors) {
|
if (res.data.errors) {
|
||||||
return res.data;
|
return res.data;
|
||||||
}
|
}
|
||||||
this.endpoints = [
|
this.endpoints = [{ value: "0", label: "All" }, ...res.data.data.pods];
|
||||||
{ value: "0", label: "All" },
|
|
||||||
...res.data.data.pods,
|
|
||||||
] || [{ value: "0", label: "All" }];
|
|
||||||
return res.data;
|
return res.data;
|
||||||
},
|
},
|
||||||
async getTraces() {
|
async getTraces() {
|
||||||
|
@ -14,6 +14,9 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
@import "./grid.scss";
|
import "element-plus/es/components/message/style/css";
|
||||||
@import "./lib.scss";
|
import "element-plus/es/components/message-box/style/css";
|
||||||
@import "./reset.scss";
|
import "element-plus/es/components/notification/style/css";
|
||||||
|
import "./grid.scss";
|
||||||
|
import "./lib.scss";
|
||||||
|
import "./reset.scss";
|
76
src/types/ebpf.d.ts
vendored
Normal file
76
src/types/ebpf.d.ts
vendored
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
layer: 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[];
|
||||||
|
};
|
||||||
|
export type AnalyzationTrees = {
|
||||||
|
id: string;
|
||||||
|
parentId: string;
|
||||||
|
symbol: string;
|
||||||
|
dumpCount: number;
|
||||||
|
stackType: string;
|
||||||
|
};
|
@ -44,7 +44,7 @@ limitations under the License. -->
|
|||||||
:style="{ fontSize: '13px', width: '100%' }"
|
:style="{ fontSize: '13px', width: '100%' }"
|
||||||
v-loading="loading"
|
v-loading="loading"
|
||||||
ref="multipleTableRef"
|
ref="multipleTableRef"
|
||||||
:default-sort="{ prop: 'name' }"
|
:default-sort="{ prop: 'name', order: 'ascending' }"
|
||||||
@selection-change="handleSelectionChange"
|
@selection-change="handleSelectionChange"
|
||||||
height="637px"
|
height="637px"
|
||||||
size="small"
|
size="small"
|
||||||
|
95
src/views/dashboard/controls/Ebpf.vue
Normal file
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>
|
@ -97,7 +97,7 @@ limitations under the License. -->
|
|||||||
:key="item.i"
|
:key="item.i"
|
||||||
@click="clickTabGrid($event, item)"
|
@click="clickTabGrid($event, item)"
|
||||||
:class="{ active: activeTabWidget === item.i }"
|
:class="{ active: activeTabWidget === item.i }"
|
||||||
drag-ignore-from="svg.d3-trace-tree, .dragger, .micro-topo-chart"
|
:drag-ignore-from="dragIgnoreFrom"
|
||||||
>
|
>
|
||||||
<component
|
<component
|
||||||
:is="item.type"
|
:is="item.type"
|
||||||
@ -122,6 +122,8 @@ import Trace from "./Trace.vue";
|
|||||||
import Profile from "./Profile.vue";
|
import Profile from "./Profile.vue";
|
||||||
import Log from "./Log.vue";
|
import Log from "./Log.vue";
|
||||||
import Text from "./Text.vue";
|
import Text from "./Text.vue";
|
||||||
|
import Ebpf from "./Ebpf.vue";
|
||||||
|
import { dragIgnoreFrom } from "../data";
|
||||||
|
|
||||||
const props = {
|
const props = {
|
||||||
data: {
|
data: {
|
||||||
@ -132,7 +134,7 @@ const props = {
|
|||||||
};
|
};
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: "Tab",
|
name: "Tab",
|
||||||
components: { Topology, Widget, Trace, Profile, Log, Text },
|
components: { Topology, Widget, Trace, Profile, Log, Text, Ebpf },
|
||||||
props,
|
props,
|
||||||
setup(props) {
|
setup(props) {
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
@ -248,6 +250,7 @@ export default defineComponent({
|
|||||||
canEditTabName,
|
canEditTabName,
|
||||||
showTools,
|
showTools,
|
||||||
t,
|
t,
|
||||||
|
dragIgnoreFrom,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -21,5 +21,6 @@ import Trace from "./Trace.vue";
|
|||||||
import Profile from "./Profile.vue";
|
import Profile from "./Profile.vue";
|
||||||
import Log from "./Log.vue";
|
import Log from "./Log.vue";
|
||||||
import Text from "./Text.vue";
|
import Text from "./Text.vue";
|
||||||
|
import Ebpf from "./Ebpf.vue";
|
||||||
|
|
||||||
export default { Tab, Widget, Trace, Topology, Profile, Log, Text };
|
export default { Tab, Widget, Trace, Topology, Profile, Log, Text, Ebpf };
|
||||||
|
@ -14,6 +14,8 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
export const dragIgnoreFrom =
|
||||||
|
"svg.d3-trace-tree, .dragger, .micro-topo-chart, .schedules";
|
||||||
|
|
||||||
export const PodsChartTypes = ["EndpointList", "InstanceList"];
|
export const PodsChartTypes = ["EndpointList", "InstanceList"];
|
||||||
|
|
||||||
@ -181,7 +183,8 @@ export const ServiceTools = [
|
|||||||
{ name: "library_books", content: "Text", id: "addText" },
|
{ name: "library_books", content: "Text", id: "addText" },
|
||||||
{ name: "device_hub", content: "Topology", id: "addTopology" },
|
{ name: "device_hub", content: "Topology", id: "addTopology" },
|
||||||
{ name: "merge", content: "Trace", id: "addTrace" },
|
{ 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: "assignment", content: "Log", id: "addLog" },
|
||||||
];
|
];
|
||||||
export const InstanceTools = [
|
export const InstanceTools = [
|
||||||
|
@ -31,7 +31,7 @@ limitations under the License. -->
|
|||||||
:key="item.i"
|
:key="item.i"
|
||||||
@click="clickGrid(item)"
|
@click="clickGrid(item)"
|
||||||
:class="{ active: dashboardStore.activedGridItem === item.i }"
|
: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" />
|
<component :is="item.type" :data="item" />
|
||||||
</grid-item>
|
</grid-item>
|
||||||
@ -45,6 +45,7 @@ import { useDashboardStore } from "@/store/modules/dashboard";
|
|||||||
import { useSelectorStore } from "@/store/modules/selectors";
|
import { useSelectorStore } from "@/store/modules/selectors";
|
||||||
import { LayoutConfig } from "@/types/dashboard";
|
import { LayoutConfig } from "@/types/dashboard";
|
||||||
import controls from "../controls/index";
|
import controls from "../controls/index";
|
||||||
|
import { dragIgnoreFrom } from "../data";
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: "Layout",
|
name: "Layout",
|
||||||
@ -72,6 +73,7 @@ export default defineComponent({
|
|||||||
dashboardStore,
|
dashboardStore,
|
||||||
clickGrid,
|
clickGrid,
|
||||||
t,
|
t,
|
||||||
|
dragIgnoreFrom,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -258,7 +258,7 @@ async function setSourceSelector() {
|
|||||||
let currentPod;
|
let currentPod;
|
||||||
if (states.currentPod) {
|
if (states.currentPod) {
|
||||||
currentPod = selectorStore.pods.find(
|
currentPod = selectorStore.pods.find(
|
||||||
(d: { id: string }) => d.label === states.currentPod
|
(d: { label: string }) => d.label === states.currentPod
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
currentPod = selectorStore.pods.find((d: { id: string }) => d.id === pod);
|
currentPod = selectorStore.pods.find((d: { id: string }) => d.id === pod);
|
||||||
@ -283,10 +283,10 @@ async function setDestSelector() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const destPod = params.destPodId || selectorStore.destPods[0].id;
|
const destPod = params.destPodId || selectorStore.destPods[0].id;
|
||||||
let currentDestPod = "";
|
let currentDestPod = { label: "" };
|
||||||
if (states.currentDestPod) {
|
if (states.currentDestPod) {
|
||||||
currentDestPod = selectorStore.pods.find(
|
currentDestPod = selectorStore.pods.find(
|
||||||
(d: { id: string }) => d.label === states.currentDestPod
|
(d: { label: string }) => d.label === states.currentDestPod
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
currentDestPod = selectorStore.destPods.find(
|
currentDestPod = selectorStore.destPods.find(
|
||||||
@ -317,19 +317,23 @@ async function getServices() {
|
|||||||
let s;
|
let s;
|
||||||
if (states.currentService) {
|
if (states.currentService) {
|
||||||
s = (selectorStore.services || []).find(
|
s = (selectorStore.services || []).find(
|
||||||
(d) => d.label === states.currentService
|
(d: { label: string }) => d.label === states.currentService
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
s = (selectorStore.services || []).find((d, index) => index === 0);
|
s = (selectorStore.services || []).find(
|
||||||
|
(d: unknown, index: number) => index === 0
|
||||||
|
);
|
||||||
}
|
}
|
||||||
selectorStore.setCurrentService(s || null);
|
selectorStore.setCurrentService(s || null);
|
||||||
let d;
|
let d;
|
||||||
if (states.currentService) {
|
if (states.currentService) {
|
||||||
d = (selectorStore.services || []).find(
|
d = (selectorStore.services || []).find(
|
||||||
(d) => d.label === states.currentDestService
|
(d: { label: string }) => d.label === states.currentDestService
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
d = (selectorStore.services || []).find((d, index) => index === 1);
|
d = (selectorStore.services || []).find(
|
||||||
|
(d: unknown, index: number) => index === 1
|
||||||
|
);
|
||||||
}
|
}
|
||||||
selectorStore.setCurrentDestService(d || null);
|
selectorStore.setCurrentDestService(d || null);
|
||||||
if (!selectorStore.currentService) {
|
if (!selectorStore.currentService) {
|
||||||
@ -431,6 +435,9 @@ function setTabControls(id: string) {
|
|||||||
case "addProfile":
|
case "addProfile":
|
||||||
dashboardStore.addTabControls("Profile");
|
dashboardStore.addTabControls("Profile");
|
||||||
break;
|
break;
|
||||||
|
case "addEbpf":
|
||||||
|
dashboardStore.addTabControls("Ebpf");
|
||||||
|
break;
|
||||||
case "addTopology":
|
case "addTopology":
|
||||||
dashboardStore.addTabControls("Topology");
|
dashboardStore.addTabControls("Topology");
|
||||||
break;
|
break;
|
||||||
@ -457,6 +464,9 @@ function setControls(id: string) {
|
|||||||
case "addProfile":
|
case "addProfile":
|
||||||
dashboardStore.addControl("Profile");
|
dashboardStore.addControl("Profile");
|
||||||
break;
|
break;
|
||||||
|
case "addEbpf":
|
||||||
|
dashboardStore.addControl("Ebpf");
|
||||||
|
break;
|
||||||
case "addLog":
|
case "addLog":
|
||||||
dashboardStore.addControl("Log");
|
dashboardStore.addControl("Log");
|
||||||
break;
|
break;
|
||||||
@ -484,9 +494,13 @@ async function fetchPods(
|
|||||||
if (setPod) {
|
if (setPod) {
|
||||||
let p;
|
let p;
|
||||||
if (states.currentPod) {
|
if (states.currentPod) {
|
||||||
p = selectorStore.pods.find((d) => d.label === states.currentPod);
|
p = selectorStore.pods.find(
|
||||||
|
(d: { label: unknown }) => d.label === states.currentPod
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
p = selectorStore.pods.find((d, index) => index === 0);
|
p = selectorStore.pods.find(
|
||||||
|
(d: unknown, index: number) => index === 0
|
||||||
|
);
|
||||||
}
|
}
|
||||||
selectorStore.setCurrentPod(p || null);
|
selectorStore.setCurrentPod(p || null);
|
||||||
states.currentPod = selectorStore.currentPod.label;
|
states.currentPod = selectorStore.currentPod.label;
|
||||||
@ -497,9 +511,13 @@ async function fetchPods(
|
|||||||
if (setPod) {
|
if (setPod) {
|
||||||
let p;
|
let p;
|
||||||
if (states.currentPod) {
|
if (states.currentPod) {
|
||||||
p = selectorStore.pods.find((d) => d.label === states.currentPod);
|
p = selectorStore.pods.find(
|
||||||
|
(d: { label: string }) => d.label === states.currentPod
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
p = selectorStore.pods.find((d, index) => index === 0);
|
p = selectorStore.pods.find(
|
||||||
|
(d: { label: string }, index: number) => index === 0
|
||||||
|
);
|
||||||
}
|
}
|
||||||
selectorStore.setCurrentPod(p || null);
|
selectorStore.setCurrentPod(p || null);
|
||||||
states.currentPod = selectorStore.currentPod.label;
|
states.currentPod = selectorStore.currentPod.label;
|
||||||
@ -514,9 +532,13 @@ async function fetchPods(
|
|||||||
if (setPod) {
|
if (setPod) {
|
||||||
let p;
|
let p;
|
||||||
if (states.currentDestPod) {
|
if (states.currentDestPod) {
|
||||||
p = selectorStore.pods.find((d) => d.label === states.currentDestPod);
|
p = selectorStore.pods.find(
|
||||||
|
(d: { label: string }) => d.label === states.currentDestPod
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
p = selectorStore.pods.find((d, index) => index === 0);
|
p = selectorStore.pods.find(
|
||||||
|
(d: { label: string }, index: number) => index === 0
|
||||||
|
);
|
||||||
}
|
}
|
||||||
selectorStore.setCurrentDestPod(p || null);
|
selectorStore.setCurrentDestPod(p || null);
|
||||||
states.currentDestPod = selectorStore.currentDestPod.label;
|
states.currentDestPod = selectorStore.currentDestPod.label;
|
||||||
@ -530,9 +552,13 @@ async function fetchPods(
|
|||||||
if (setPod) {
|
if (setPod) {
|
||||||
let p;
|
let p;
|
||||||
if (states.currentDestPod) {
|
if (states.currentDestPod) {
|
||||||
p = selectorStore.pods.find((d) => d.label === states.currentDestPod);
|
p = selectorStore.pods.find(
|
||||||
|
(d: { label: string }) => d.label === states.currentDestPod
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
p = selectorStore.pods.find((d, index) => index === 0);
|
p = selectorStore.pods.find(
|
||||||
|
(d: { label: string }, index: number) => index === 0
|
||||||
|
);
|
||||||
}
|
}
|
||||||
selectorStore.setCurrentDestPod(p || null);
|
selectorStore.setCurrentDestPod(p || null);
|
||||||
states.currentDestPod = selectorStore.currentDestPod.label;
|
states.currentDestPod = selectorStore.currentDestPod.label;
|
||||||
|
50
src/views/dashboard/related/ebpf/Content.vue
Normal file
50
src/views/dashboard/related/ebpf/Content.vue
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
<!-- Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
contributor license agreements. See the NOTICE file distributed with
|
||||||
|
this work for additional information regarding copyright ownership.
|
||||||
|
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
(the "License"); you may not use this file except in compliance with
|
||||||
|
the License. You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License. -->
|
||||||
|
<template>
|
||||||
|
<div class="flex-h content">
|
||||||
|
<TaskList />
|
||||||
|
<div class="vis-graph ml-5">
|
||||||
|
<div class="item">
|
||||||
|
<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%;
|
||||||
|
width: calc(100% - 300px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.item {
|
||||||
|
width: 100%;
|
||||||
|
overflow: auto;
|
||||||
|
height: calc(50% - 10px);
|
||||||
|
padding-bottom: 10px;
|
||||||
|
}
|
||||||
|
</style>
|
104
src/views/dashboard/related/ebpf/Header.vue
Normal file
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>
|
244
src/views/dashboard/related/ebpf/components/EBPFSchedules.vue
Normal file
244
src/views/dashboard/related/ebpf/components/EBPFSchedules.vue
Normal file
@ -0,0 +1,244 @@
|
|||||||
|
<!-- 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">
|
||||||
|
<Selector
|
||||||
|
:value="selectedLabels"
|
||||||
|
:options="labels"
|
||||||
|
size="small"
|
||||||
|
placeholder="Please select labels"
|
||||||
|
@change="changeLabels"
|
||||||
|
class="inputs mr-10"
|
||||||
|
:multiple="true"
|
||||||
|
/>
|
||||||
|
<el-popover placement="bottom" :width="680" trigger="click">
|
||||||
|
<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"
|
||||||
|
>
|
||||||
|
<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 ref="timeline" class="schedules"></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 } from "./data";
|
||||||
|
import { useEbpfStore } from "@/store/modules/ebpf";
|
||||||
|
import { EBPFProfilingSchedule, Process } from "@/types/ebpf";
|
||||||
|
import { DataSet, Timeline } from "vis-timeline/standalone";
|
||||||
|
import "vis-timeline/styles/vis-timeline-graph2d.css";
|
||||||
|
import { ElMessage, ElTable } from "element-plus";
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
const ebpfStore = useEbpfStore();
|
||||||
|
const pageSize = 5;
|
||||||
|
/*global Nullable */
|
||||||
|
const multipleTableRef = ref<InstanceType<typeof ElTable>>();
|
||||||
|
const selectedProcesses = ref<string[]>([]);
|
||||||
|
const timeline = ref<Nullable<HTMLDivElement>>(null);
|
||||||
|
const visGraph = ref<Nullable<any>>(null);
|
||||||
|
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 dateFormat = (date: number, pattern = "YYYY-MM-DD HH:mm:ss") =>
|
||||||
|
new Date(dayjs(date).format(pattern));
|
||||||
|
|
||||||
|
function changeLabels(opt: any[]) {
|
||||||
|
const arr = opt.map((d) => d.value);
|
||||||
|
selectedLabels.value = arr;
|
||||||
|
}
|
||||||
|
|
||||||
|
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,
|
||||||
|
});
|
||||||
|
if (res.data.errors) {
|
||||||
|
ElMessage.error(res.data.errors);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function visTimeline() {
|
||||||
|
if (visGraph.value) {
|
||||||
|
visGraph.value.destroy();
|
||||||
|
}
|
||||||
|
labels.value = [{ label: "All", value: "0" }];
|
||||||
|
selectedLabels.value = ["0"];
|
||||||
|
processes.value = [];
|
||||||
|
const schedules = ebpfStore.eBPFSchedules.map(
|
||||||
|
(d: EBPFProfilingSchedule, index: number) => {
|
||||||
|
for (const l of d.process.labels) {
|
||||||
|
labels.value.push({ label: l, value: l });
|
||||||
|
}
|
||||||
|
processes.value.push(d.process);
|
||||||
|
return {
|
||||||
|
id: index + 1,
|
||||||
|
content: d.process.name,
|
||||||
|
start: dateFormat(d.startTime),
|
||||||
|
end: dateFormat(d.endTime),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
searchProcesses();
|
||||||
|
if (!timeline.value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const h = timeline.value.getBoundingClientRect().height;
|
||||||
|
const items: any = new DataSet(schedules);
|
||||||
|
const options = {
|
||||||
|
height: h,
|
||||||
|
width: "100%",
|
||||||
|
locale: "en",
|
||||||
|
};
|
||||||
|
visGraph.value = new Timeline(timeline.value, items, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
function changePage(pageIndex: number) {
|
||||||
|
searchProcesses(pageIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
function searchProcesses(pageIndex?: any) {
|
||||||
|
const arr = processes.value.filter(
|
||||||
|
(d: { name: string; instanceName: string }) =>
|
||||||
|
d.name.includes(searchText.value) ||
|
||||||
|
d.instanceName.includes(searchText.value)
|
||||||
|
);
|
||||||
|
currentProcesses.value = arr.splice(
|
||||||
|
(pageIndex - 1 || 0) * pageSize,
|
||||||
|
pageSize * (pageIndex || 1)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => ebpfStore.eBPFSchedules,
|
||||||
|
() => {
|
||||||
|
visTimeline();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.filters {
|
||||||
|
margin: 5px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.schedules {
|
||||||
|
width: calc(100% - 5px);
|
||||||
|
margin: 0 5px 5px 0;
|
||||||
|
height: calc(100% - 60px);
|
||||||
|
min-height: 150px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.inputs {
|
||||||
|
width: 300px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-with-search {
|
||||||
|
width: 650px;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination {
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
</style>
|
148
src/views/dashboard/related/ebpf/components/EBPFStack.vue
Normal file
148
src/views/dashboard/related/ebpf/components/EBPFStack.vue
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
<!-- 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 "d3-flame-graph/dist/d3-flamegraph.css";
|
||||||
|
|
||||||
|
/*global Nullable*/
|
||||||
|
const ebpfStore = useEbpfStore();
|
||||||
|
const stackTree = ref<Nullable<StackElement>>(null);
|
||||||
|
const graph = ref<Nullable<HTMLDivElement>>(null);
|
||||||
|
const flameChart = ref<any>(null);
|
||||||
|
|
||||||
|
function drawGraph() {
|
||||||
|
if (flameChart.value) {
|
||||||
|
flameChart.value.destroy();
|
||||||
|
}
|
||||||
|
if (!ebpfStore.analyzeTrees.length) {
|
||||||
|
return (stackTree.value = null);
|
||||||
|
}
|
||||||
|
stackTree.value = processTree(ebpfStore.analyzeTrees);
|
||||||
|
|
||||||
|
const w = (graph.value && graph.value.getBoundingClientRect().width) || 10;
|
||||||
|
flameChart.value = flamegraph()
|
||||||
|
.width(w - 15)
|
||||||
|
.cellHeight(18)
|
||||||
|
.transitionDuration(750)
|
||||||
|
.minFrameSize(5)
|
||||||
|
.transitionEase(d3.easeCubic as any)
|
||||||
|
.sort(true)
|
||||||
|
.title("")
|
||||||
|
.selfValue(false)
|
||||||
|
.setColorMapper((d, originalColor) =>
|
||||||
|
d.highlight ? "#6aff8f" : originalColor
|
||||||
|
);
|
||||||
|
const tip = (d3tip as any)()
|
||||||
|
.attr("class", "d3-tip")
|
||||||
|
.direction("w")
|
||||||
|
.html(
|
||||||
|
(d: { data: StackElement }) =>
|
||||||
|
`<div class="mb-5">Symbol: ${d.data.name}</div><div class="mb-5">Dump Count: ${d.data.dumpCount}</div>`
|
||||||
|
);
|
||||||
|
flameChart.value.tooltip(tip);
|
||||||
|
d3.select("#graph-stack").datum(stackTree.value).call(flameChart.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
function processTree(arr: StackElement[]) {
|
||||||
|
const copyArr = JSON.parse(JSON.stringify(arr));
|
||||||
|
const obj: any = {};
|
||||||
|
let res = null;
|
||||||
|
let min = 1;
|
||||||
|
let max = 1;
|
||||||
|
for (const item of copyArr) {
|
||||||
|
item.originId = item.id;
|
||||||
|
item.name = item.symbol;
|
||||||
|
delete item.id;
|
||||||
|
obj[item.originId] = item;
|
||||||
|
if (item.dumpCount > max) {
|
||||||
|
max = item.dumpCount;
|
||||||
|
}
|
||||||
|
if (item.dumpCount < min) {
|
||||||
|
min = item.dumpCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const scale = d3.scaleLinear().domain([min, max]).range([1, 200]);
|
||||||
|
for (const item of copyArr) {
|
||||||
|
if (item.parentId === "0") {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
</style>
|
165
src/views/dashboard/related/ebpf/components/NewTask.vue
Normal file
165
src/views/dashboard/related/ebpf/components/NewTask.vue
Normal file
@ -0,0 +1,165 @@
|
|||||||
|
<!-- 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);
|
||||||
|
|
||||||
|
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 (!labels.value.length) {
|
||||||
|
ElMessage.warning("no labels");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
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: "ON_CPU",
|
||||||
|
};
|
||||||
|
const res = await eBPFStore.createTask(params);
|
||||||
|
if (res.errors) {
|
||||||
|
ElMessage.error(res.errors);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
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>
|
195
src/views/dashboard/related/ebpf/components/TaskList.vue
Normal file
195
src/views/dashboard/related/ebpf/components/TaskList.vue
Normal file
@ -0,0 +1,195 @@
|
|||||||
|
<!-- 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.processLabels.join(" ") }}</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 }}</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;
|
||||||
|
const res = await ebpfStore.getEBPFSchedules({
|
||||||
|
taskId: item.taskId,
|
||||||
|
});
|
||||||
|
if (res.errors) {
|
||||||
|
ElMessage.error(res.errors);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
watch(
|
||||||
|
() => ebpfStore.taskList,
|
||||||
|
() => {
|
||||||
|
selectedTask.value = ebpfStore.taskList[0] || {};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
</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>
|
51
src/views/dashboard/related/ebpf/components/data.ts
Normal file
51
src/views/dashboard/related/ebpf/components/data.ts
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
/**
|
||||||
|
* 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 ProfileMode: any[] = [
|
||||||
|
{ label: "Include Children", value: "include" },
|
||||||
|
{ label: "Exclude Children", value: "exclude" },
|
||||||
|
];
|
||||||
|
export const NewTaskField = {
|
||||||
|
service: { key: "", label: "None" },
|
||||||
|
monitorTime: { key: "0", label: "monitor now" },
|
||||||
|
monitorDuration: { key: 5, label: "5 min" },
|
||||||
|
minThreshold: 0,
|
||||||
|
dumpPeriod: { key: 10, label: "10ms" },
|
||||||
|
endpointName: "",
|
||||||
|
maxSamplingCount: { key: 5, label: "5" },
|
||||||
|
};
|
||||||
|
|
||||||
|
export const TargetTypes = [{ label: "ON_CPU", value: "ON_CPU" }];
|
||||||
|
|
||||||
|
export const InitTaskField = {
|
||||||
|
monitorTimeEn: [
|
||||||
|
{ value: "0", label: "monitor now" },
|
||||||
|
{ value: "1", label: "set start time" },
|
||||||
|
],
|
||||||
|
monitorTimeCn: [
|
||||||
|
{ value: "0", label: "此刻" },
|
||||||
|
{ value: "1", label: "设置时间" },
|
||||||
|
],
|
||||||
|
monitorDuration: [
|
||||||
|
{ value: "5", label: "5 min" },
|
||||||
|
{ value: "10", label: "10 min" },
|
||||||
|
{ value: "15", label: "15 min" },
|
||||||
|
],
|
||||||
|
};
|
||||||
|
export const TableHeader = [
|
||||||
|
{ property: "name", label: "Name" },
|
||||||
|
{ property: "instanceName", label: "Instance Name" },
|
||||||
|
];
|
@ -14,19 +14,18 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License. -->
|
limitations under the License. -->
|
||||||
<template>
|
<template>
|
||||||
<div class="flex-h header">
|
<div class="flex-h header">
|
||||||
<!-- <div class="mr-10" v-if="dashboardStore.entity==='All'">
|
|
||||||
<span class="grey mr-5">{{ t("service") }}:</span>
|
|
||||||
<Selector
|
|
||||||
size="small"
|
|
||||||
:value="service.value"
|
|
||||||
:options="profileStore.services"
|
|
||||||
placeholder="Select a service"
|
|
||||||
@change="changeService"
|
|
||||||
/>
|
|
||||||
</div> -->
|
|
||||||
<div class="mr-10">
|
<div class="mr-10">
|
||||||
<span class="grey mr-5">{{ t("endpointName") }}:</span>
|
<span class="grey mr-5">{{ t("endpointName") }}:</span>
|
||||||
<el-input v-model="endpointName" class="name" size="small" />
|
<Selector
|
||||||
|
class="name"
|
||||||
|
size="small"
|
||||||
|
:value="endpointName"
|
||||||
|
:options="profileStore.endpoints"
|
||||||
|
placeholder="Select a endpoint"
|
||||||
|
:isRemote="true"
|
||||||
|
@change="changeEndpoint"
|
||||||
|
@query="searchEndpoints"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<el-button
|
<el-button
|
||||||
class="search-btn"
|
class="search-btn"
|
||||||
@ -65,27 +64,30 @@ const appStore = useAppStoreWithOut();
|
|||||||
const selectorStore = useSelectorStore();
|
const selectorStore = useSelectorStore();
|
||||||
const dashboardStore = useDashboardStore();
|
const dashboardStore = useDashboardStore();
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
// const service = ref<any>({});
|
|
||||||
const endpointName = ref<string>("");
|
const endpointName = ref<string>("");
|
||||||
const newTask = ref<boolean>(false);
|
const newTask = ref<boolean>(false);
|
||||||
|
|
||||||
searchTasks();
|
searchTasks();
|
||||||
// getServices();
|
searchEndpoints("");
|
||||||
|
|
||||||
// async function getServices() {
|
async function searchEndpoints(keyword: string) {
|
||||||
// const res = await profileStore.getServices(dashboardStore.layerId);
|
if (!selectorStore.currentService) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const service = selectorStore.currentService.id;
|
||||||
|
const res = await profileStore.getEndpoints(service, keyword);
|
||||||
|
|
||||||
// if (res.errors) {
|
if (res.errors) {
|
||||||
// ElMessage.error(res.errors);
|
ElMessage.error(res.errors);
|
||||||
// return;
|
return;
|
||||||
// }
|
}
|
||||||
// service.value = profileStore.services[0];
|
endpointName.value = profileStore.endpoints[0].value;
|
||||||
// searchTasks();
|
}
|
||||||
// }
|
|
||||||
|
function changeEndpoint(opt: any[]) {
|
||||||
|
endpointName.value = opt[0].value;
|
||||||
|
}
|
||||||
|
|
||||||
// function changeService(opt: any[]) {
|
|
||||||
// service.value = opt[0];
|
|
||||||
// }
|
|
||||||
async function searchTasks() {
|
async function searchTasks() {
|
||||||
profileStore.setConditions({
|
profileStore.setConditions({
|
||||||
serviceId:
|
serviceId:
|
||||||
|
@ -17,7 +17,16 @@ limitations under the License. -->
|
|||||||
<div class="profile-task">
|
<div class="profile-task">
|
||||||
<div>
|
<div>
|
||||||
<div class="label">{{ t("endpointName") }}</div>
|
<div class="label">{{ t("endpointName") }}</div>
|
||||||
<el-input v-model="endpointName" class="profile-input" size="small" />
|
<Selector
|
||||||
|
class="profile-input"
|
||||||
|
size="small"
|
||||||
|
:value="endpointName"
|
||||||
|
:options="profileStore.endpoints"
|
||||||
|
placeholder="Select a endpoint"
|
||||||
|
:isRemote="true"
|
||||||
|
@change="changeEndpoint"
|
||||||
|
@query="searchEndpoints"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div class="label">{{ t("monitorTime") }}</div>
|
<div class="label">{{ t("monitorTime") }}</div>
|
||||||
@ -105,6 +114,20 @@ const minThreshold = ref<number>(0);
|
|||||||
const dumpPeriod = ref<string>(InitTaskField.dumpPeriod[0].value);
|
const dumpPeriod = ref<string>(InitTaskField.dumpPeriod[0].value);
|
||||||
const maxSamplingCount = ref<string>(InitTaskField.maxSamplingCount[0].value);
|
const maxSamplingCount = ref<string>(InitTaskField.maxSamplingCount[0].value);
|
||||||
|
|
||||||
|
async function searchEndpoints(keyword: string) {
|
||||||
|
if (!selectorStore.currentService) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const service = selectorStore.currentService.id;
|
||||||
|
const res = await profileStore.getEndpoints(service, keyword);
|
||||||
|
|
||||||
|
if (res.errors) {
|
||||||
|
ElMessage.error(res.errors);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
endpointName.value = profileStore.taskEndpoints[0].value;
|
||||||
|
}
|
||||||
|
|
||||||
function changeMonitorTime(opt: string) {
|
function changeMonitorTime(opt: string) {
|
||||||
monitorTime.value = opt;
|
monitorTime.value = opt;
|
||||||
}
|
}
|
||||||
@ -121,10 +144,13 @@ function changeMaxSamplingCount(opt: any[]) {
|
|||||||
maxSamplingCount.value = opt[0].value;
|
maxSamplingCount.value = opt[0].value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function changeEndpoint(opt: any[]) {
|
||||||
|
endpointName.value = opt[0].value;
|
||||||
|
}
|
||||||
|
|
||||||
async function createTask() {
|
async function createTask() {
|
||||||
emits("close");
|
emits("close");
|
||||||
const date =
|
const date = monitorTime.value === "0" ? new Date() : time.value;
|
||||||
monitorTime.value === "0" ? appStore.durationRow.start : time.value;
|
|
||||||
const params = {
|
const params = {
|
||||||
serviceId: selectorStore.currentService.id,
|
serviceId: selectorStore.currentService.id,
|
||||||
endpointName: endpointName.value,
|
endpointName: endpointName.value,
|
||||||
@ -153,7 +179,7 @@ function changeTimeRange(val: Date) {
|
|||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.profile-task {
|
.profile-task {
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
width: 350px;
|
width: 400px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.date {
|
.date {
|
||||||
|
@ -36,7 +36,7 @@ limitations under the License. -->
|
|||||||
<div class="ell">
|
<div class="ell">
|
||||||
<span>{{ i.endpointName }}</span>
|
<span>{{ i.endpointName }}</span>
|
||||||
<a class="profile-btn r" @click="viewTask($event, i)">
|
<a class="profile-btn r" @click="viewTask($event, i)">
|
||||||
<Icon iconName="library_books" size="middle" />
|
<Icon iconName="view" size="middle" />
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="grey ell sm">
|
<div class="grey ell sm">
|
||||||
|
@ -88,7 +88,7 @@ limitations under the License. -->
|
|||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<el-button
|
<el-button
|
||||||
class="grey"
|
class="grey small"
|
||||||
:class="{ ghost: displayMode !== 'List' }"
|
:class="{ ghost: displayMode !== 'List' }"
|
||||||
@click="displayMode = 'List'"
|
@click="displayMode = 'List'"
|
||||||
>
|
>
|
||||||
@ -96,7 +96,7 @@ limitations under the License. -->
|
|||||||
{{ t("list") }}
|
{{ t("list") }}
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button
|
<el-button
|
||||||
class="grey"
|
class="grey small"
|
||||||
:class="{ ghost: displayMode !== 'Tree' }"
|
:class="{ ghost: displayMode !== 'Tree' }"
|
||||||
@click="displayMode = 'Tree'"
|
@click="displayMode = 'Tree'"
|
||||||
>
|
>
|
||||||
@ -104,7 +104,7 @@ limitations under the License. -->
|
|||||||
{{ t("tree") }}
|
{{ t("tree") }}
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button
|
<el-button
|
||||||
class="grey"
|
class="grey small"
|
||||||
:class="{ ghost: displayMode !== 'Table' }"
|
:class="{ ghost: displayMode !== 'Table' }"
|
||||||
@click="displayMode = 'Table'"
|
@click="displayMode = 'Table'"
|
||||||
>
|
>
|
||||||
@ -112,7 +112,7 @@ limitations under the License. -->
|
|||||||
{{ t("table") }}
|
{{ t("table") }}
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button
|
<el-button
|
||||||
class="grey"
|
class="grey small"
|
||||||
:class="{ ghost: displayMode !== 'Statistics' }"
|
:class="{ ghost: displayMode !== 'Statistics' }"
|
||||||
@click="displayMode = 'Statistics'"
|
@click="displayMode = 'Statistics'"
|
||||||
>
|
>
|
||||||
|
Loading…
Reference in New Issue
Block a user