Compare commits
88 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
1f98619a5b | ||
![]() |
aab44626da | ||
![]() |
0ff5d4d6bb | ||
![]() |
611731d6d0 | ||
![]() |
221751f034 | ||
![]() |
d4dde7e73b | ||
![]() |
5be106fc4f | ||
![]() |
d8f91bbdf3 | ||
![]() |
23e9742946 | ||
![]() |
7a1c83b5fb | ||
![]() |
7d802d490e | ||
![]() |
da1db8def6 | ||
![]() |
2230d05508 | ||
![]() |
e8d909792d | ||
![]() |
dc842609ba | ||
![]() |
670bef1d69 | ||
![]() |
882828b04a | ||
![]() |
ed6fb0448b | ||
![]() |
a0fc879eb1 | ||
![]() |
b37d65eaac | ||
![]() |
fd46211a37 | ||
![]() |
ae0b8c056d | ||
![]() |
4b88d8bbb3 | ||
![]() |
09051e916b | ||
![]() |
e597f91448 | ||
![]() |
4232161d36 | ||
![]() |
eda44db0cd | ||
![]() |
78f0096c00 | ||
![]() |
5e161f17c2 | ||
![]() |
77d189cdfb | ||
![]() |
9f57e35119 | ||
![]() |
2bf90d6a6d | ||
![]() |
0f4319499a | ||
![]() |
5bb58a00cd | ||
![]() |
d50e9fc261 | ||
![]() |
b235929c77 | ||
![]() |
4561e2e374 | ||
![]() |
214b34ddfd | ||
![]() |
26817e9f92 | ||
![]() |
9ed0121fd0 | ||
![]() |
0d63d538c3 | ||
![]() |
5da441ff9a | ||
![]() |
49bc349064 | ||
![]() |
61a4d2f759 | ||
![]() |
0b4e738699 | ||
![]() |
b88356ba46 | ||
![]() |
d8889f1787 | ||
![]() |
1a989a1434 | ||
![]() |
82b348a766 | ||
![]() |
42b20660e4 | ||
![]() |
cb3aa940b3 | ||
![]() |
87a5553e6d | ||
![]() |
e17562a766 | ||
![]() |
fdfdaab47b | ||
![]() |
a4fc5192ac | ||
![]() |
ffabc7c7a7 | ||
![]() |
2fd5fb9b1e | ||
![]() |
adb457d660 | ||
![]() |
9c0bb988e6 | ||
![]() |
973b51e9ca | ||
![]() |
f5bcd5da2e | ||
![]() |
732b834749 | ||
![]() |
4b43196bc2 | ||
![]() |
b01565b2b8 | ||
![]() |
3b3e790dd9 | ||
![]() |
dc8e4bf273 | ||
![]() |
2ba3c67d31 | ||
![]() |
673b1a41a8 | ||
![]() |
c7079ea17c | ||
![]() |
017f5bf709 | ||
![]() |
bec86e80fd | ||
![]() |
ec7a8bbfa9 | ||
![]() |
4e022ff29a | ||
![]() |
42ead4a572 | ||
![]() |
e144b43267 | ||
![]() |
b5c07e023b | ||
![]() |
04d109d0e3 | ||
![]() |
024cd1195d | ||
![]() |
7fbd6170de | ||
![]() |
3ff3d5d1cd | ||
![]() |
2230702d97 | ||
![]() |
9ad9362935 | ||
![]() |
2be0a84d48 | ||
![]() |
4c762a2458 | ||
![]() |
7813c92673 | ||
![]() |
f12d7899e4 | ||
![]() |
b697fe4713 | ||
![]() |
0828f8a7aa |
4
.github/workflows/nodejs.yml
vendored
@@ -44,9 +44,9 @@ jobs:
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
- name: npm install, lint, build, and test
|
||||
- name: npm ci, lint, build, and test
|
||||
run: |
|
||||
npm install
|
||||
npm ci
|
||||
npm run lint
|
||||
npm run build --if-present
|
||||
npm run test:unit
|
||||
|
1577
package-lock.json
generated
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "skywalking-booster-ui",
|
||||
"version": "9.1.0",
|
||||
"version": "9.3.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"serve": "vue-cli-service serve",
|
||||
@@ -19,12 +19,12 @@
|
||||
"lodash": "^4.17.21",
|
||||
"monaco-editor": "^0.27.0",
|
||||
"pinia": "^2.0.5",
|
||||
"vis-timeline": "^7.5.1",
|
||||
"vue": "^3.0.0",
|
||||
"vue-grid-layout": "^3.0.0-beta1",
|
||||
"vue-i18n": "^9.1.9",
|
||||
"vue-router": "^4.0.0-0",
|
||||
"vue-types": "^4.1.1",
|
||||
"vuex": "^4.0.0-0"
|
||||
"vue-types": "^4.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/d3": "^7.1.0",
|
||||
@@ -36,7 +36,7 @@
|
||||
"@typescript-eslint/eslint-plugin": "^4.18.0",
|
||||
"@typescript-eslint/parser": "^4.18.0",
|
||||
"@vue/cli-plugin-babel": "~4.5.0",
|
||||
"@vue/cli-plugin-e2e-cypress": "~4.5.0",
|
||||
"@vue/cli-plugin-e2e-cypress": "~5.0.8",
|
||||
"@vue/cli-plugin-eslint": "~4.5.0",
|
||||
"@vue/cli-plugin-router": "~4.5.0",
|
||||
"@vue/cli-plugin-typescript": "~4.5.0",
|
||||
|
@@ -19,7 +19,7 @@ limitations under the License. -->
|
||||
#app {
|
||||
color: #2c3e50;
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
overflow: hidden;
|
||||
min-width: 1024px;
|
||||
}
|
||||
</style>
|
||||
|
15
src/assets/icons/add_fill.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="1655799536378" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="9286" width="48" height="48"><path d="M563.2 614.4v51.2c0 30.72-20.48 51.2-51.2 51.2s-51.2-20.48-51.2-51.2v-51.2H409.6c-30.72 0-51.2-20.48-51.2-51.2s20.48-51.2 51.2-51.2h51.2V460.8c0-30.72 20.48-51.2 51.2-51.2s51.2 20.48 51.2 51.2v51.2h51.2c30.72 0 51.2 20.48 51.2 51.2s-20.48 51.2-51.2 51.2h-51.2z m51.2-563.2c158.72 15.36 281.6 143.36 281.6 307.2v512c0 56.32-46.08 102.4-102.4 102.4h-563.2c-56.32 0-102.4-46.08-102.4-102.4V153.6c0-56.32 46.08-102.4 102.4-102.4H614.4z m163.84 230.4c-25.6-61.44-76.8-107.52-138.24-122.88v71.68c0 30.72 20.48 51.2 51.2 51.2h87.04zM537.6 153.6h-256c-30.72 0-51.2 20.48-51.2 51.2v614.4c0 30.72 20.48 51.2 51.2 51.2h460.8c30.72 0 51.2-20.48 51.2-51.2V384h-153.6c-56.32 0-102.4-46.08-102.4-102.4V153.6z" fill="#707070" p-id="9287"></path></svg>
|
After Width: | Height: | Size: 1.6 KiB |
15
src/assets/icons/circle.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="1667899293763" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4705" width="16" height="16"><path d="M512 512m-368 0a368 368 0 1 0 736 0 368 368 0 1 0-736 0Z" p-id="4706"></path></svg>
|
After Width: | Height: | Size: 1001 B |
16
src/assets/icons/conditions.svg
Normal file
@@ -0,0 +1,16 @@
|
||||
<!-- Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License. -->
|
||||
|
||||
<svg t="1666624449554" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2649" width="48" height="48"><path d="M381.482667 673.877333a90.389333 90.389333 0 0 1 85.226666 60.245334H853.333333v64H465.28a90.389333 90.389333 0 0 1-167.573333 0H170.666667v-64h125.610666a90.389333 90.389333 0 0 1 85.205334-60.245334z m0 64a26.346667 26.346667 0 1 0 0 52.693334 26.346667 26.346667 0 0 0 0-52.693334z m261.034666-304.938666a90.389333 90.389333 0 0 1 85.205334 60.245333H853.333333v64h-127.04a90.389333 90.389333 0 0 1-167.573333 0H170.666667v-64h386.624a90.389333 90.389333 0 0 1 85.226666-60.245333z m0 64a26.346667 26.346667 0 1 0 0 52.693333 26.346667 26.346667 0 0 0 0-52.693333zM381.482667 192a90.389333 90.389333 0 0 1 85.226666 60.224H853.333333v64H465.28a90.389333 90.389333 0 0 1-167.573333 0H170.666667v-64h125.610666A90.389333 90.389333 0 0 1 381.482667 192z m0 64a26.346667 26.346667 0 1 0 0 52.693333 26.346667 26.346667 0 0 0 0-52.693333z" p-id="2650"></path></svg>
|
After Width: | Height: | Size: 1.7 KiB |
@@ -12,4 +12,4 @@ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License. -->
|
||||
<svg t="1648717513168" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="15451" width="48" height="48"><path d="M810.666667 213.333333v597.333334H213.333333V213.333333h597.333334m85.333333-85.333333H128v768h768V128z m-512 170.666667h-85.333333v85.333333h85.333333z m170.666667 0h-85.333334v85.333333h85.333334z m-170.666667 170.666666h-85.333333v85.333334h85.333333z m170.666667 0h-85.333334v85.333334h85.333334z m-170.666667 170.666667h-85.333333v85.333333h85.333333z m170.666667 0h-85.333334v85.333333h85.333334z m170.666666-341.333333h-85.333333v85.333333h85.333333z m0 170.666666h-85.333333v85.333334h85.333333z m0 170.666667h-85.333333v85.333333h85.333333z" p-id="15452" fill="#515151"></path></svg>
|
||||
<svg t="1648717513168" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="15451" width="48" height="48"><path d="M810.666667 213.333333v597.333334H213.333333V213.333333h597.333334m85.333333-85.333333H128v768h768V128z m-512 170.666667h-85.333333v85.333333h85.333333z m170.666667 0h-85.333334v85.333333h85.333334z m-170.666667 170.666666h-85.333333v85.333334h85.333333z m170.666667 0h-85.333334v85.333334h85.333334z m-170.666667 170.666667h-85.333333v85.333333h85.333333z m170.666667 0h-85.333334v85.333333h85.333334z m170.666666-341.333333h-85.333333v85.333333h85.333333z m0 170.666666h-85.333333v85.333334h85.333333z m0 170.666667h-85.333333v85.333333h85.333333z" p-id="15452"></path></svg>
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
15
src/assets/icons/copy.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="1664265269855" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4109" width="48" height="48"><path d="M866.461538 39.384615H354.461538c-43.323077 0-78.769231 35.446154-78.76923 78.769231v39.384616h472.615384c43.323077 0 78.769231 35.446154 78.769231 78.76923v551.384616h39.384615c43.323077 0 78.769231-35.446154 78.769231-78.769231V118.153846c0-43.323077-35.446154-78.769231-78.769231-78.769231z m-118.153846 275.692308c0-43.323077-35.446154-78.769231-78.76923-78.769231H157.538462c-43.323077 0-78.769231 35.446154-78.769231 78.769231v590.769231c0 43.323077 35.446154 78.769231 78.769231 78.769231h512c43.323077 0 78.769231-35.446154 78.76923-78.769231V315.076923z m-354.461538 137.846154c0 11.815385-7.876923 19.692308-19.692308 19.692308h-157.538461c-11.815385 0-19.692308-7.876923-19.692308-19.692308v-39.384615c0-11.815385 7.876923-19.692308 19.692308-19.692308h157.538461c11.815385 0 19.692308 7.876923 19.692308 19.692308v39.384615z m157.538461 315.076923c0 11.815385-7.876923 19.692308-19.692307 19.692308H216.615385c-11.815385 0-19.692308-7.876923-19.692308-19.692308v-39.384615c0-11.815385 7.876923-19.692308 19.692308-19.692308h315.076923c11.815385 0 19.692308 7.876923 19.692307 19.692308v39.384615z m78.769231-157.538462c0 11.815385-7.876923 19.692308-19.692308 19.692308H216.615385c-11.815385 0-19.692308-7.876923-19.692308-19.692308v-39.384615c0-11.815385 7.876923-19.692308 19.692308-19.692308h393.846153c11.815385 0 19.692308 7.876923 19.692308 19.692308v39.384615z" p-id="4110"></path></svg>
|
After Width: | Height: | Size: 2.3 KiB |
15
src/assets/icons/event.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="1655695739627" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2218" width="48" height="48"><path d="M173.292308 177.230769C86.646154 265.846154 39.384615 382.030769 39.384615 504.123077 39.384615 531.692308 61.046154 551.384615 86.646154 551.384615s47.261538-21.661538 47.261538-47.261538c-1.969231-96.492308 37.415385-189.046154 106.338462-257.969231s163.446154-106.338462 257.969231-106.338461c27.569231 0 47.261538-21.661538 47.261538-47.261539 0-27.569231-21.661538-47.261538-47.261538-47.261538C378.092308 43.323077 259.938462 90.584615 173.292308 177.230769z m57.107692 326.892308c0 27.569231 19.692308 47.261538 47.261538 47.261538s47.261538-21.661538 47.261539-47.261538c0-45.292308 17.723077-90.584615 51.2-122.092308 33.476923-33.476923 76.8-49.230769 122.092308-51.2 27.569231 0 47.261538-21.661538 47.261538-47.261538 0-27.569231-19.692308-47.261538-47.261538-47.261539-70.892308 0-139.815385 27.569231-191.015385 76.8-7.876923 9.846154-80.738462 82.707692-76.8 191.015385z m665.6-204.8c-17.723077-23.630769-41.353846-51.2-45.292308-55.138462-5.907692-3.938462-13.784615-7.876923-21.661538-7.876923-7.876923 0-15.753846 1.969231-19.692308 7.876923L610.461538 441.107692c-47.261538-39.384615-118.153846-37.415385-163.446153 7.876923-45.292308 45.292308-47.261538 116.184615-7.876923 163.446154l-191.015385 191.015385c-5.907692 5.907692-9.846154 13.784615-9.846154 21.661538 0 9.846154 3.938462 19.692308 11.815385 25.6l53.16923 39.384616c72.861538 57.107692 163.446154 88.615385 259.938462 88.615384 232.369231 0 421.415385-189.046154 421.415385-421.415384 0-94.523077-33.476923-185.107692-88.615385-257.969231z" p-id="2219" fill="#707070"></path></svg>
|
After Width: | Height: | Size: 2.4 KiB |
15
src/assets/icons/gateway.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="1664244255409" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2266" width="48" height="48"><path d="M523.776 430.592l-153.088 88.576 153.088 88.576 152.576-88.576-152.576-88.576z m-165.888 108.544l0.512 177.152 153.6 87.552-1.024-176.64-153.088-88.064z m330.24 0l-153.6 87.552-1.024 176.64 153.6-87.552 1.024-176.64z m131.072 205.824l-68.096-40.96 39.936-8.704-5.632-26.112-67.072 14.848-13.824 23.04 101.376 60.928 13.312-23.04z m-142.848 7.68l68.096 40.96-39.936 8.704 5.632 26.112 67.072-14.848 13.824-23.04-101.888-60.928-12.8 23.04zM481.28 424.96h26.624V306.176H481.28v79.36l-27.648-29.696-19.456 18.432L481.28 424.96z m53.76-118.784V424.96h26.624V345.088l27.648 29.696 19.456-18.432-47.104-50.176h-26.624z m-190.464 401.92l-13.312-23.04-68.608 40.448 11.264-38.912-25.6-7.168-18.944 66.048 13.312 23.04 101.888-60.416z m-89.088 82.944l13.312 23.04 68.608-39.936-11.264 38.912 25.6 7.168 19.456-66.048-13.312-23.04-102.4 59.904z m622.08-45.056c-45.568 0-82.432 36.864-82.432 82.432 0 45.568 36.864 82.432 82.432 82.432 45.568 0 82.432-36.864 82.432-82.432 0-45.568-36.864-82.432-82.432-82.432z m0 122.88c-22.528 0-40.448-17.92-40.448-40.448s17.92-40.448 40.448-40.448 40.448 17.92 40.448 40.448-17.92 40.448-40.448 40.448zM521.728 292.864c45.568 0 82.432-36.864 82.432-82.432 0-45.568-36.864-82.432-82.432-82.432-45.568 0-82.432 36.864-82.432 82.432 0 45.568 36.864 82.432 82.432 82.432z m0-122.88c22.528 0 40.448 17.92 40.448 40.448s-17.92 40.448-40.448 40.448-40.448-17.92-40.448-40.448 18.432-40.448 40.448-40.448zM167.936 749.056c-45.568 0-82.432 36.864-82.432 82.432 0 45.568 36.864 82.432 82.432 82.432 45.568 0 82.432-36.864 82.432-82.432 0-45.568-36.864-82.432-82.432-82.432z m0 122.88c-22.528 0-40.448-17.92-40.448-40.448s17.92-40.448 40.448-40.448 40.448 17.92 40.448 40.448-18.432 40.448-40.448 40.448z" p-id="2267"></path></svg>
|
After Width: | Height: | Size: 2.6 KiB |
@@ -13,6 +13,5 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License. -->
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
|
||||
<title>info_outline</title>
|
||||
<path d="M11.016 9v-2.016h1.969v2.016h-1.969zM12 20.016q3.281 0 5.648-2.367t2.367-5.648-2.367-5.648-5.648-2.367-5.648 2.367-2.367 5.648 2.367 5.648 5.648 2.367zM12 2.016q4.125 0 7.055 2.93t2.93 7.055-2.93 7.055-7.055 2.93-7.055-2.93-2.93-7.055 2.93-7.055 7.055-2.93zM11.016 17.016v-6h1.969v6h-1.969z"></path>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
17
src/assets/icons/keyboard_arrow_down.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="M7.406 8.578l4.594 4.594 4.594-4.594 1.406 1.406-6 6-6-6z"></path>
|
||||
</svg>
|
After Width: | Height: | Size: 946 B |
17
src/assets/icons/keyboard_arrow_up.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="M7.406 15.422l-1.406-1.406 6-6 6 6-1.406 1.406-4.594-4.594z"></path>
|
||||
</svg>
|
After Width: | Height: | Size: 948 B |
17
src/assets/icons/library_add.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="M18.984 11.016v-2.016h-3.984v-3.984h-2.016v3.984h-3.984v2.016h3.984v3.984h2.016v-3.984h3.984zM20.016 2.016q0.797 0 1.383 0.586t0.586 1.383v12q0 0.797-0.586 1.406t-1.383 0.609h-12q-0.797 0-1.406-0.609t-0.609-1.406v-12q0-0.797 0.609-1.383t1.406-0.586h12zM3.984 6v14.016h14.016v1.969h-14.016q-0.797 0-1.383-0.586t-0.586-1.383v-14.016h1.969z"></path>
|
||||
</svg>
|
After Width: | Height: | Size: 1.2 KiB |
15
src/assets/icons/operation.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="1664266918236" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5378" width="48" height="48"><path d="M571.178667 643.328a144 144 0 0 1-189.098667-193.450667l77.781333 77.866667a48 48 0 1 0 67.882667-67.84l-77.824-77.909333a144 144 0 0 1 193.450667 189.141333l226.517333 207.061333a64.896 64.896 0 1 1-91.690667 91.690667l-207.018666-226.56z m51.498666 134.656a288.298667 288.298667 0 0 1-38.656 12.928v95.488c0 5.290667-4.309333 9.6-9.642666 9.6h-124.757334a9.6 9.6 0 0 1-9.6-9.6v-95.488a286.293333 286.293333 0 0 1-74.325333-30.805333l-67.541333 67.541333a9.6 9.6 0 0 1-13.568 0L196.352 739.413333a9.6 9.6 0 0 1 0-13.568l67.541333-67.541333a286.293333 286.293333 0 0 1-30.805333-74.325333H137.6A9.6 9.6 0 0 1 128 574.378667v-124.757334c0-5.290667 4.309333-9.6 9.6-9.6h95.488c6.826667-26.453333 17.28-51.370667 30.805333-74.325333L196.352 298.154667a9.6 9.6 0 0 1 0-13.568L284.586667 196.352a9.6 9.6 0 0 1 13.568 0l67.541333 67.498667a287.146667 287.146667 0 0 1 74.325333-30.848V137.6c0-5.290667 4.266667-9.6 9.6-9.6h124.8c5.248 0 9.6 4.309333 9.6 9.6v95.488c26.368 6.826667 51.328 17.28 74.282667 30.805333l67.541333-67.541333a9.6 9.6 0 0 1 13.568 0l88.234667 88.234667a9.6 9.6 0 0 1 0 13.568l-67.498667 67.541333a287.146667 287.146667 0 0 1 30.848 74.282667h95.402667c5.290667 0 9.6 4.352 9.6 9.642666v124.757334c0 5.333333-4.266667 9.6-9.6 9.6h-95.488c-4.693333 18.133333-11.178667 35.754667-19.328 52.650666a9.6 9.6 0 0 1-15.018667 2.986667l-10.112-9.173333-38.314666-34.261334-12.16-10.88a9.6 9.6 0 0 1-2.688-10.24A192.298667 192.298667 0 0 0 512 320a192 192 0 1 0 63.018667 373.333333 9.6 9.6 0 0 1 10.24 2.645334l10.837333 12.074666 35.285333 39.338667 8.149334 9.130667a9.6 9.6 0 0 1-2.901334 15.061333 283.306667 283.306667 0 0 1-13.952 6.4z" p-id="5379"></path></svg>
|
After Width: | Height: | Size: 2.5 KiB |
16
src/assets/icons/setting_empty.svg
Normal file
After Width: | Height: | Size: 5.7 KiB |
19
src/assets/icons/time_range.svg
Normal file
@@ -0,0 +1,19 @@
|
||||
<!-- 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="1660976558460" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="813" width="48" height="48">
|
||||
<path d="M498.596 482.29H345.42v57.308h210.478V274.197h-57.301V482.29z m0 0M577.685 644.985h379.88v57.302h-379.88v-57.302z m0 0M577.685 773.765h379.88v57.307h-379.88v-57.307z m0 0M577.685 902.55h379.88v57.307h-379.88V902.55z m0 0" p-id="814"></path>
|
||||
<path d="M102.523 382.29a28.668 28.668 0 0 0 23.367 2.56l190.81-61.886c15.053-4.883 23.298-21.04 18.415-36.09-4.882-15.052-21.04-23.297-36.093-18.415l-123.346 40c15.994-26.117 35.17-50.538 57.37-72.745 73.768-73.767 171.847-114.388 276.169-114.388 104.32 0 202.395 40.622 276.161 114.388S899.77 407.56 899.77 511.882c0 26.428-2.616 52.45-7.71 77.78h58.303c4.465-25.499 6.709-51.47 6.709-77.78 0-60.45-11.846-119.102-35.205-174.336-22.56-53.335-54.85-101.227-95.969-142.35-41.122-41.122-89.017-73.408-142.348-95.968-55.233-23.361-113.89-35.207-174.334-35.207-60.45 0-119.107 11.846-174.337 35.208-53.335 22.56-101.23 54.846-142.35 95.969-23.98 23.98-44.933 50.278-62.727 78.6l-20.738-105.654c-3.043-15.528-18.105-25.642-33.632-22.6-15.528 3.048-25.643 18.105-22.6 33.637l36.103 183.932a28.666 28.666 0 0 0 13.588 19.178z m0 0M126.02 587.942H67.768c5.76 33.679 15.368 66.544 28.79 98.278 22.56 53.334 54.85 101.225 95.972 142.348 41.123 41.123 89.014 73.409 142.349 95.969 54.112 22.888 111.518 34.711 170.668 35.182v-57.324c-102.95-0.941-199.595-41.446-272.5-114.349-55.501-55.502-92.237-124.77-107.027-200.104z m0 0" p-id="815">
|
||||
</path>
|
||||
</svg>
|
After Width: | Height: | Size: 2.2 KiB |
BIN
src/assets/img/technologies/BOTTLE.png
Normal file
After Width: | Height: | Size: 6.7 KiB |
BIN
src/assets/img/technologies/EVENTMESH.png
Normal file
After Width: | Height: | Size: 9.6 KiB |
BIN
src/assets/img/technologies/HTTPDARK.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
src/assets/img/technologies/HTTPS.png
Normal file
After Width: | Height: | Size: 895 B |
BIN
src/assets/img/technologies/IMPALA.png
Normal file
After Width: | Height: | Size: 5.2 KiB |
BIN
src/assets/img/technologies/MICRONAUT.png
Normal file
After Width: | Height: | Size: 3.1 KiB |
BIN
src/assets/img/technologies/NATS.png
Normal file
After Width: | Height: | Size: 626 B |
@@ -552,7 +552,7 @@ const ok = (info: any) => {
|
||||
if (props.right && _time.getTime() / 100000 > start.value) {
|
||||
emit("setDates", _time, "right");
|
||||
}
|
||||
if (!(props.left && props.right)) {
|
||||
if (!(props.left || props.right)) {
|
||||
emit("setDates", _time);
|
||||
}
|
||||
emit("ok", info === "h");
|
||||
@@ -632,11 +632,6 @@ onMounted(() => {
|
||||
right: 24px;
|
||||
}
|
||||
|
||||
.calendar-next-month-btn .middle,
|
||||
.calendar-prev-month-btn .middle {
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.calendar-body {
|
||||
position: relative;
|
||||
width: 196px;
|
||||
|
@@ -15,6 +15,28 @@ limitations under the License. -->
|
||||
<template>
|
||||
<div class="chart" ref="chartRef" :style="`height:${height};width:${width};`">
|
||||
<div v-if="!available" class="no-data">No Data</div>
|
||||
<div class="menus" v-show="visMenus" ref="menus">
|
||||
<div class="tools" @click="associateMetrics" v-if="associate.length">
|
||||
{{ t("associateMetrics") }}
|
||||
</div>
|
||||
<div
|
||||
class="tools"
|
||||
@click="viewTrace"
|
||||
v-if="relatedTrace && relatedTrace.enableRelate"
|
||||
>
|
||||
{{ t("viewTrace") }}
|
||||
</div>
|
||||
</div>
|
||||
<el-drawer
|
||||
v-model="showTrace"
|
||||
size="100%"
|
||||
:destroy-on-close="true"
|
||||
:before-close="() => (showTrace = false)"
|
||||
:append-to-body="true"
|
||||
title="The Related Traces"
|
||||
>
|
||||
<Trace :data="traceOptions" />
|
||||
</el-drawer>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
@@ -28,15 +50,28 @@ import {
|
||||
computed,
|
||||
} from "vue";
|
||||
import type { PropType } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { EventParams } from "@/types/app";
|
||||
import { Filters, RelatedTrace } from "@/types/dashboard";
|
||||
import { useECharts } from "@/hooks/useEcharts";
|
||||
import { addResizeListener, removeResizeListener } from "@/utils/event";
|
||||
import Trace from "@/views/dashboard/related/trace/Index.vue";
|
||||
import associateProcessor from "@/hooks/useAssociateProcessor";
|
||||
|
||||
/*global Nullable, defineProps, defineEmits*/
|
||||
const emits = defineEmits(["select"]);
|
||||
const { t } = useI18n();
|
||||
const chartRef = ref<Nullable<HTMLDivElement>>(null);
|
||||
const menus = ref<Nullable<HTMLDivElement>>(null);
|
||||
const visMenus = ref<boolean>(false);
|
||||
const { setOptions, resize, getInstance } = useECharts(
|
||||
chartRef as Ref<HTMLDivElement>
|
||||
);
|
||||
const currentParams = ref<Nullable<EventParams>>(null);
|
||||
const showTrace = ref<boolean>(false);
|
||||
const traceOptions = ref<{ type: string; filters?: unknown }>({
|
||||
type: "Trace",
|
||||
});
|
||||
const props = defineProps({
|
||||
height: { type: String, default: "100%" },
|
||||
width: { type: String, default: "100%" },
|
||||
@@ -44,6 +79,16 @@ const props = defineProps({
|
||||
type: Object as PropType<{ [key: string]: any }>,
|
||||
default: () => ({}),
|
||||
},
|
||||
filters: {
|
||||
type: Object as PropType<Filters>,
|
||||
},
|
||||
relatedTrace: {
|
||||
type: Object as PropType<RelatedTrace>,
|
||||
},
|
||||
associate: {
|
||||
type: Array as PropType<{ widgetId: string }[]>,
|
||||
default: () => [],
|
||||
},
|
||||
});
|
||||
const available = computed(
|
||||
() =>
|
||||
@@ -55,17 +100,97 @@ const available = computed(
|
||||
onMounted(async () => {
|
||||
await setOptions(props.option);
|
||||
chartRef.value && addResizeListener(unref(chartRef), resize);
|
||||
instanceEvent();
|
||||
});
|
||||
|
||||
function instanceEvent() {
|
||||
setTimeout(() => {
|
||||
const instance = getInstance();
|
||||
|
||||
if (!instance) {
|
||||
return;
|
||||
}
|
||||
instance.on("click", (params: any) => {
|
||||
emits("select", params);
|
||||
instance.on("click", (params: EventParams) => {
|
||||
currentParams.value = params;
|
||||
if (!menus.value || !chartRef.value) {
|
||||
return;
|
||||
}
|
||||
visMenus.value = true;
|
||||
const w = chartRef.value.getBoundingClientRect().width || 0;
|
||||
const h = chartRef.value.getBoundingClientRect().height || 0;
|
||||
if (w - params.event.offsetX > 120) {
|
||||
menus.value.style.left = params.event.offsetX + "px";
|
||||
} else {
|
||||
menus.value.style.left = params.event.offsetX - 120 + "px";
|
||||
}
|
||||
if (h - params.event.offsetY < 50) {
|
||||
menus.value.style.top = params.event.offsetY - 40 + "px";
|
||||
} else {
|
||||
menus.value.style.top = params.event.offsetY + 2 + "px";
|
||||
}
|
||||
});
|
||||
document.addEventListener(
|
||||
"click",
|
||||
() => {
|
||||
if (instance.isDisposed()) {
|
||||
return;
|
||||
}
|
||||
visMenus.value = false;
|
||||
instance.dispatchAction({
|
||||
type: "updateAxisPointer",
|
||||
currTrigger: "leave",
|
||||
});
|
||||
},
|
||||
true
|
||||
);
|
||||
}, 1000);
|
||||
});
|
||||
}
|
||||
|
||||
function associateMetrics() {
|
||||
emits("select", currentParams.value);
|
||||
const { dataIndex, seriesIndex } = currentParams.value || {
|
||||
dataIndex: 0,
|
||||
seriesIndex: 0,
|
||||
};
|
||||
updateOptions({ dataIndex, seriesIndex });
|
||||
}
|
||||
|
||||
function updateOptions(params?: { dataIndex: number; seriesIndex: number }) {
|
||||
const instance = getInstance();
|
||||
if (!instance) {
|
||||
return;
|
||||
}
|
||||
if (!props.filters) {
|
||||
return;
|
||||
}
|
||||
if (props.filters.isRange) {
|
||||
const { eventAssociate } = associateProcessor(props);
|
||||
const options = eventAssociate();
|
||||
setOptions(options || props.option);
|
||||
} else {
|
||||
instance.dispatchAction({
|
||||
type: "updateAxisPointer",
|
||||
dataIndex: params ? params.dataIndex : props.filters.dataIndex,
|
||||
seriesIndex: params ? params.seriesIndex : 0,
|
||||
});
|
||||
const ids = props.option.series.map((_: unknown, index: number) => index);
|
||||
instance.dispatchAction({
|
||||
type: "highlight",
|
||||
dataIndex: params ? params.dataIndex : props.filters.dataIndex,
|
||||
seriesIndex: ids,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function viewTrace() {
|
||||
const item = associateProcessor(props).traceFilters(currentParams.value);
|
||||
traceOptions.value = {
|
||||
...traceOptions.value,
|
||||
filters: item,
|
||||
};
|
||||
showTrace.value = true;
|
||||
visMenus.value = true;
|
||||
}
|
||||
|
||||
watch(
|
||||
() => props.option,
|
||||
@@ -76,7 +201,18 @@ watch(
|
||||
if (JSON.stringify(newVal) === JSON.stringify(oldVal)) {
|
||||
return;
|
||||
}
|
||||
setOptions(newVal);
|
||||
let options;
|
||||
if (props.filters && props.filters.isRange) {
|
||||
const { eventAssociate } = associateProcessor(props);
|
||||
options = eventAssociate();
|
||||
}
|
||||
setOptions(options || props.option);
|
||||
}
|
||||
);
|
||||
watch(
|
||||
() => props.filters,
|
||||
() => {
|
||||
updateOptions();
|
||||
}
|
||||
);
|
||||
|
||||
@@ -98,5 +234,30 @@ onBeforeUnmount(() => {
|
||||
|
||||
.chart {
|
||||
overflow: hidden;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.menus {
|
||||
position: absolute;
|
||||
display: block;
|
||||
white-space: nowrap;
|
||||
z-index: 9999999;
|
||||
box-shadow: #ddd 1px 2px 10px;
|
||||
transition: all cubic-bezier(0.075, 0.82, 0.165, 1) linear;
|
||||
background-color: rgb(255, 255, 255);
|
||||
border-radius: 4px;
|
||||
color: rgb(51, 51, 51);
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.tools {
|
||||
padding: 5px;
|
||||
color: #999;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
color: #409eff;
|
||||
background-color: #eee;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@@ -24,8 +24,8 @@ import { ref } from "vue";
|
||||
import type { PropType } from "vue";
|
||||
|
||||
interface Option {
|
||||
label: string;
|
||||
value: string;
|
||||
label: string | number;
|
||||
value: string | number;
|
||||
}
|
||||
|
||||
/*global defineProps, defineEmits */
|
||||
|
@@ -18,7 +18,6 @@ limitations under the License. -->
|
||||
v-model="selected"
|
||||
:placeholder="placeholder"
|
||||
@change="changeSelected"
|
||||
filterable
|
||||
:multiple="multiple"
|
||||
:disabled="disabled"
|
||||
:style="{ borderRadius }"
|
||||
@@ -26,12 +25,13 @@ limitations under the License. -->
|
||||
:remote="isRemote"
|
||||
:reserve-keyword="isRemote"
|
||||
:remote-method="remoteMethod"
|
||||
:filterable="filterable"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in options"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
:key="item.value || ''"
|
||||
:label="item.label || ''"
|
||||
:value="item.value || ''"
|
||||
>
|
||||
</el-option>
|
||||
</el-select>
|
||||
@@ -66,6 +66,7 @@ const props = defineProps({
|
||||
disabled: { type: Boolean, default: false },
|
||||
clearable: { type: Boolean, default: false },
|
||||
isRemote: { type: Boolean, default: false },
|
||||
filterable: { type: Boolean, default: true },
|
||||
});
|
||||
|
||||
const selected = ref<string[] | string>(props.value);
|
||||
|
@@ -14,6 +14,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export enum TimeType {
|
||||
MINUTE_TIME = "MINUTE",
|
||||
HOUR_TIME = "HOUR",
|
||||
@@ -25,18 +26,3 @@ export const Languages = [
|
||||
{ label: "Chinese", value: "zh" },
|
||||
{ label: "Spanish", value: "es" },
|
||||
];
|
||||
|
||||
export const RoutesMap: { [key: string]: string } = {
|
||||
GeneralServices: "GENERAL",
|
||||
Database: "VIRTUAL_DATABASE",
|
||||
MeshServices: "MESH",
|
||||
ControlPanel: "MESH_CP",
|
||||
DataPanel: "MESH_DP",
|
||||
Linux: "OS_LINUX",
|
||||
SkyWalkingServer: "SO11Y_OAP",
|
||||
Satellite: "SO11Y_SATELLITE",
|
||||
Functions: "FAAS",
|
||||
Browser: "BROWSER",
|
||||
KubernetesCluster: "K8S",
|
||||
KubernetesService: "K8S_SERVICE",
|
||||
};
|
||||
|
@@ -33,12 +33,15 @@ export const createEBPFTask = {
|
||||
}`,
|
||||
};
|
||||
export const queryEBPFTasks = {
|
||||
variable: "$serviceId: ID!",
|
||||
variable:
|
||||
"$serviceId: ID, $serviceInstanceId: ID, $targets: [EBPFProfilingTargetType!]",
|
||||
query: `
|
||||
queryEBPFTasks: queryEBPFProfilingTasks(serviceId: $serviceId) {
|
||||
queryEBPFTasks: queryEBPFProfilingTasks(serviceId: $serviceId, serviceInstanceId: $serviceInstanceId, targets: $targets) {
|
||||
taskId
|
||||
serviceName
|
||||
serviceId
|
||||
serviceInstanceId
|
||||
serviceInstanceName
|
||||
processLabels
|
||||
taskStartTime
|
||||
triggerType
|
||||
@@ -90,3 +93,22 @@ export const analysisEBPFResult = {
|
||||
}
|
||||
}`,
|
||||
};
|
||||
|
||||
export const createNetworkProfiling = {
|
||||
variable: "$request: EBPFProfilingNetworkTaskRequest!",
|
||||
query: `
|
||||
createEBPFNetworkProfiling(request: $request) {
|
||||
status
|
||||
errorReason
|
||||
id
|
||||
}`,
|
||||
};
|
||||
|
||||
export const keepNetworkProfiling = {
|
||||
variable: "$taskId: ID!",
|
||||
query: `
|
||||
keepEBPFNetworkProfiling(taskId: $taskId) {
|
||||
status
|
||||
errorReason
|
||||
}`,
|
||||
};
|
||||
|
@@ -48,6 +48,29 @@ export const Instances = {
|
||||
}
|
||||
`,
|
||||
};
|
||||
|
||||
export const Processes = {
|
||||
variable: "$instanceId: ID!, $duration: Duration!",
|
||||
query: `
|
||||
processes: listProcesses(instanceId: $instanceId, duration: $duration) {
|
||||
id
|
||||
value: name
|
||||
label: name
|
||||
serviceId
|
||||
serviceName
|
||||
instanceId
|
||||
instanceName
|
||||
agentId
|
||||
detectType
|
||||
attributes {
|
||||
name
|
||||
value
|
||||
}
|
||||
labels
|
||||
}
|
||||
`,
|
||||
};
|
||||
|
||||
export const Endpoints = {
|
||||
variable: "$serviceId: ID!, $keyword: String!",
|
||||
query: `
|
||||
@@ -102,3 +125,24 @@ export const getEndpoint = {
|
||||
}
|
||||
`,
|
||||
};
|
||||
|
||||
export const getProcess = {
|
||||
variable: "$processId: ID!",
|
||||
query: `
|
||||
process: getProcess(processId: $processId) {
|
||||
id
|
||||
value: name
|
||||
label: name
|
||||
serviceId
|
||||
serviceName
|
||||
instanceId
|
||||
instanceName
|
||||
agentId
|
||||
detectType
|
||||
attributes {
|
||||
name
|
||||
value
|
||||
}
|
||||
}
|
||||
`,
|
||||
};
|
||||
|
@@ -75,3 +75,28 @@ export const InstanceTopology = {
|
||||
}
|
||||
`,
|
||||
};
|
||||
export const ProcessTopology = {
|
||||
variable: "$serviceInstanceId: ID!, $duration: Duration!",
|
||||
query: `
|
||||
topology: getProcessTopology(serviceInstanceId: $serviceInstanceId,
|
||||
duration: $duration) {
|
||||
nodes {
|
||||
id
|
||||
name
|
||||
isReal
|
||||
serviceName
|
||||
serviceId
|
||||
serviceInstanceId
|
||||
serviceInstanceName
|
||||
}
|
||||
calls {
|
||||
id
|
||||
source
|
||||
detectPoints
|
||||
target
|
||||
sourceComponents
|
||||
targetComponents
|
||||
}
|
||||
}
|
||||
`,
|
||||
};
|
||||
|
@@ -69,6 +69,25 @@ export const TraceSpans = {
|
||||
value
|
||||
}
|
||||
}
|
||||
attachedEvents {
|
||||
startTime {
|
||||
seconds
|
||||
nanos
|
||||
}
|
||||
event
|
||||
endTime {
|
||||
seconds
|
||||
nanos
|
||||
}
|
||||
tags {
|
||||
key
|
||||
value
|
||||
}
|
||||
summary {
|
||||
key
|
||||
value
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`,
|
||||
|
@@ -21,6 +21,8 @@ import {
|
||||
queryEBPFTasks,
|
||||
queryEBPFSchedules,
|
||||
analysisEBPFResult,
|
||||
createNetworkProfiling,
|
||||
keepNetworkProfiling,
|
||||
} from "../fragments/ebpf";
|
||||
|
||||
export const getCreateTaskData = `query queryCreateTaskData(${queryCreateTaskData.variable}) {${queryCreateTaskData.query}}`;
|
||||
@@ -32,3 +34,7 @@ export const getEBPFTasks = `query queryEBPFTasks(${queryEBPFTasks.variable}) {$
|
||||
export const getEBPFSchedules = `query queryEBPFSchedules(${queryEBPFSchedules.variable}) {${queryEBPFSchedules.query}}`;
|
||||
|
||||
export const getEBPFResult = `query analysisEBPFResult(${analysisEBPFResult.variable}) {${analysisEBPFResult.query}}`;
|
||||
|
||||
export const newNetworkProfiling = `mutation createNetworkProfiling(${createNetworkProfiling.variable}) {${createNetworkProfiling.query}}`;
|
||||
|
||||
export const aliveNetworkProfiling = `mutation keepNetworkProfiling(${keepNetworkProfiling.variable}) {${keepNetworkProfiling.query}}`;
|
||||
|
@@ -22,6 +22,8 @@ import {
|
||||
getService,
|
||||
getInstance,
|
||||
getEndpoint,
|
||||
Processes,
|
||||
getProcess,
|
||||
} from "../fragments/selector";
|
||||
|
||||
export const queryServices = `query queryServices(${Services.variable}) {${Services.query}}`;
|
||||
@@ -30,4 +32,6 @@ export const queryInstances = `query queryInstances(${Instances.variable}) {${In
|
||||
export const queryLayers = `query listLayer {${Layers.query}}`;
|
||||
export const queryService = `query queryService(${getService.variable}) {${getService.query}}`;
|
||||
export const queryInstance = `query queryInstance(${getInstance.variable}) {${getInstance.query}}`;
|
||||
export const queryEndpoint = `query queryInstance(${getEndpoint.variable}) {${getEndpoint.query}}`;
|
||||
export const queryEndpoint = `query queryEndpoint(${getEndpoint.variable}) {${getEndpoint.query}}`;
|
||||
export const queryProcesses = `query queryProcesses(${Processes.variable}) {${Processes.query}}`;
|
||||
export const queryProcess = `query queryProcess(${getProcess.variable}) {${getProcess.query}}`;
|
||||
|
@@ -18,8 +18,10 @@ import {
|
||||
InstanceTopology,
|
||||
EndpointTopology,
|
||||
ServicesTopology,
|
||||
ProcessTopology,
|
||||
} from "../fragments/topology";
|
||||
|
||||
export const getInstanceTopology = `query queryData(${InstanceTopology.variable}) {${InstanceTopology.query}}`;
|
||||
export const getEndpointTopology = `query queryData(${EndpointTopology.variable}) {${EndpointTopology.query}}`;
|
||||
export const getServicesTopology = `query queryData(${ServicesTopology.variable}) {${ServicesTopology.query}}`;
|
||||
export const getProcessTopology = `query queryData(${ProcessTopology.variable}) {${ProcessTopology.query}}`;
|
||||
|
@@ -21,6 +21,7 @@ export enum MetricQueryTypes {
|
||||
ReadLabeledMetricsValues = "readLabeledMetricsValues",
|
||||
READHEATMAP = "readHeatMap",
|
||||
ReadSampledRecords = "readSampledRecords",
|
||||
ReadRecords = "readRecords",
|
||||
}
|
||||
|
||||
export enum Calculations {
|
||||
@@ -32,10 +33,12 @@ export enum Calculations {
|
||||
Precision = "precision",
|
||||
ConvertSeconds = "convertSeconds",
|
||||
ConvertMilliseconds = "convertMilliseconds",
|
||||
MsTos = "msTos",
|
||||
MsToS = "msTos",
|
||||
Average = "average",
|
||||
PercentageAvg = "percentageAvg",
|
||||
ApdexAvg = "apdexAvg",
|
||||
SecondToDay = "secondToDay",
|
||||
NanosecondToMillisecond = "nanosecondToMillisecond",
|
||||
}
|
||||
export enum sizeEnum {
|
||||
XS = "XS",
|
||||
@@ -99,4 +102,10 @@ export const RespFields: any = {
|
||||
value
|
||||
refId
|
||||
}`,
|
||||
readRecords: `{
|
||||
id
|
||||
name
|
||||
value
|
||||
refId
|
||||
}`,
|
||||
};
|
||||
|
138
src/hooks/useAssociateProcessor.ts
Normal file
@@ -0,0 +1,138 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||
import dateFormatStep from "@/utils/dateFormat";
|
||||
import getLocalTime from "@/utils/localtime";
|
||||
import { EventParams } from "@/types/app";
|
||||
|
||||
export default function associateProcessor(props: any) {
|
||||
function eventAssociate() {
|
||||
if (!props.filters) {
|
||||
return;
|
||||
}
|
||||
if (!props.filters.duration) {
|
||||
return props.option;
|
||||
}
|
||||
if (!props.option.series[0]) {
|
||||
return;
|
||||
}
|
||||
const list = props.option.series[0].data.map(
|
||||
(d: (number | string)[]) => d[0]
|
||||
);
|
||||
if (!list.includes(props.filters.duration.endTime)) {
|
||||
return;
|
||||
}
|
||||
const markArea = {
|
||||
silent: true,
|
||||
itemStyle: {
|
||||
opacity: 0.3,
|
||||
},
|
||||
data: [
|
||||
[
|
||||
{
|
||||
xAxis: props.filters.duration.startTime,
|
||||
},
|
||||
{
|
||||
xAxis: props.filters.duration.endTime,
|
||||
},
|
||||
],
|
||||
],
|
||||
};
|
||||
const series = (window as any).structuredClone(props.option.series);
|
||||
for (const [key, temp] of series.entries()) {
|
||||
if (key === 0) {
|
||||
temp.markArea = markArea;
|
||||
}
|
||||
}
|
||||
const options = {
|
||||
...props.option,
|
||||
series,
|
||||
};
|
||||
return options;
|
||||
}
|
||||
function traceFilters(currentParams: Nullable<EventParams>) {
|
||||
const appStore = useAppStoreWithOut();
|
||||
|
||||
if (!currentParams) {
|
||||
return;
|
||||
}
|
||||
const start = appStore.intervalUnix[currentParams.dataIndex];
|
||||
const { step } = appStore.durationRow;
|
||||
let duration = undefined;
|
||||
|
||||
if (start) {
|
||||
const end = start;
|
||||
duration = {
|
||||
start: dateFormatStep(
|
||||
getLocalTime(appStore.utc, new Date(start)),
|
||||
step,
|
||||
true
|
||||
),
|
||||
end: dateFormatStep(
|
||||
getLocalTime(appStore.utc, new Date(end)),
|
||||
step,
|
||||
true
|
||||
),
|
||||
step,
|
||||
};
|
||||
}
|
||||
const relatedTrace = props.relatedTrace || {};
|
||||
const status = relatedTrace.status;
|
||||
const queryOrder = relatedTrace.queryOrder;
|
||||
const latency = relatedTrace.latency;
|
||||
const series = props.option.series || [];
|
||||
const item: any = {
|
||||
duration,
|
||||
queryOrder,
|
||||
status,
|
||||
};
|
||||
if (latency) {
|
||||
const latencyList = series.map(
|
||||
(d: { name: string; data: number[][] }, index: number) => {
|
||||
const data = [
|
||||
d.data[currentParams.dataIndex][1],
|
||||
series[index + 1]
|
||||
? series[index + 1].data[currentParams.dataIndex][1]
|
||||
: Infinity,
|
||||
];
|
||||
return {
|
||||
label:
|
||||
d.name +
|
||||
"--" +
|
||||
(series[index + 1] ? series[index + 1].name : "Infinity"),
|
||||
value: String(index),
|
||||
data,
|
||||
};
|
||||
}
|
||||
);
|
||||
item.latency = latencyList;
|
||||
}
|
||||
const value = series.map(
|
||||
(d: { name: string; data: number[][] }, index: number) => {
|
||||
return {
|
||||
label: d.name,
|
||||
value: String(index),
|
||||
data: d.data[currentParams.dataIndex][1],
|
||||
date: d.data[currentParams.dataIndex][0],
|
||||
};
|
||||
}
|
||||
);
|
||||
item.metricValue = value;
|
||||
return item;
|
||||
}
|
||||
return { eventAssociate, traceFilters };
|
||||
}
|
@@ -14,19 +14,68 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { ElMessage } from "element-plus";
|
||||
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||
import { LayoutConfig } from "@/types/dashboard";
|
||||
|
||||
export default function getDashboard(param: {
|
||||
export default function getDashboard(param?: {
|
||||
name: string;
|
||||
layer: string;
|
||||
entity: string;
|
||||
}) {
|
||||
const dashboardStore = useDashboardStore();
|
||||
const opt = param || dashboardStore.currentDashboard;
|
||||
const list = JSON.parse(sessionStorage.getItem("dashboards") || "[]");
|
||||
const dashboard = list.find(
|
||||
(d: { name: string; layer: string; entity: string }) =>
|
||||
d.name === param.name &&
|
||||
d.entity === param.entity &&
|
||||
d.layer === param.layer
|
||||
d.name === opt.name && d.entity === opt.entity && d.layer === opt.layer
|
||||
);
|
||||
const all = dashboardStore.layout;
|
||||
const widgets: LayoutConfig[] = [];
|
||||
for (const item of all) {
|
||||
if (item.type === "Tab") {
|
||||
widgets.push(item);
|
||||
if (item.children && item.children.length) {
|
||||
for (const child of item.children) {
|
||||
if (child.children && child.children.length) {
|
||||
widgets.push(...child.children);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
widgets.push(item);
|
||||
}
|
||||
}
|
||||
function associationWidget(sourceId: string, filters: unknown, type: string) {
|
||||
const widget = widgets.find((d: { type: string }) => d.type === type);
|
||||
if (!widget) {
|
||||
return ElMessage.info(`There has no a ${type} widget in the dashboard`);
|
||||
}
|
||||
const item = {
|
||||
...widget,
|
||||
filters,
|
||||
};
|
||||
dashboardStore.setWidget(item);
|
||||
const targetTabIndex = (widget.id || "").split("-");
|
||||
const sourceTabindex = (sourceId || "").split("-") || [];
|
||||
let container: Nullable<Element>;
|
||||
|
||||
return dashboard;
|
||||
if (targetTabIndex[1] === undefined) {
|
||||
container = document.querySelector(".ds-main");
|
||||
} else {
|
||||
const w = widgets.find((d: any) => d.id === targetTabIndex[0]);
|
||||
container = document.querySelector(".tab-layout");
|
||||
const layout: Nullable<Element> = document.querySelector(".ds-main");
|
||||
if (w && layout) {
|
||||
layout.scrollTop = w.y * 10 + w.h * 5;
|
||||
}
|
||||
}
|
||||
if (targetTabIndex[1] && targetTabIndex[1] !== sourceTabindex[1]) {
|
||||
dashboardStore.setActiveTabIndex(Number(targetTabIndex[1]));
|
||||
}
|
||||
if (container && widget) {
|
||||
container.scrollTop = widget.y * 10 + widget.h * 5;
|
||||
}
|
||||
}
|
||||
return { dashboard, widgets, associationWidget };
|
||||
}
|
||||
|
@@ -18,7 +18,6 @@ import {
|
||||
BarSeriesOption,
|
||||
LineSeriesOption,
|
||||
HeatmapSeriesOption,
|
||||
PieSeriesOption,
|
||||
SankeySeriesOption,
|
||||
} from "echarts/charts";
|
||||
import {
|
||||
@@ -46,7 +45,6 @@ export type ECOption = echarts.ComposeOption<
|
||||
| DatasetComponentOption
|
||||
| LegendComponentOption
|
||||
| HeatmapSeriesOption
|
||||
| PieSeriesOption
|
||||
| SankeySeriesOption
|
||||
>;
|
||||
|
||||
|
142
src/hooks/useLegendProcessor.ts
Normal file
@@ -0,0 +1,142 @@
|
||||
/**
|
||||
* 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 { LegendOptions } from "@/types/dashboard";
|
||||
import { isDef } from "@/utils/is";
|
||||
|
||||
export default function useLegendProcess(legend?: LegendOptions) {
|
||||
let isRight = false;
|
||||
if (legend && legend.toTheRight) {
|
||||
isRight = true;
|
||||
}
|
||||
function showEchartsLegend(keys: string[]) {
|
||||
if (legend && isDef(legend.show)) {
|
||||
if (legend.asTable && legend.show) {
|
||||
return false;
|
||||
}
|
||||
return legend.show;
|
||||
}
|
||||
if (keys.length === 1) {
|
||||
return false;
|
||||
}
|
||||
if (legend && legend.asTable) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
function aggregations(
|
||||
data: { [key: string]: number[] },
|
||||
intervalTime: string[]
|
||||
) {
|
||||
const source: { [key: string]: unknown }[] = [];
|
||||
const keys = Object.keys(data || {}).filter(
|
||||
(i: any) => Array.isArray(data[i]) && data[i].length
|
||||
);
|
||||
const headers = [];
|
||||
|
||||
for (const [key, value] of keys.entries()) {
|
||||
const arr = JSON.parse(JSON.stringify(data[value]));
|
||||
const item: { [key: string]: unknown } = {
|
||||
name: value,
|
||||
topN: arr
|
||||
.map((d: number, index: number) => {
|
||||
return {
|
||||
key: intervalTime[index],
|
||||
value: d,
|
||||
};
|
||||
})
|
||||
.sort(
|
||||
(
|
||||
a: { key: string; value: number },
|
||||
b: { key: string; value: number }
|
||||
) => b.value - a.value
|
||||
)
|
||||
.filter((_: unknown, index: number) => index < 10),
|
||||
};
|
||||
if (legend) {
|
||||
if (legend.min) {
|
||||
item.min = Math.min(...data[value]).toFixed(2);
|
||||
if (key === 0) {
|
||||
headers.push({ value: "min", label: "Min" });
|
||||
}
|
||||
}
|
||||
if (legend.max) {
|
||||
item.max = Math.max(...data[value]).toFixed(2);
|
||||
if (key === 0) {
|
||||
headers.push({ value: "max", label: "Max" });
|
||||
}
|
||||
}
|
||||
if (legend.mean) {
|
||||
const total = data[value].reduce((prev: number, next: number) => {
|
||||
prev += Number(next);
|
||||
return prev;
|
||||
}, 0);
|
||||
item.mean = (total / data[value].length).toFixed(4);
|
||||
if (key === 0) {
|
||||
headers.push({ value: "mean", label: "Mean" });
|
||||
}
|
||||
}
|
||||
if (legend.total) {
|
||||
item.total = data[value]
|
||||
.reduce((prev: number, next: number) => {
|
||||
prev += Number(next);
|
||||
return prev;
|
||||
}, 0)
|
||||
.toFixed(2);
|
||||
if (key === 0) {
|
||||
headers.push({ value: "total", label: "Total" });
|
||||
}
|
||||
}
|
||||
}
|
||||
source.push(item);
|
||||
}
|
||||
|
||||
return { source, headers };
|
||||
}
|
||||
function chartColors(keys: string[]) {
|
||||
let color: string[] = [];
|
||||
switch (keys.length) {
|
||||
case 2:
|
||||
color = ["#FF6A84", "#a0b1e6"];
|
||||
break;
|
||||
case 1:
|
||||
color = ["#3f96e3"];
|
||||
break;
|
||||
default:
|
||||
color = [
|
||||
"#30A4EB",
|
||||
"#45BFC0",
|
||||
"#FFCC55",
|
||||
"#FF6A84",
|
||||
"#a0a7e6",
|
||||
"#c23531",
|
||||
"#2f4554",
|
||||
"#61a0a8",
|
||||
"#d48265",
|
||||
"#91c7ae",
|
||||
"#749f83",
|
||||
"#ca8622",
|
||||
"#bda29a",
|
||||
"#6e7074",
|
||||
"#546570",
|
||||
"#c4ccd3",
|
||||
];
|
||||
break;
|
||||
}
|
||||
return color;
|
||||
}
|
||||
return { showEchartsLegend, isRight, aggregations, chartColors };
|
||||
}
|
@@ -26,14 +26,18 @@ export function useListConfig(config: any, index: string) {
|
||||
config.metricConfig &&
|
||||
config.metricConfig[i] &&
|
||||
config.metricConfig[i].calculation;
|
||||
const line =
|
||||
config.metricTypes[i] === MetricQueryTypes.ReadMetricsValues &&
|
||||
!types.includes(calculation);
|
||||
const isLinear =
|
||||
[
|
||||
MetricQueryTypes.ReadMetricsValues,
|
||||
MetricQueryTypes.ReadLabeledMetricsValues,
|
||||
].includes(config.metricTypes[i]) && !types.includes(calculation);
|
||||
const isAvg =
|
||||
config.metricTypes[i] === MetricQueryTypes.ReadMetricsValues &&
|
||||
types.includes(calculation);
|
||||
[
|
||||
MetricQueryTypes.ReadMetricsValues,
|
||||
MetricQueryTypes.ReadLabeledMetricsValues,
|
||||
].includes(config.metricTypes[i]) && types.includes(calculation);
|
||||
return {
|
||||
isLinear: line,
|
||||
isLinear,
|
||||
isAvg,
|
||||
};
|
||||
}
|
||||
|
@@ -46,6 +46,7 @@ export function useQueryProcessor(config: any) {
|
||||
"ServiceRelation",
|
||||
"ServiceInstanceRelation",
|
||||
"EndpointRelation",
|
||||
"ProcessRelation",
|
||||
].includes(dashboardStore.entity);
|
||||
if (isRelation && !selectorStore.currentDestService) {
|
||||
return;
|
||||
@@ -73,50 +74,73 @@ export function useQueryProcessor(config: any) {
|
||||
order: c.sortOrder || "DES",
|
||||
};
|
||||
} else {
|
||||
if (metricType === MetricQueryTypes.ReadLabeledMetricsValues) {
|
||||
const labels = (c.labelsIndex || "")
|
||||
.split(",")
|
||||
.map((item: string) => item.replace(/^\s*|\s*$/g, ""));
|
||||
variables.push(`$labels${index}: [String!]!`);
|
||||
conditions[`labels${index}`] = labels;
|
||||
}
|
||||
variables.push(`$condition${index}: MetricsCondition!`);
|
||||
conditions[`condition${index}`] = {
|
||||
name,
|
||||
entity: {
|
||||
scope: dashboardStore.entity,
|
||||
serviceName:
|
||||
dashboardStore.entity === "All"
|
||||
? undefined
|
||||
: selectorStore.currentService.value,
|
||||
normal:
|
||||
dashboardStore.entity === "All"
|
||||
? undefined
|
||||
: selectorStore.currentService.normal,
|
||||
serviceInstanceName: dashboardStore.entity.includes("ServiceInstance")
|
||||
? selectorStore.currentPod && selectorStore.currentPod.value
|
||||
const entity = {
|
||||
scope: config.catalog,
|
||||
serviceName:
|
||||
dashboardStore.entity === "All"
|
||||
? undefined
|
||||
: selectorStore.currentService.value,
|
||||
normal:
|
||||
dashboardStore.entity === "All"
|
||||
? undefined
|
||||
: selectorStore.currentService.normal,
|
||||
serviceInstanceName: [
|
||||
"ServiceInstance",
|
||||
"ServiceInstanceRelation",
|
||||
"ProcessRelation",
|
||||
].includes(dashboardStore.entity)
|
||||
? selectorStore.currentPod && selectorStore.currentPod.value
|
||||
: undefined,
|
||||
endpointName: dashboardStore.entity.includes("Endpoint")
|
||||
? selectorStore.currentPod && selectorStore.currentPod.value
|
||||
: undefined,
|
||||
processName: dashboardStore.entity.includes("Process")
|
||||
? selectorStore.currentProcess && selectorStore.currentProcess.value
|
||||
: undefined,
|
||||
destNormal: isRelation
|
||||
? selectorStore.currentDestService.normal
|
||||
: undefined,
|
||||
destServiceName: isRelation
|
||||
? selectorStore.currentDestService.value
|
||||
: undefined,
|
||||
destServiceInstanceName: [
|
||||
"ServiceInstanceRelation",
|
||||
"ProcessRelation",
|
||||
].includes(dashboardStore.entity)
|
||||
? selectorStore.currentDestPod && selectorStore.currentDestPod.value
|
||||
: undefined,
|
||||
destEndpointName:
|
||||
dashboardStore.entity === "EndpointRelation"
|
||||
? selectorStore.currentDestPod && selectorStore.currentDestPod.value
|
||||
: undefined,
|
||||
endpointName: dashboardStore.entity.includes("Endpoint")
|
||||
? selectorStore.currentPod && selectorStore.currentPod.value
|
||||
: undefined,
|
||||
destNormal: isRelation
|
||||
? selectorStore.currentDestService.normal
|
||||
: undefined,
|
||||
destServiceName: isRelation
|
||||
? selectorStore.currentDestService.value
|
||||
: undefined,
|
||||
destServiceInstanceName:
|
||||
dashboardStore.entity === "ServiceInstanceRelation"
|
||||
? selectorStore.currentDestPod &&
|
||||
selectorStore.currentDestPod.value
|
||||
: undefined,
|
||||
destEndpointName:
|
||||
dashboardStore.entity === "EndpointRelation"
|
||||
? selectorStore.currentDestPod &&
|
||||
selectorStore.currentDestPod.value
|
||||
: undefined,
|
||||
},
|
||||
destProcessName: dashboardStore.entity.includes("ProcessRelation")
|
||||
? selectorStore.currentDestProcess &&
|
||||
selectorStore.currentDestProcess.value
|
||||
: undefined,
|
||||
};
|
||||
if ([MetricQueryTypes.ReadRecords].includes(metricType)) {
|
||||
variables.push(`$condition${index}: RecordCondition!`);
|
||||
conditions[`condition${index}`] = {
|
||||
name,
|
||||
parentEntity: entity,
|
||||
topN: c.topN || 10,
|
||||
order: c.sortOrder || "DES",
|
||||
};
|
||||
} else {
|
||||
entity.scope = dashboardStore.entity;
|
||||
if (metricType === MetricQueryTypes.ReadLabeledMetricsValues) {
|
||||
const labels = (c.labelsIndex || "")
|
||||
.split(",")
|
||||
.map((item: string) => item.replace(/^\s*|\s*$/g, ""));
|
||||
variables.push(`$labels${index}: [String!]!`);
|
||||
conditions[`labels${index}`] = labels;
|
||||
}
|
||||
variables.push(`$condition${index}: MetricsCondition!`);
|
||||
conditions[`condition${index}`] = {
|
||||
name,
|
||||
entity,
|
||||
};
|
||||
}
|
||||
}
|
||||
if (metricType === MetricQueryTypes.ReadLabeledMetricsValues) {
|
||||
return `${name}${index}: ${metricType}(condition: $condition${index}, labels: $labels${index}, duration: $duration)${RespFields[metricType]}`;
|
||||
@@ -125,6 +149,7 @@ export function useQueryProcessor(config: any) {
|
||||
}
|
||||
});
|
||||
const queryStr = `query queryData(${variables}) {${fragment}}`;
|
||||
|
||||
return {
|
||||
queryStr,
|
||||
conditions,
|
||||
@@ -142,6 +167,10 @@ export function useSourceProcessor(
|
||||
ElMessage.error(resp.errors);
|
||||
return {};
|
||||
}
|
||||
if (!resp.data) {
|
||||
ElMessage.error("The query is wrong");
|
||||
return {};
|
||||
}
|
||||
const source: { [key: string]: unknown } = {};
|
||||
const keys = Object.keys(resp.data);
|
||||
|
||||
@@ -150,7 +179,10 @@ export function useSourceProcessor(
|
||||
const c = (config.metricConfig && config.metricConfig[index]) || {};
|
||||
|
||||
if (type === MetricQueryTypes.ReadMetricsValues) {
|
||||
source[m] = calculateExp(resp.data[keys[index]].values.values, c);
|
||||
source[c.label || m] =
|
||||
(resp.data[keys[index]] &&
|
||||
calculateExp(resp.data[keys[index]].values.values, c)) ||
|
||||
[];
|
||||
}
|
||||
if (type === MetricQueryTypes.ReadLabeledMetricsValues) {
|
||||
const resVal = Object.values(resp.data)[0] || [];
|
||||
@@ -176,8 +208,13 @@ export function useSourceProcessor(
|
||||
source[m] = aggregation(Number(Object.values(resp.data)[0]), c);
|
||||
}
|
||||
if (
|
||||
type === MetricQueryTypes.SortMetrics ||
|
||||
type === MetricQueryTypes.ReadSampledRecords
|
||||
(
|
||||
[
|
||||
MetricQueryTypes.ReadRecords,
|
||||
MetricQueryTypes.ReadSampledRecords,
|
||||
MetricQueryTypes.SortMetrics,
|
||||
] as string[]
|
||||
).includes(type)
|
||||
) {
|
||||
source[m] = (Object.values(resp.data)[0] || []).map(
|
||||
(d: { value: unknown; name: string }) => {
|
||||
@@ -218,13 +255,19 @@ export function useSourceProcessor(
|
||||
|
||||
export function useQueryPodsMetrics(
|
||||
pods: Array<Instance | Endpoint | Service | any>,
|
||||
config: { metrics: string[]; metricTypes: string[] },
|
||||
config: {
|
||||
metrics: string[];
|
||||
metricTypes: string[];
|
||||
metricConfig: MetricConfigOpt[];
|
||||
},
|
||||
scope: string
|
||||
) {
|
||||
if (!(config.metrics && config.metrics[0])) {
|
||||
const metricTypes = (config.metricTypes || []).filter((m: string) => m);
|
||||
if (!metricTypes.length) {
|
||||
return;
|
||||
}
|
||||
if (!(config.metricTypes && config.metricTypes[0])) {
|
||||
const metrics = (config.metrics || []).filter((m: string) => m);
|
||||
if (!metrics.length) {
|
||||
return;
|
||||
}
|
||||
const appStore = useAppStoreWithOut();
|
||||
@@ -246,14 +289,24 @@ export function useQueryPodsMetrics(
|
||||
endpointName: scope === "Endpoint" ? d.label : undefined,
|
||||
normal: scope === "Service" ? d.normal : currentService.normal,
|
||||
};
|
||||
const f = config.metrics.map((name: string, idx: number) => {
|
||||
const metricType = config.metricTypes[idx] || "";
|
||||
const f = metrics.map((name: string, idx: number) => {
|
||||
const metricType = metricTypes[idx] || "";
|
||||
variables.push(`$condition${index}${idx}: MetricsCondition!`);
|
||||
conditions[`condition${index}${idx}`] = {
|
||||
name,
|
||||
entity: param,
|
||||
};
|
||||
variables.push(`$condition${index}${idx}: MetricsCondition!`);
|
||||
return `${name}${index}${idx}: ${metricType}(condition: $condition${index}${idx}, duration: $duration)${RespFields[metricType]}`;
|
||||
let labelStr = "";
|
||||
if (metricType === MetricQueryTypes.ReadLabeledMetricsValues) {
|
||||
const c = config.metricConfig[idx] || {};
|
||||
variables.push(`$labels${index}${idx}: [String!]!`);
|
||||
labelStr = `labels: $labels${index}${idx}, `;
|
||||
const labels = (c.labelsIndex || "")
|
||||
.split(",")
|
||||
.map((item: string) => item.replace(/^\s*|\s*$/g, ""));
|
||||
conditions[`labels${index}${idx}`] = labels;
|
||||
}
|
||||
return `${name}${index}${idx}: ${metricType}(condition: $condition${index}${idx}, ${labelStr}duration: $duration)${RespFields[metricType]}`;
|
||||
});
|
||||
return f;
|
||||
}
|
||||
@@ -263,6 +316,7 @@ export function useQueryPodsMetrics(
|
||||
|
||||
return { queryStr, conditions };
|
||||
}
|
||||
|
||||
export function usePodsSource(
|
||||
pods: Array<Instance | Endpoint>,
|
||||
resp: { errors: string; data: { [key: string]: any } },
|
||||
@@ -276,12 +330,20 @@ export function usePodsSource(
|
||||
ElMessage.error(resp.errors);
|
||||
return {};
|
||||
}
|
||||
const names: string[] = [];
|
||||
const metricConfigArr: MetricConfigOpt[] = [];
|
||||
const metricTypesArr: string[] = [];
|
||||
const data = pods.map((d: Instance | any, idx: number) => {
|
||||
config.metrics.map((name: string, index: number) => {
|
||||
const c: any = (config.metricConfig && config.metricConfig[index]) || {};
|
||||
const key = name + idx + index;
|
||||
if (config.metricTypes[index] === MetricQueryTypes.ReadMetricsValue) {
|
||||
d[name] = aggregation(resp.data[key], c);
|
||||
if (idx === 0) {
|
||||
names.push(name);
|
||||
metricConfigArr.push(c);
|
||||
metricTypesArr.push(config.metricTypes[index]);
|
||||
}
|
||||
}
|
||||
if (config.metricTypes[index] === MetricQueryTypes.ReadMetricsValues) {
|
||||
d[name] = {};
|
||||
@@ -297,12 +359,56 @@ export function usePodsSource(
|
||||
d[name]["values"] = resp.data[key].values.values.map(
|
||||
(val: { value: number }) => aggregation(val.value, c)
|
||||
);
|
||||
if (idx === 0) {
|
||||
names.push(name);
|
||||
metricConfigArr.push(c);
|
||||
metricTypesArr.push(config.metricTypes[index]);
|
||||
}
|
||||
}
|
||||
if (
|
||||
config.metricTypes[index] === MetricQueryTypes.ReadLabeledMetricsValues
|
||||
) {
|
||||
const resVal = resp.data[key] || [];
|
||||
const labels = (c.label || "")
|
||||
.split(",")
|
||||
.map((item: string) => item.replace(/^\s*|\s*$/g, ""));
|
||||
const labelsIdx = (c.labelsIndex || "")
|
||||
.split(",")
|
||||
.map((item: string) => item.replace(/^\s*|\s*$/g, ""));
|
||||
for (let i = 0; i < resVal.length; i++) {
|
||||
const item = resVal[i];
|
||||
const values = item.values.values.map((d: { value: number }) =>
|
||||
aggregation(Number(d.value), c)
|
||||
);
|
||||
const indexNum = labelsIdx.findIndex((d: string) => d === item.label);
|
||||
let key = item.label;
|
||||
if (labels[indexNum] && indexNum > -1) {
|
||||
key = labels[indexNum];
|
||||
}
|
||||
if (!d[key]) {
|
||||
d[key] = {};
|
||||
}
|
||||
if (
|
||||
[
|
||||
Calculations.Average,
|
||||
Calculations.ApdexAvg,
|
||||
Calculations.PercentageAvg,
|
||||
].includes(c.calculation)
|
||||
) {
|
||||
d[key]["avg"] = calculateExp(item.values.values, c);
|
||||
}
|
||||
d[key]["values"] = values;
|
||||
if (idx === 0) {
|
||||
names.push(key);
|
||||
metricConfigArr.push({ ...c, index: i });
|
||||
metricTypesArr.push(config.metricTypes[index]);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return d;
|
||||
});
|
||||
return data;
|
||||
return { data, names, metricConfigArr, metricTypesArr };
|
||||
}
|
||||
export function useQueryTopologyMetrics(metrics: string[], ids: string[]) {
|
||||
const appStore = useAppStoreWithOut();
|
||||
@@ -377,23 +483,26 @@ export function aggregation(
|
||||
data = (val / 1024 / 1024 / 1024).toFixed(2);
|
||||
break;
|
||||
case Calculations.Apdex:
|
||||
data = val / 10000;
|
||||
break;
|
||||
case Calculations.ApdexAvg:
|
||||
data = val / 10000;
|
||||
data = (val / 10000).toFixed(2);
|
||||
break;
|
||||
case Calculations.ConvertSeconds:
|
||||
data = dayjs(val).format("YYYY-MM-DD HH:mm:ss");
|
||||
data = dayjs(val * 1000).format("YYYY-MM-DD HH:mm:ss");
|
||||
break;
|
||||
case Calculations.ConvertMilliseconds:
|
||||
data = dayjs.unix(val).format("YYYY-MM-DD HH:mm:ss");
|
||||
data = dayjs(val).format("YYYY-MM-DD HH:mm:ss");
|
||||
break;
|
||||
case Calculations.Precision:
|
||||
data = data.toFixed(2);
|
||||
break;
|
||||
case Calculations.MsTos:
|
||||
case Calculations.MsToS:
|
||||
data = (val / 1000).toFixed(2);
|
||||
break;
|
||||
case Calculations.SecondToDay:
|
||||
data = (val / 86400).toFixed(2);
|
||||
break;
|
||||
case Calculations.NanosecondToMillisecond:
|
||||
data = (val / 1000 / 1000).toFixed(2);
|
||||
break;
|
||||
default:
|
||||
data;
|
||||
break;
|
||||
@@ -412,6 +521,7 @@ export async function useGetMetricEntity(metric: string, metricType: any) {
|
||||
[
|
||||
MetricQueryTypes.ReadSampledRecords,
|
||||
MetricQueryTypes.SortMetrics,
|
||||
MetricQueryTypes.ReadRecords,
|
||||
].includes(metricType)
|
||||
) {
|
||||
const res = await dashboardStore.fetchMetricList(metric);
|
@@ -13,12 +13,12 @@ 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="nav-bar flex-h" :class="{ dark: theme === 'dark' }">
|
||||
<div class="nav-bar flex-h">
|
||||
<div class="title">{{ appStore.pageTitle || t(pageName) }}</div>
|
||||
<div class="app-config">
|
||||
<span class="red" v-show="timeRange">{{ t("timeTips") }}</span>
|
||||
<TimePicker
|
||||
:value="time"
|
||||
:value="[appStore.durationRow.start, appStore.durationRow.end]"
|
||||
position="bottom"
|
||||
format="YYYY-MM-DD HH:mm"
|
||||
@input="changeTimeRange"
|
||||
@@ -49,7 +49,7 @@ limitations under the License. -->
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref, watch, computed } from "vue";
|
||||
import { ref, watch } from "vue";
|
||||
import { useRoute } from "vue-router";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import timeFormat from "@/utils/timeFormat";
|
||||
@@ -61,23 +61,20 @@ const appStore = useAppStoreWithOut();
|
||||
const route = useRoute();
|
||||
const pageName = ref<string>("");
|
||||
const timeRange = ref<number>(0);
|
||||
const theme = ref<string>("light");
|
||||
|
||||
resetDuration();
|
||||
getVersion();
|
||||
const setConfig = (value: string) => {
|
||||
pageName.value = value || "";
|
||||
// theme.value = route.path.includes("/infrastructure/") ? "dark" : "light";
|
||||
};
|
||||
const time = computed(() => [
|
||||
appStore.durationRow.start,
|
||||
appStore.durationRow.end,
|
||||
]);
|
||||
const handleReload = () => {
|
||||
|
||||
function handleReload() {
|
||||
const gap =
|
||||
appStore.duration.end.getTime() - appStore.duration.start.getTime();
|
||||
const time: Date[] = [new Date(new Date().getTime() - gap), new Date()];
|
||||
appStore.setDuration(timeFormat(time));
|
||||
};
|
||||
const dates: Date[] = [new Date(new Date().getTime() - gap), new Date()];
|
||||
appStore.setDuration(timeFormat(dates));
|
||||
}
|
||||
|
||||
function changeTimeRange(val: Date[] | any) {
|
||||
timeRange.value =
|
||||
val[1].getTime() - val[0].getTime() > 60 * 24 * 60 * 60 * 1000 ? 1 : 0;
|
||||
@@ -99,6 +96,19 @@ async function getVersion() {
|
||||
ElMessage.error(res.errors);
|
||||
}
|
||||
}
|
||||
function resetDuration() {
|
||||
const { duration }: any = route.params;
|
||||
if (duration) {
|
||||
const d = JSON.parse(duration);
|
||||
|
||||
appStore.updateDurationRow({
|
||||
start: new Date(d.start),
|
||||
end: new Date(d.end),
|
||||
step: d.step,
|
||||
});
|
||||
appStore.updateUTC(d.utc);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.nav-bar {
|
||||
|
@@ -33,11 +33,7 @@ limitations under the License. -->
|
||||
<template v-for="(menu, index) in routes" :key="index">
|
||||
<el-sub-menu :index="String(menu.name)" v-if="menu.meta.hasGroup">
|
||||
<template #title>
|
||||
<router-link
|
||||
class="items"
|
||||
:to="menu.path"
|
||||
:exact="menu.meta.exact || false"
|
||||
>
|
||||
<router-link class="items" :to="menu.path">
|
||||
<el-icon class="menu-icons" :style="{ marginRight: '12px' }">
|
||||
<Icon size="lg" :iconName="menu.meta.icon" />
|
||||
</el-icon>
|
||||
@@ -52,12 +48,8 @@ limitations under the License. -->
|
||||
:index="m.name"
|
||||
:key="idx"
|
||||
>
|
||||
<router-link
|
||||
class="items"
|
||||
:to="m.path"
|
||||
:exact="m.meta.exact || false"
|
||||
>
|
||||
<span class="title">{{ t(m.meta.title) }}</span>
|
||||
<router-link class="items" :to="m.path">
|
||||
<span class="title">{{ m.meta && t(m.meta.title) }}</span>
|
||||
</router-link>
|
||||
</el-menu-item>
|
||||
</el-menu-item-group>
|
||||
@@ -68,20 +60,12 @@ limitations under the License. -->
|
||||
v-else
|
||||
>
|
||||
<el-icon class="menu-icons" :style="{ marginRight: '12px' }">
|
||||
<router-link
|
||||
class="items"
|
||||
:to="menu.children[0].path"
|
||||
:exact="menu.meta.exact"
|
||||
>
|
||||
<router-link class="items" :to="menu.children[0].path">
|
||||
<Icon size="lg" :iconName="menu.meta.icon" />
|
||||
</router-link>
|
||||
</el-icon>
|
||||
<template #title>
|
||||
<router-link
|
||||
class="items"
|
||||
:to="menu.children[0].path"
|
||||
:exact="menu.meta.exact"
|
||||
>
|
||||
<router-link class="items" :to="menu.children[0].path">
|
||||
<span class="title">{{ t(menu.meta.title) }}</span>
|
||||
</router-link>
|
||||
</template>
|
||||
@@ -123,7 +107,7 @@ if (/Android|webOS|iPhone|iPod|iPad|BlackBerry/i.test(navigator.userAgent)) {
|
||||
} else {
|
||||
appStore.setIsMobile(false);
|
||||
}
|
||||
const isCollapse = ref(appStore.isMobile ? true : false);
|
||||
const isCollapse = ref(false);
|
||||
const controlMenu = () => {
|
||||
isCollapse.value = !isCollapse.value;
|
||||
};
|
||||
@@ -141,13 +125,13 @@ const filterMenus = (menus: any[]) => {
|
||||
.side-bar {
|
||||
background: #252a2f;
|
||||
height: 100%;
|
||||
min-height: 700px;
|
||||
position: relative;
|
||||
margin-bottom: 100px;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
.el-menu-vertical:not(.el-menu--collapse) {
|
||||
width: 200px;
|
||||
width: 220px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
@@ -173,7 +157,7 @@ span.collapse {
|
||||
.menu-control {
|
||||
position: absolute;
|
||||
top: 7px;
|
||||
left: 200px;
|
||||
left: 220px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s linear;
|
||||
z-index: 99;
|
||||
|
@@ -32,6 +32,7 @@ const msg = {
|
||||
dashboards: "Dashboards",
|
||||
profiles: "Profiles",
|
||||
database: "Database",
|
||||
mySQL: "MySQL",
|
||||
serviceName: "Service Name",
|
||||
technologies: "Technologies",
|
||||
generalServicePanel: "General Service Panel",
|
||||
@@ -51,17 +52,19 @@ const msg = {
|
||||
instance: "Instance",
|
||||
create: "Create",
|
||||
loading: "Loading",
|
||||
selectVisualization: "Visualize your metrics",
|
||||
selectVisualization: "Visualize Metrics",
|
||||
visualization: "Visualization",
|
||||
graphStyles: "Graph styles",
|
||||
widgetOptions: "Widget options",
|
||||
standardOptions: "Standard options",
|
||||
graphStyles: "Graph Styles",
|
||||
widgetOptions: "Widget Options",
|
||||
standardOptions: "Standard Options",
|
||||
max: "Max",
|
||||
min: "Min",
|
||||
plus: "Plus",
|
||||
mean: "Mean",
|
||||
minus: "Minus",
|
||||
multiply: "Multiply",
|
||||
divide: "Divide",
|
||||
total: "Total",
|
||||
convertToMilliseconds: "Convert Unix Timestamp(milliseconds)",
|
||||
convertToSeconds: "Convert Unix Timestamp(seconds)",
|
||||
smooth: "Smooth",
|
||||
@@ -107,6 +110,7 @@ const msg = {
|
||||
showXAxis: "Show X Axis",
|
||||
showYAxis: "Show Y Axis",
|
||||
nameError: "The dashboard name cannot be duplicate",
|
||||
nameEmptyError: "The dashboard name cannot be empty",
|
||||
showGroup: "Show Group",
|
||||
noRoot: "Please set a root dashboard for",
|
||||
noWidget: "Please add widgets.",
|
||||
@@ -122,6 +126,7 @@ const msg = {
|
||||
editWarning: "You are entering edit mode",
|
||||
viewWarning: "You are entering view mode",
|
||||
virtualDatabase: "Virtual Database",
|
||||
virtualCache: "Virtual Cache",
|
||||
reloadDashboards: "Reload dashboards",
|
||||
kubernetesService: "Service",
|
||||
kubernetesCluster: "Cluster",
|
||||
@@ -142,6 +147,40 @@ const msg = {
|
||||
interval: "Refresh Interval",
|
||||
pause: "Pause",
|
||||
begin: "Start",
|
||||
associateOptions: "Association Options",
|
||||
associateMetrics: "Association Metrics",
|
||||
widget: "Widget",
|
||||
nameTip:
|
||||
"The name only supports Chinese and English, horizontal lines and underscores. The length of the name is limited to 300 characters",
|
||||
duplicateName: "Duplicate name",
|
||||
enableAssociate: "Enable association",
|
||||
text: "Text",
|
||||
query: "Query",
|
||||
postgreSQL: "PostgreSQL",
|
||||
endpointTips: "The table shows up to 20 pieces of endpoints.",
|
||||
apisix: "APISIX",
|
||||
viewTrace: "View Related Traces",
|
||||
relatedTraceOptions: "Related Trace Options",
|
||||
setLatencyDuration: "Latency Related Metrics",
|
||||
queryOrder: "Query By Duration",
|
||||
setOrder: "Query Order",
|
||||
latency: "Latency",
|
||||
metricValues: "Metric Values",
|
||||
queryConditions: "Query Conditions",
|
||||
enableRelatedTrace: "Enable Related Trace",
|
||||
maxTraceDuration: "Maximum Duration",
|
||||
minTraceDuration: "Minimum Duration",
|
||||
legendOptions: "Legend Options",
|
||||
showLegend: "Show Legend",
|
||||
asTable: "As Table",
|
||||
toTheRight: "To The Right",
|
||||
legendValues: "Legend Values",
|
||||
minDuration: "Minimal Request Duration",
|
||||
when4xx:
|
||||
"Sample HTTP requests and responses with tracing when response code between 400 and 499",
|
||||
when5xx:
|
||||
"Sample HTTP requests and responses with tracing when response code between 500 and 599",
|
||||
taskTitle: "HTTP request and response collecting rules",
|
||||
seconds: "Seconds",
|
||||
hourTip: "Select Hour",
|
||||
minuteTip: "Select Minute",
|
||||
@@ -151,8 +190,6 @@ const msg = {
|
||||
monthsHead: "Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec",
|
||||
months: "Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec",
|
||||
weeks: "Mon_Tue_Wed_Thu_Fri_Sat_Sun",
|
||||
hello: "Hello",
|
||||
helloMessage: "Welcome Back, Apache SkyWalking APM System !",
|
||||
username: "Username",
|
||||
password: "Password",
|
||||
title: "Title",
|
||||
@@ -161,7 +198,7 @@ const msg = {
|
||||
dashboard: "Dashboard",
|
||||
topology: "Topology",
|
||||
trace: "Trace",
|
||||
alarm: "Alarms",
|
||||
alarm: "Alerting",
|
||||
auto: "Auto",
|
||||
reload: "Reload",
|
||||
version: "Version",
|
||||
@@ -236,7 +273,7 @@ const msg = {
|
||||
entityType: "Entity Type",
|
||||
maxItemNum: "Max number of Item",
|
||||
unknownMetrics: "Unknown Metrics",
|
||||
labels: "Labels",
|
||||
labels: "Label",
|
||||
aggregation: "Calculation",
|
||||
unit: "Unit",
|
||||
labelsIndex: "Label Subscript",
|
||||
@@ -297,6 +334,7 @@ const msg = {
|
||||
eventsParameters: "Event Parameters",
|
||||
eventDetail: "Event Detail",
|
||||
value: "Value",
|
||||
key: "Key",
|
||||
show: "Show",
|
||||
hide: "Hide",
|
||||
statistics: "Statistics",
|
||||
@@ -335,5 +373,7 @@ const msg = {
|
||||
conditionNotice:
|
||||
"Notice: Please press Enter after inputting a key of content, exclude key of content(key=value).",
|
||||
language: "Language",
|
||||
gateway: "Gateway",
|
||||
virtualMQ: "Virtual MQ",
|
||||
};
|
||||
export default msg;
|
||||
|
@@ -32,6 +32,7 @@ const msg = {
|
||||
dashboards: "Paneles",
|
||||
profiles: "Perfiles",
|
||||
database: "Base de Datos",
|
||||
mySQL: "MySQL",
|
||||
serviceName: "Nombre Servicio",
|
||||
technologies: "Tecnologías",
|
||||
generalServicePanel: "Panel Servicio General",
|
||||
@@ -58,9 +59,11 @@ const msg = {
|
||||
standardOptions: "Opciones estandar",
|
||||
max: "Máx",
|
||||
min: "Mín",
|
||||
mean: "Promedio",
|
||||
plus: "Más",
|
||||
minus: "Menoss",
|
||||
multiply: "Multiplcar",
|
||||
total: "Todo",
|
||||
divide: "Dividir",
|
||||
convertToMilliseconds: "Convertir Unix Timestamp(milisegundos)",
|
||||
convertToSeconds: "Convertir Unix Timestamp(segundos)",
|
||||
@@ -109,6 +112,7 @@ const msg = {
|
||||
showXAxis: "Mostrar Eje X",
|
||||
showYAxis: "Mostrar Eje Y",
|
||||
nameError: "El nombre del panel no puede ser duplicado",
|
||||
nameEmptyError: "El nombre del panel no puede estar vacío",
|
||||
showGroup: "Mostrar Grupo",
|
||||
noRoot: "Por favor ponga la raíz del panel",
|
||||
noWidget: "Por favor añada widgets.",
|
||||
@@ -124,6 +128,7 @@ const msg = {
|
||||
editWarning: "Estás entrando en modo edición",
|
||||
viewWarning: "Estás entrando en modo visualización",
|
||||
virtualDatabase: "Base de Datos Virtual",
|
||||
virtualCache: "Caché virtual",
|
||||
reloadDashboards: "Recargar Panel",
|
||||
kubernetesService: "Servicio",
|
||||
kubernetesCluster: "Cluster",
|
||||
@@ -142,17 +147,49 @@ const msg = {
|
||||
interval: "Intervalo de actualización",
|
||||
pause: "Pausa",
|
||||
begin: "Inicio",
|
||||
associateOptions: "Opciones de asociación",
|
||||
associateMetrics: "Índice de correlación",
|
||||
widget: "Dispositivo pequeño",
|
||||
text: "Texto",
|
||||
duplicateName: "Nombre duplicado",
|
||||
nameTip:
|
||||
"El nombre sólo admite chino e inglés, líneas horizontales y subrayado, y la longitud del nombre no excederá de 300 caracteres",
|
||||
enableAssociate: "Activar asociación",
|
||||
query: "Consulta",
|
||||
postgreSQL: "PostgreSQL",
|
||||
endpointTips: "Aquí, la tabla muestra hasta 20 punto final.",
|
||||
apisix: "APISIX",
|
||||
queryOrder: "Consulta por duración",
|
||||
setOrder: "Orden de consulta",
|
||||
latency: "Retraso",
|
||||
metricValues: "Valor métrico",
|
||||
legendValues: "Valor de la leyenda",
|
||||
seconds: "Segundos",
|
||||
hourTip: "Seleccione Hora",
|
||||
minuteTip: "Seleccione Minuto",
|
||||
secondTip: "Seleccione Segundo",
|
||||
viewTrace: "Ver trazas relacionadas",
|
||||
relatedTraceOptions: "Opciones de seguimiento relacionadas",
|
||||
setLatencyDuration: "Índice de correlación retardada",
|
||||
enableRelatedTrace: "Activar trazas relacionadas",
|
||||
queryConditions: "Condiciones de consulta",
|
||||
maxTraceDuration: "Duración máxima",
|
||||
minTraceDuration: "Duración mínima",
|
||||
legendOptions: "Opciones de leyenda",
|
||||
showLegend: "Mostrar leyenda",
|
||||
asTable: "Como tabla",
|
||||
toTheRight: "Derecha",
|
||||
minDuration: "Duración mínima de la solicitud",
|
||||
when4xx:
|
||||
"Ejemplo de solicitud y respuesta http con seguimiento cuando el Código de respuesta está entre 400 y 499",
|
||||
when5xx:
|
||||
"Ejemplo de solicitud y respuesta http con seguimiento cuando el Código de respuesta está entre 500 y 599",
|
||||
taskTitle: "Reglas de recolección de peticiones y respuestas HTTP",
|
||||
second: "s",
|
||||
yearSuffix: "Año",
|
||||
monthsHead: "Ene_Feb_Mar_Abr_May_Jun_Jul_Ago_Set_Oct_Nov_Dic",
|
||||
months: "Ene_Feb_Mar_Abr_May_Jun_Jul_Ago_Set_Oct_Nov_Dic",
|
||||
weeks: "Lun_Mar_Mier_Jue_Vie_Sáb_Dom",
|
||||
hello: "Hola",
|
||||
helloMessage: "Bienvenido de vuelta, Apache SkyWalking APM System !",
|
||||
username: "Usuario",
|
||||
password: "Contraseña",
|
||||
title: "Título",
|
||||
@@ -161,7 +198,7 @@ const msg = {
|
||||
dashboard: "Panel",
|
||||
topology: "Topología",
|
||||
trace: "Traza",
|
||||
alarm: "Alarmas",
|
||||
alarm: "Recordatorio en curso",
|
||||
auto: "Auto",
|
||||
reload: "Recargar",
|
||||
version: "Versión",
|
||||
@@ -297,6 +334,7 @@ const msg = {
|
||||
eventsParameters: "Parámetro del Evento",
|
||||
eventDetail: "Detalle del Evento",
|
||||
value: "Valor",
|
||||
key: "Clave",
|
||||
show: "Mostrar",
|
||||
hide: "Oculatr",
|
||||
statistics: "Estadísticas",
|
||||
@@ -338,5 +376,7 @@ const msg = {
|
||||
conditionNotice:
|
||||
"Aviso: Por favor presione Intro después de introducir una clave de contenido, excluir clave de contenido(clave=valor).",
|
||||
language: "Lenguaje",
|
||||
gateway: "Puerta",
|
||||
virtualMQ: "MQ virtual",
|
||||
};
|
||||
export default msg;
|
||||
|
@@ -32,6 +32,7 @@ const msg = {
|
||||
dashboards: "仪表盘",
|
||||
profiles: "性能剖析",
|
||||
database: "数据库",
|
||||
mySQL: "MySQL",
|
||||
serviceName: "服务名称",
|
||||
technologies: "技术",
|
||||
health: "健康",
|
||||
@@ -55,10 +56,12 @@ const msg = {
|
||||
standardOptions: "标准选项",
|
||||
max: "最大值",
|
||||
min: "最小值",
|
||||
mean: "平均值",
|
||||
plus: "加法",
|
||||
minus: "减法",
|
||||
multiply: "乘法",
|
||||
divide: "除法",
|
||||
total: "总计",
|
||||
convertToMilliseconds: "转换Unix时间戳(毫秒)",
|
||||
convertToSeconds: "转换Unix时间戳(秒)",
|
||||
smooth: "光滑的",
|
||||
@@ -105,6 +108,7 @@ const msg = {
|
||||
showXAxis: "显示X轴",
|
||||
showYAxis: "显示Y轴",
|
||||
nameError: "仪表板名称不能重复",
|
||||
nameEmptyError: "仪表板名称不能为空",
|
||||
noRoot: "请设置根仪表板,为",
|
||||
showGroup: "显示分组",
|
||||
noWidget: "请添加组件",
|
||||
@@ -120,6 +124,7 @@ const msg = {
|
||||
editWarning: "你正在进入编辑模式",
|
||||
viewWarning: "你正在进入预览模式",
|
||||
virtualDatabase: "虚拟数据库",
|
||||
virtualCache: "虚拟缓存",
|
||||
reloadDashboards: "重新加载仪表盘",
|
||||
kubernetesService: "服务",
|
||||
kubernetesCluster: "集群",
|
||||
@@ -140,6 +145,37 @@ const msg = {
|
||||
interval: "刷新间隔时间",
|
||||
pause: "暂停",
|
||||
begin: "开始",
|
||||
associateOptions: "关联选项",
|
||||
associateMetrics: "关联指标",
|
||||
widget: "部件",
|
||||
enableAssociate: "启用关联",
|
||||
nameTip: "该名称仅支持中文和英文、横线和下划线, 并且限制长度为300个字符",
|
||||
duplicateName: "重复的名称",
|
||||
text: "文本",
|
||||
query: "查询",
|
||||
postgreSQL: "PostgreSQL",
|
||||
endpointTips: "这里最多展示20条endpoints。",
|
||||
apisix: "APISIX",
|
||||
viewTrace: "查看相关Trace",
|
||||
relatedTraceOptions: "相关的Trace选项",
|
||||
setLatencyDuration: "延迟相关指标",
|
||||
queryOrder: "按持续时间查询",
|
||||
setOrder: "查询顺序",
|
||||
latency: "延迟",
|
||||
metricValues: "指标值",
|
||||
enableRelatedTrace: "启用相关Trace",
|
||||
queryConditions: "查询条件",
|
||||
maxTraceDuration: "最大持续时间",
|
||||
minTraceDuration: "最小持续时间",
|
||||
legendOptions: "图例选项",
|
||||
showLegend: "显示图例",
|
||||
asTable: "作为表格",
|
||||
toTheRight: "在右边",
|
||||
legendValues: "图例值",
|
||||
minDuration: "最小请求持续时间",
|
||||
when4xx: "当响应代码介于400和499之间时,带有跟踪的HTTP请求和响应示例",
|
||||
when5xx: "当响应代码介于500和599之间时,带有跟踪的HTTP请求和响应示例",
|
||||
taskTitle: "HTTP请求和响应收集规则",
|
||||
seconds: "秒",
|
||||
hourTip: "选择小时",
|
||||
minuteTip: "选择分钟",
|
||||
@@ -149,8 +185,6 @@ const msg = {
|
||||
monthsHead: "1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月",
|
||||
months: "一月_二月_三月_四月_五月_六月_七月_八月_九月_十月_十一月_十二月",
|
||||
weeks: "一_二_三_四_五_六_日",
|
||||
hello: "你好",
|
||||
helloMessage: "欢迎来到, Apache SkyWalking APM 系统 !",
|
||||
username: "用户名",
|
||||
password: "密码",
|
||||
title: "标题",
|
||||
@@ -296,6 +330,7 @@ const msg = {
|
||||
eventsParameters: "事件参数",
|
||||
eventDetail: "事件详情",
|
||||
value: "数值",
|
||||
key: "Key",
|
||||
tableHeader: "表头名称",
|
||||
tableValues: "表值",
|
||||
show: "展示",
|
||||
@@ -336,5 +371,7 @@ const msg = {
|
||||
conditionNotice:
|
||||
"请输入一个内容关键词或者内容不包含的关键词(key=value)之后回车",
|
||||
language: "语言",
|
||||
gateway: "网关",
|
||||
virtualMQ: "虚拟消息队列",
|
||||
};
|
||||
export default msg;
|
||||
|
@@ -25,18 +25,14 @@ export const routesAlarm: Array<RouteRecordRaw> = [
|
||||
title: "alarm",
|
||||
icon: "spam",
|
||||
hasGroup: false,
|
||||
exact: true,
|
||||
},
|
||||
component: Layout,
|
||||
children: [
|
||||
{
|
||||
path: "/alarm",
|
||||
path: "/alerting",
|
||||
name: "Alarm",
|
||||
meta: {
|
||||
exact: false,
|
||||
},
|
||||
component: () =>
|
||||
import(/* webpackChunkName: "alarms" */ "@/views/Alarm.vue"),
|
||||
import(/* webpackChunkName: "alerting" */ "@/views/Alarm.vue"),
|
||||
},
|
||||
],
|
||||
},
|
||||
|
@@ -26,7 +26,6 @@ export const routesDashboard: Array<RouteRecordRaw> = [
|
||||
title: "dashboards",
|
||||
icon: "dashboard_customize",
|
||||
hasGroup: true,
|
||||
exact: true,
|
||||
},
|
||||
children: [
|
||||
{
|
||||
@@ -38,7 +37,6 @@ export const routesDashboard: Array<RouteRecordRaw> = [
|
||||
name: "List",
|
||||
meta: {
|
||||
title: "dashboardList",
|
||||
exact: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -50,73 +48,198 @@ export const routesDashboard: Array<RouteRecordRaw> = [
|
||||
name: "New",
|
||||
meta: {
|
||||
title: "dashboardNew",
|
||||
exact: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
path: "/dashboard/:layerId/:entity/:name",
|
||||
path: "",
|
||||
redirect: "/dashboard/:layerId/:entity/:name",
|
||||
name: "Create",
|
||||
component: () =>
|
||||
import(
|
||||
/* webpackChunkName: "dashboards" */ "@/views/dashboard/Edit.vue"
|
||||
),
|
||||
name: "Create",
|
||||
meta: {
|
||||
title: "dashboardEdit",
|
||||
exact: false,
|
||||
notShow: true,
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: "/dashboard/:layerId/:entity/:name",
|
||||
component: () =>
|
||||
import(
|
||||
/* webpackChunkName: "dashboards" */ "@/views/dashboard/Edit.vue"
|
||||
),
|
||||
name: "CreateChild",
|
||||
},
|
||||
{
|
||||
path: "/dashboard/:layerId/:entity/:name/tab/:activeTabIndex",
|
||||
component: () =>
|
||||
import(
|
||||
/* webpackChunkName: "dashboards" */ "@/views/dashboard/Edit.vue"
|
||||
),
|
||||
name: "CreateActiveTabIndex",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: "/dashboard/:layerId/:entity/:serviceId/:name",
|
||||
path: "",
|
||||
component: () =>
|
||||
import(
|
||||
/* webpackChunkName: "dashboards" */ "@/views/dashboard/Edit.vue"
|
||||
),
|
||||
name: "View",
|
||||
redirect: "/dashboard/:layerId/:entity/:serviceId/:name",
|
||||
meta: {
|
||||
title: "dashboardEdit",
|
||||
exact: false,
|
||||
notShow: true,
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: "/dashboard/:layerId/:entity/:serviceId/:name",
|
||||
component: () =>
|
||||
import(
|
||||
/* webpackChunkName: "dashboards" */ "@/views/dashboard/Edit.vue"
|
||||
),
|
||||
name: "ViewChild",
|
||||
},
|
||||
{
|
||||
path: "/dashboard/:layerId/:entity/:serviceId/:name/tab/:activeTabIndex",
|
||||
component: () =>
|
||||
import(
|
||||
/* webpackChunkName: "dashboards" */ "@/views/dashboard/Edit.vue"
|
||||
),
|
||||
name: "ViewActiveTabIndex",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: "/dashboard/related/:layerId/:entity/:serviceId/:destServiceId/:name",
|
||||
path: "",
|
||||
redirect:
|
||||
"/dashboard/related/:layerId/:entity/:serviceId/:destServiceId/:name",
|
||||
component: () =>
|
||||
import(
|
||||
/* webpackChunkName: "dashboards" */ "@/views/dashboard/Edit.vue"
|
||||
),
|
||||
name: "ViewServiceRelation",
|
||||
meta: {
|
||||
title: "dashboardEdit",
|
||||
exact: false,
|
||||
notShow: true,
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: "/dashboard/related/:layerId/:entity/:serviceId/:destServiceId/:name",
|
||||
component: () =>
|
||||
import(
|
||||
/* webpackChunkName: "dashboards" */ "@/views/dashboard/Edit.vue"
|
||||
),
|
||||
name: "ViewServiceRelation",
|
||||
},
|
||||
{
|
||||
path: "/dashboard/related/:layerId/:entity/:serviceId/:destServiceId/:name/tab/:activeTabIndex",
|
||||
component: () =>
|
||||
import(
|
||||
/* webpackChunkName: "dashboards" */ "@/views/dashboard/Edit.vue"
|
||||
),
|
||||
name: "ViewServiceRelationActiveTabIndex",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: "/dashboard/:layerId/:entity/:serviceId/:podId/:name",
|
||||
path: "",
|
||||
redirect: "/dashboard/:layerId/:entity/:serviceId/:podId/:name",
|
||||
component: () =>
|
||||
import(
|
||||
/* webpackChunkName: "dashboards" */ "@/views/dashboard/Edit.vue"
|
||||
),
|
||||
name: "ViewPod",
|
||||
meta: {
|
||||
title: "dashboardEdit",
|
||||
exact: false,
|
||||
notShow: true,
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: "/dashboard/:layerId/:entity/:serviceId/:podId/:name",
|
||||
component: () =>
|
||||
import(
|
||||
/* webpackChunkName: "dashboards" */ "@/views/dashboard/Edit.vue"
|
||||
),
|
||||
name: "ViewPod",
|
||||
},
|
||||
{
|
||||
path: "/dashboard/:layerId/:entity/:serviceId/:podId/:name/tab/:activeTabIndex",
|
||||
component: () =>
|
||||
import(
|
||||
/* webpackChunkName: "dashboards" */ "@/views/dashboard/Edit.vue"
|
||||
),
|
||||
name: "ViewPodActiveTabIndex",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: "/dashboard/:layerId/:entity/:serviceId/:podId/:destServiceId/:destPodId/:name",
|
||||
path: "",
|
||||
redirect:
|
||||
"/dashboard/:layerId/:entity/:serviceId/:podId/:destServiceId/:destPodId/:name",
|
||||
component: () =>
|
||||
import(
|
||||
/* webpackChunkName: "dashboards" */ "@/views/dashboard/Edit.vue"
|
||||
),
|
||||
name: "ViewPodRelation",
|
||||
name: "PodRelation",
|
||||
meta: {
|
||||
title: "dashboardEdit",
|
||||
exact: true,
|
||||
notShow: true,
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: "/dashboard/:layerId/:entity/:serviceId/:podId/:destServiceId/:destPodId/:name",
|
||||
component: () =>
|
||||
import(
|
||||
/* webpackChunkName: "dashboards" */ "@/views/dashboard/Edit.vue"
|
||||
),
|
||||
name: "ViewPodRelation",
|
||||
},
|
||||
{
|
||||
path: "/dashboard/:layerId/:entity/:serviceId/:podId/:destServiceId/:destPodId/:name/tab/:activeTabIndex",
|
||||
component: () =>
|
||||
import(
|
||||
/* webpackChunkName: "dashboards" */ "@/views/dashboard/Edit.vue"
|
||||
),
|
||||
name: "ViewPodRelationActiveTabIndex",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: "",
|
||||
redirect:
|
||||
"/dashboard/:layerId/:entity/:serviceId/:podId/:processId/:destServiceId/:destPodId/:destProcessId/:name",
|
||||
component: () =>
|
||||
import(
|
||||
/* webpackChunkName: "dashboards" */ "@/views/dashboard/Edit.vue"
|
||||
),
|
||||
name: "ProcessRelation",
|
||||
meta: {
|
||||
notShow: true,
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: "/dashboard/:layerId/:entity/:serviceId/:podId/:processId/:destServiceId/:destPodId/:destProcessId/:name",
|
||||
component: () =>
|
||||
import(
|
||||
/* webpackChunkName: "dashboards" */ "@/views/dashboard/Edit.vue"
|
||||
),
|
||||
name: "ViewProcessRelation",
|
||||
},
|
||||
{
|
||||
path: "/dashboard/:layerId/:entity/:serviceId/:podId/:processId/:destServiceId/:destPodId/:destProcessId/:name/tab/:activeTabIndex",
|
||||
component: () =>
|
||||
import(
|
||||
/* webpackChunkName: "dashboards" */ "@/views/dashboard/Edit.vue"
|
||||
),
|
||||
name: "ViewProcessRelationActiveTabIndex",
|
||||
},
|
||||
{
|
||||
path: "/dashboard/:layerId/:entity/:serviceId/:podId/:processId/:destServiceId/:destPodId/:destProcessId/:name/duration/:duration",
|
||||
component: () =>
|
||||
import(
|
||||
/* webpackChunkName: "dashboards" */ "@/views/dashboard/Edit.vue"
|
||||
),
|
||||
name: "ViewProcessRelationDuration",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
@@ -14,10 +14,8 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { RouteRecordRaw } from "vue-router";
|
||||
import Layout from "@/layout/Index.vue";
|
||||
|
||||
export const routesBrowser: Array<RouteRecordRaw> = [
|
||||
export default [
|
||||
{
|
||||
path: "",
|
||||
name: "Browser",
|
||||
@@ -26,18 +24,22 @@ export const routesBrowser: Array<RouteRecordRaw> = [
|
||||
icon: "language",
|
||||
},
|
||||
redirect: "/browser",
|
||||
component: Layout,
|
||||
children: [
|
||||
{
|
||||
path: "/browser",
|
||||
name: "Browser",
|
||||
meta: {
|
||||
title: "browser",
|
||||
headPath: "/browser",
|
||||
exact: true,
|
||||
layer: "BROWSER",
|
||||
},
|
||||
},
|
||||
{
|
||||
path: "/browser/tab/:activeTabIndex",
|
||||
name: "BrowserActiveTabIndex",
|
||||
meta: {
|
||||
notShow: true,
|
||||
layer: "BROWSER",
|
||||
},
|
||||
component: () =>
|
||||
import(/* webpackChunkName: "layer" */ "@/views/Layer.vue"),
|
||||
},
|
||||
],
|
||||
},
|
63
src/router/data/database.ts
Normal file
@@ -0,0 +1,63 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export default [
|
||||
{
|
||||
path: "",
|
||||
name: "Database",
|
||||
meta: {
|
||||
title: "database",
|
||||
icon: "storage",
|
||||
hasGroup: true,
|
||||
},
|
||||
redirect: "/mySQL",
|
||||
children: [
|
||||
{
|
||||
path: "/mySQL",
|
||||
name: "MySQL",
|
||||
meta: {
|
||||
title: "mySQL",
|
||||
layer: "MYSQL",
|
||||
},
|
||||
},
|
||||
{
|
||||
path: "/mySQL/tab/:activeTabIndex",
|
||||
name: "MySQLActiveTabIndex",
|
||||
meta: {
|
||||
notShow: true,
|
||||
layer: "MYSQL",
|
||||
},
|
||||
},
|
||||
{
|
||||
path: "/postgreSQL",
|
||||
name: "PostgreSQL",
|
||||
meta: {
|
||||
title: "postgreSQL",
|
||||
layer: "POSTGRESQL",
|
||||
},
|
||||
},
|
||||
{
|
||||
path: "/postgreSQL/tab/:activeTabIndex",
|
||||
name: "PostgreSQLActiveTabIndex",
|
||||
meta: {
|
||||
notShow: true,
|
||||
layer: "POSTGRESQL",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
@@ -14,30 +14,25 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { RouteRecordRaw } from "vue-router";
|
||||
import Layout from "@/layout/Index.vue";
|
||||
|
||||
export const routesFunctions: Array<RouteRecordRaw> = [
|
||||
export default [
|
||||
{
|
||||
path: "",
|
||||
name: "Functions",
|
||||
meta: {
|
||||
title: "functions",
|
||||
icon: "cloud_queue",
|
||||
layer: "FAAS",
|
||||
},
|
||||
redirect: "/functions",
|
||||
component: Layout,
|
||||
children: [
|
||||
{
|
||||
path: "/functions",
|
||||
name: "Functions",
|
||||
meta: {
|
||||
title: "functions",
|
||||
headPath: "/functions",
|
||||
exact: true,
|
||||
},
|
||||
component: () =>
|
||||
import(/* webpackChunkName: "layer" */ "@/views/Layer.vue"),
|
||||
},
|
||||
{
|
||||
path: "/functions/tab/:activeTabIndex",
|
||||
name: "FunctionsActiveTabIndex",
|
||||
},
|
||||
],
|
||||
},
|
@@ -14,29 +14,33 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { RouteRecordRaw } from "vue-router";
|
||||
import Layout from "@/layout/Index.vue";
|
||||
|
||||
export const routesEvent: Array<RouteRecordRaw> = [
|
||||
export default [
|
||||
{
|
||||
path: "",
|
||||
name: "Events",
|
||||
name: "Gateway",
|
||||
meta: {
|
||||
title: "events",
|
||||
icon: "av_timer",
|
||||
hasGroup: false,
|
||||
exact: true,
|
||||
title: "gateway",
|
||||
icon: "gateway",
|
||||
hasGroup: true,
|
||||
},
|
||||
component: Layout,
|
||||
redirect: "/apisix",
|
||||
children: [
|
||||
{
|
||||
path: "/events",
|
||||
name: "Events",
|
||||
path: "/apisix",
|
||||
name: "APISIX",
|
||||
meta: {
|
||||
exact: false,
|
||||
title: "apisix",
|
||||
layer: "APISIX",
|
||||
},
|
||||
},
|
||||
{
|
||||
path: "/apisix/tab/:activeTabIndex",
|
||||
name: "APISIXActiveTabIndex",
|
||||
meta: {
|
||||
notShow: true,
|
||||
layer: "APISIX",
|
||||
},
|
||||
component: () =>
|
||||
import(/* webpackChunkName: "events" */ "@/views/Event.vue"),
|
||||
},
|
||||
],
|
||||
},
|
94
src/router/data/general.ts
Normal file
@@ -0,0 +1,94 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export default [
|
||||
{
|
||||
path: "",
|
||||
name: "General",
|
||||
meta: {
|
||||
title: "general",
|
||||
icon: "chart",
|
||||
hasGroup: true,
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: "/general",
|
||||
name: "GeneralServices",
|
||||
meta: {
|
||||
title: "services",
|
||||
layer: "GENERAL",
|
||||
},
|
||||
},
|
||||
{
|
||||
path: "/general/tab/:activeTabIndex",
|
||||
name: "GeneralServicesActiveTabIndex",
|
||||
meta: {
|
||||
notShow: true,
|
||||
layer: "GENERAL",
|
||||
},
|
||||
},
|
||||
{
|
||||
path: "/database",
|
||||
name: "VirtualDatabase",
|
||||
meta: {
|
||||
title: "virtualDatabase",
|
||||
layer: "VIRTUAL_DATABASE",
|
||||
},
|
||||
},
|
||||
{
|
||||
path: "/database/tab/:activeTabIndex",
|
||||
name: "VirtualDatabaseActiveTabIndex",
|
||||
meta: {
|
||||
notShow: true,
|
||||
layer: "VIRTUAL_DATABASE",
|
||||
},
|
||||
},
|
||||
{
|
||||
path: "/cache",
|
||||
name: "VirtualCache",
|
||||
meta: {
|
||||
title: "virtualCache",
|
||||
layer: "VIRTUAL_CACHE",
|
||||
},
|
||||
},
|
||||
{
|
||||
path: "/cache/tab/:activeTabIndex",
|
||||
name: "VirtualCacheActiveTabIndex",
|
||||
meta: {
|
||||
notShow: true,
|
||||
layer: "VIRTUAL_CACHE",
|
||||
},
|
||||
},
|
||||
{
|
||||
path: "/mq",
|
||||
name: "VirtualMQ",
|
||||
meta: {
|
||||
title: "virtualMQ",
|
||||
layer: "VIRTUAL_MQ",
|
||||
},
|
||||
},
|
||||
{
|
||||
path: "/mq/tab/:activeTabIndex",
|
||||
name: "VirtualMQActiveTabIndex",
|
||||
meta: {
|
||||
notShow: true,
|
||||
layer: "VIRTUAL_MQ",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
37
src/router/data/index.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import general from "./general";
|
||||
import serviceMesh from "./serviceMesh";
|
||||
import database from "./database";
|
||||
import infrastructure from "./infrastructure";
|
||||
import selfObservability from "./selfObservability";
|
||||
import functions from "./functions";
|
||||
import browser from "./browser";
|
||||
import k8s from "./k8s";
|
||||
import gateway from "./gateway";
|
||||
|
||||
export default [
|
||||
...general,
|
||||
...serviceMesh,
|
||||
...functions,
|
||||
...k8s,
|
||||
...infrastructure,
|
||||
...browser,
|
||||
...gateway,
|
||||
...database,
|
||||
...selfObservability,
|
||||
];
|
@@ -14,31 +14,34 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { RouteRecordRaw } from "vue-router";
|
||||
import Layout from "@/layout/Index.vue";
|
||||
|
||||
export const routesDatabase: Array<RouteRecordRaw> = [
|
||||
export default [
|
||||
{
|
||||
path: "",
|
||||
name: "Database",
|
||||
name: "Infrastructure",
|
||||
meta: {
|
||||
title: "database",
|
||||
icon: "storage",
|
||||
title: "infrastructure",
|
||||
icon: "scatter_plot",
|
||||
hasGroup: true,
|
||||
},
|
||||
redirect: "/database",
|
||||
component: Layout,
|
||||
redirect: "/linux",
|
||||
children: [
|
||||
{
|
||||
path: "/database",
|
||||
name: "Database",
|
||||
path: "/linux",
|
||||
name: "Linux",
|
||||
meta: {
|
||||
title: "virtualDatabase",
|
||||
headPath: "/database",
|
||||
exact: true,
|
||||
title: "linux",
|
||||
layer: "OS_LINUX",
|
||||
},
|
||||
},
|
||||
{
|
||||
path: "/linux/tab/:activeTabIndex",
|
||||
name: "LinuxActiveTabIndex",
|
||||
meta: {
|
||||
title: "linux",
|
||||
notShow: true,
|
||||
layer: "OS_LINUX",
|
||||
},
|
||||
component: () =>
|
||||
import(/* webpackChunkName: "layer" */ "@/views/Layer.vue"),
|
||||
},
|
||||
],
|
||||
},
|
@@ -14,10 +14,8 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { RouteRecordRaw } from "vue-router";
|
||||
import Layout from "@/layout/Index.vue";
|
||||
|
||||
export const routesK8s: Array<RouteRecordRaw> = [
|
||||
export default [
|
||||
{
|
||||
path: "",
|
||||
name: "Kubernetes",
|
||||
@@ -27,25 +25,42 @@ export const routesK8s: Array<RouteRecordRaw> = [
|
||||
hasGroup: true,
|
||||
},
|
||||
redirect: "/kubernetes/cluster",
|
||||
component: Layout,
|
||||
children: [
|
||||
{
|
||||
path: "/kubernetes/cluster",
|
||||
name: "KubernetesCluster",
|
||||
meta: {
|
||||
notShow: false,
|
||||
title: "kubernetesCluster",
|
||||
layer: "K8S",
|
||||
},
|
||||
},
|
||||
{
|
||||
path: "/kubernetes/cluster/tab/:activeTabIndex",
|
||||
name: "KubernetesClusterActiveTabIndex",
|
||||
meta: {
|
||||
notShow: true,
|
||||
title: "kubernetesClusterActiveTabIndex",
|
||||
layer: "K8S",
|
||||
},
|
||||
component: () =>
|
||||
import(/* webpackChunkName: "layer" */ "@/views/Layer.vue"),
|
||||
},
|
||||
{
|
||||
path: "/kubernetes/service",
|
||||
name: "KubernetesService",
|
||||
meta: {
|
||||
notShow: false,
|
||||
title: "kubernetesService",
|
||||
layer: "K8S_SERVICE",
|
||||
},
|
||||
},
|
||||
{
|
||||
path: "/kubernetes/service/tab/:activeTabIndex",
|
||||
name: "KubernetesServiceActiveTabIndex",
|
||||
meta: {
|
||||
notShow: true,
|
||||
title: "kubernetesServiceActiveTabIndex",
|
||||
layer: "K8S_SERVICE",
|
||||
},
|
||||
component: () =>
|
||||
import(/* webpackChunkName: "layer" */ "@/views/Layer.vue"),
|
||||
},
|
||||
],
|
||||
},
|
@@ -14,10 +14,8 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { RouteRecordRaw } from "vue-router";
|
||||
import Layout from "@/layout/Index.vue";
|
||||
|
||||
export const routesSelf: Array<RouteRecordRaw> = [
|
||||
export default [
|
||||
{
|
||||
path: "",
|
||||
name: "SelfObservability",
|
||||
@@ -27,27 +25,38 @@ export const routesSelf: Array<RouteRecordRaw> = [
|
||||
icon: "logo",
|
||||
hasGroup: true,
|
||||
},
|
||||
component: Layout,
|
||||
children: [
|
||||
{
|
||||
path: "/self/skyWalkingServer",
|
||||
name: "SkyWalkingServer",
|
||||
meta: {
|
||||
title: "skyWalkingServer",
|
||||
headPath: "/mesh/services",
|
||||
layer: "SO11Y_OAP",
|
||||
},
|
||||
},
|
||||
{
|
||||
path: "/self/skyWalkingServer/tab/:activeTabIndex",
|
||||
name: "SkyWalkingServerActiveTabIndex",
|
||||
meta: {
|
||||
notShow: true,
|
||||
layer: "SO11Y_OAP",
|
||||
},
|
||||
component: () =>
|
||||
import(/* webpackChunkName: "layer" */ "@/views/Layer.vue"),
|
||||
},
|
||||
{
|
||||
path: "/self/satellite",
|
||||
name: "Satellite",
|
||||
meta: {
|
||||
title: "satellite",
|
||||
headPath: "/mesh/controlPanel",
|
||||
layer: "SO11Y_SATELLITE",
|
||||
},
|
||||
},
|
||||
{
|
||||
path: "/self/satellite/tab/:activeTabIndex",
|
||||
name: "SatelliteActiveTabIndex",
|
||||
meta: {
|
||||
notShow: true,
|
||||
layer: "SO11Y_SATELLITE",
|
||||
},
|
||||
component: () =>
|
||||
import(/* webpackChunkName: "layer" */ "@/views/Layer.vue"),
|
||||
},
|
||||
],
|
||||
},
|
@@ -14,10 +14,8 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { RouteRecordRaw } from "vue-router";
|
||||
import Layout from "@/layout/Index.vue";
|
||||
|
||||
export const routesMesh: Array<RouteRecordRaw> = [
|
||||
export default [
|
||||
{
|
||||
path: "",
|
||||
name: "ServiceMesh",
|
||||
@@ -27,36 +25,58 @@ export const routesMesh: Array<RouteRecordRaw> = [
|
||||
icon: "epic",
|
||||
hasGroup: true,
|
||||
},
|
||||
component: Layout,
|
||||
children: [
|
||||
{
|
||||
path: "/mesh/services",
|
||||
name: "MeshServices",
|
||||
meta: {
|
||||
notShow: false,
|
||||
title: "services",
|
||||
headPath: "/mesh/services",
|
||||
layer: "MESH",
|
||||
},
|
||||
},
|
||||
{
|
||||
path: "/mesh/services/tab/:activeTabIndex",
|
||||
name: "MeshServicesActiveTabIndex",
|
||||
meta: {
|
||||
notShow: true,
|
||||
layer: "MESH",
|
||||
},
|
||||
component: () =>
|
||||
import(/* webpackChunkName: "layer" */ "@/views/Layer.vue"),
|
||||
},
|
||||
{
|
||||
path: "/mesh/controlPanel",
|
||||
name: "ControlPanel",
|
||||
meta: {
|
||||
notShow: false,
|
||||
title: "controlPanel",
|
||||
headPath: "/mesh/controlPanel",
|
||||
layer: "MESH_CP",
|
||||
},
|
||||
},
|
||||
{
|
||||
path: "/mesh/controlPanel/tab/:activeTabIndex",
|
||||
name: "ControlPanelActiveTabIndex",
|
||||
meta: {
|
||||
notShow: true,
|
||||
layer: "MESH_CP",
|
||||
},
|
||||
component: () =>
|
||||
import(/* webpackChunkName: "layer" */ "@/views/Layer.vue"),
|
||||
},
|
||||
{
|
||||
path: "/mesh/dataPanel",
|
||||
name: "DataPanel",
|
||||
meta: {
|
||||
notShow: false,
|
||||
title: "dataPanel",
|
||||
headPath: "/mesh/dataPanel",
|
||||
layer: "MESH_DP",
|
||||
},
|
||||
},
|
||||
{
|
||||
path: "/mesh/dataPanel/tab/:activeTabIndex",
|
||||
name: "DataPanelActiveTabIndex",
|
||||
meta: {
|
||||
notShow: true,
|
||||
title: "dataPanelActiveTabIndex",
|
||||
layer: "MESH_DP",
|
||||
},
|
||||
component: () => import("@/views/Layer.vue"),
|
||||
},
|
||||
],
|
||||
},
|
@@ -15,31 +15,15 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { createRouter, createWebHistory, RouteRecordRaw } from "vue-router";
|
||||
import { routesGen } from "./general";
|
||||
import { routesMesh } from "./serviceMesh";
|
||||
import { routesDatabase } from "./database";
|
||||
import { routesInfra } from "./infrastructure";
|
||||
import { routesDashboard } from "./dashboard";
|
||||
import { routesEvent } from "./event";
|
||||
import { routesSetting } from "./setting";
|
||||
import { routesAlarm } from "./alarm";
|
||||
import { routesSelf } from "./selfObservability";
|
||||
import { routesFunctions } from "./functions";
|
||||
import { routesBrowser } from "./browser";
|
||||
import { routesK8s } from "./k8s";
|
||||
import routesLayers from "./layer";
|
||||
|
||||
const routes: Array<RouteRecordRaw> = [
|
||||
...routesGen,
|
||||
...routesMesh,
|
||||
...routesFunctions,
|
||||
...routesK8s,
|
||||
...routesInfra,
|
||||
...routesBrowser,
|
||||
...routesDatabase,
|
||||
...routesSelf,
|
||||
...routesLayers,
|
||||
...routesDashboard,
|
||||
...routesAlarm,
|
||||
...routesEvent,
|
||||
...routesSetting,
|
||||
];
|
||||
|
||||
|
@@ -1,60 +0,0 @@
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { RouteRecordRaw } from "vue-router";
|
||||
import Layout from "@/layout/Index.vue";
|
||||
|
||||
export const routesInfra: Array<RouteRecordRaw> = [
|
||||
{
|
||||
path: "",
|
||||
name: "Infrastructure",
|
||||
meta: {
|
||||
title: "infrastructure",
|
||||
icon: "scatter_plot",
|
||||
exact: true,
|
||||
hasGroup: true,
|
||||
},
|
||||
redirect: "/linux",
|
||||
component: Layout,
|
||||
children: [
|
||||
{
|
||||
path: "/linux",
|
||||
name: "Linux",
|
||||
meta: {
|
||||
title: "linux",
|
||||
},
|
||||
component: () =>
|
||||
import(/* webpackChunkName: "layer" */ "@/views/Layer.vue"),
|
||||
},
|
||||
// {
|
||||
// path: "/infrastructure/vm",
|
||||
// name: "VirtualMachine",
|
||||
// meta: {
|
||||
// title: "virtualMachine",
|
||||
// },
|
||||
// component: () => import("@/views/infrastructure/Infrastructure.vue"),
|
||||
// },
|
||||
// {
|
||||
// path: "/infrastructure/k8s",
|
||||
// name: "Kubernetes",
|
||||
// meta: {
|
||||
// title: "kubernetes",
|
||||
// },
|
||||
// component: () => import("@/views/infrastructure/Infrastructure.vue"),
|
||||
// },
|
||||
],
|
||||
},
|
||||
];
|
@@ -14,32 +14,22 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { RouteRecordRaw } from "vue-router";
|
||||
import LayerJson from "./data";
|
||||
import Layout from "@/layout/Index.vue";
|
||||
|
||||
export const routesGen: Array<RouteRecordRaw> = [
|
||||
{
|
||||
path: "",
|
||||
name: "General",
|
||||
meta: {
|
||||
title: "general",
|
||||
icon: "chart",
|
||||
hasGroup: false,
|
||||
exact: true,
|
||||
},
|
||||
component: Layout,
|
||||
children: [
|
||||
{
|
||||
path: "/general",
|
||||
name: "GeneralServices",
|
||||
meta: {
|
||||
title: "services",
|
||||
headPath: "/general/service",
|
||||
exact: true,
|
||||
},
|
||||
component: () =>
|
||||
import(/* webpackChunkName: "layers" */ "@/views/Layer.vue"),
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
function layerDashboards() {
|
||||
const routes = LayerJson.map((item: any) => {
|
||||
item.component = Layout;
|
||||
if (item.children) {
|
||||
item.children = item.children.map((d: any) => {
|
||||
d.component = () =>
|
||||
import(/* webpackChunkName: "layer" */ "@/views/Layer.vue");
|
||||
return d;
|
||||
});
|
||||
}
|
||||
return item;
|
||||
});
|
||||
return routes;
|
||||
}
|
||||
|
||||
export default layerDashboards();
|
@@ -25,7 +25,6 @@ export const routesSetting: Array<RouteRecordRaw> = [
|
||||
title: "settings",
|
||||
icon: "settings",
|
||||
hasGroup: false,
|
||||
exact: false,
|
||||
},
|
||||
component: Layout,
|
||||
children: [
|
||||
@@ -36,7 +35,6 @@ export const routesSetting: Array<RouteRecordRaw> = [
|
||||
title: "settings",
|
||||
icon: "settings",
|
||||
hasGroup: false,
|
||||
exact: false,
|
||||
},
|
||||
component: () =>
|
||||
import(/* webpackChunkName: "settings" */ "@/views/Settings.vue"),
|
||||
|
@@ -29,3 +29,11 @@ export const TextConfig = {
|
||||
fontSize: 14,
|
||||
textAlign: "left",
|
||||
};
|
||||
|
||||
export const TimeRangeConfig = {
|
||||
fontColor: "black",
|
||||
backgroundColor: "white",
|
||||
fontSize: 14,
|
||||
textAlign: "center",
|
||||
text: "text",
|
||||
};
|
||||
|
@@ -34,6 +34,7 @@ interface AppState {
|
||||
pageTitle: string;
|
||||
version: string;
|
||||
isMobile: boolean;
|
||||
reloadTimer: Nullable<any>;
|
||||
}
|
||||
|
||||
export const appStore = defineStore({
|
||||
@@ -53,6 +54,7 @@ export const appStore = defineStore({
|
||||
pageTitle: "",
|
||||
version: "",
|
||||
isMobile: false,
|
||||
reloadTimer: null,
|
||||
}),
|
||||
getters: {
|
||||
duration(): Duration {
|
||||
@@ -69,7 +71,7 @@ export const appStore = defineStore({
|
||||
step: this.duration.step,
|
||||
};
|
||||
},
|
||||
intervalTime(): string[] {
|
||||
intervalUnix(): number[] {
|
||||
let interval = 946080000000;
|
||||
switch (this.duration.step) {
|
||||
case "MINUTE":
|
||||
@@ -95,12 +97,17 @@ export const appStore = defineStore({
|
||||
this.utcMin * 60000;
|
||||
const startUnix: number = this.duration.start.getTime();
|
||||
const endUnix: number = this.duration.end.getTime();
|
||||
const timeIntervals: string[] = [];
|
||||
const timeIntervals: number[] = [];
|
||||
for (let i = 0; i <= endUnix - startUnix; i += interval) {
|
||||
const temp: string = dateFormatTime(
|
||||
new Date(startUnix + i - utcSpace),
|
||||
this.duration.step
|
||||
);
|
||||
timeIntervals.push(startUnix + i - utcSpace);
|
||||
}
|
||||
return timeIntervals;
|
||||
},
|
||||
intervalTime(): string[] {
|
||||
const arr = this.intervalUnix;
|
||||
const timeIntervals: string[] = [];
|
||||
for (const item of arr) {
|
||||
const temp: string = dateFormatTime(new Date(item), this.duration.step);
|
||||
timeIntervals.push(temp);
|
||||
}
|
||||
return timeIntervals;
|
||||
@@ -117,12 +124,18 @@ export const appStore = defineStore({
|
||||
}
|
||||
this.runEventStack();
|
||||
},
|
||||
updateDurationRow(data: Duration) {
|
||||
this.durationRow = data;
|
||||
},
|
||||
setUTC(utcHour: number, utcMin: number): void {
|
||||
this.runEventStack();
|
||||
this.utcMin = utcMin;
|
||||
this.utcHour = utcHour;
|
||||
this.utc = `${utcHour}:${utcMin}`;
|
||||
},
|
||||
updateUTC(data: string) {
|
||||
this.utc = data;
|
||||
},
|
||||
setIsMobile(mode: boolean) {
|
||||
this.isMobile = mode;
|
||||
},
|
||||
@@ -153,10 +166,9 @@ export const appStore = defineStore({
|
||||
.params({});
|
||||
if (res.data.errors) {
|
||||
this.utc = -(new Date().getTimezoneOffset() / 60) + ":0";
|
||||
return res.data;
|
||||
} else {
|
||||
this.utc = res.data.data.getTimeInfo.timezone / 100 + ":0";
|
||||
}
|
||||
this.utc = res.data.data.getTimeInfo.timezone / 100 + ":0";
|
||||
|
||||
const utcArr = this.utc.split(":");
|
||||
this.utcHour = isNaN(Number(utcArr[0])) ? 0 : Number(utcArr[0]);
|
||||
this.utcMin = isNaN(Number(utcArr[1])) ? 0 : Number(utcArr[1]);
|
||||
@@ -173,6 +185,9 @@ export const appStore = defineStore({
|
||||
this.version = res.data.data.version;
|
||||
return res.data;
|
||||
},
|
||||
setReloadTimer(timer: any): void {
|
||||
this.reloadTimer = timer;
|
||||
},
|
||||
},
|
||||
});
|
||||
export function useAppStoreWithOut(): any {
|
||||
|
@@ -21,7 +21,7 @@ import graphql from "@/graphql";
|
||||
import query from "@/graphql/fetch";
|
||||
import { DashboardItem } from "@/types/dashboard";
|
||||
import { useSelectorStore } from "@/store/modules/selectors";
|
||||
import { NewControl, TextConfig } from "../data";
|
||||
import { NewControl, TextConfig, TimeRangeConfig } from "../data";
|
||||
import { AxiosResponse } from "axios";
|
||||
import { ElMessage } from "element-plus";
|
||||
import { useI18n } from "vue-i18n";
|
||||
@@ -39,6 +39,7 @@ interface DashboardState {
|
||||
dashboards: DashboardItem[];
|
||||
currentDashboard: Nullable<DashboardItem>;
|
||||
editMode: boolean;
|
||||
currentTabIndex: number;
|
||||
}
|
||||
|
||||
export const dashboardStore = defineStore({
|
||||
@@ -56,6 +57,7 @@ export const dashboardStore = defineStore({
|
||||
dashboards: [],
|
||||
currentDashboard: null,
|
||||
editMode: false,
|
||||
currentTabIndex: 0,
|
||||
}),
|
||||
actions: {
|
||||
setLayout(data: LayoutConfig[]) {
|
||||
@@ -80,6 +82,7 @@ export const dashboardStore = defineStore({
|
||||
const newItem: LayoutConfig = {
|
||||
...NewControl,
|
||||
i: index,
|
||||
id: index,
|
||||
type,
|
||||
metricTypes: [""],
|
||||
metrics: [""],
|
||||
@@ -111,11 +114,14 @@ export const dashboardStore = defineStore({
|
||||
};
|
||||
}
|
||||
if (
|
||||
type === "Trace" ||
|
||||
type === "Profile" ||
|
||||
type === "Log" ||
|
||||
type === "Ebpf" ||
|
||||
type === "DemandLog"
|
||||
[
|
||||
"Trace",
|
||||
"Profile",
|
||||
"Log",
|
||||
"DemandLog",
|
||||
"Ebpf",
|
||||
"NetworkProfiling",
|
||||
].includes(type)
|
||||
) {
|
||||
newItem.h = 36;
|
||||
}
|
||||
@@ -123,6 +129,11 @@ export const dashboardStore = defineStore({
|
||||
newItem.h = 6;
|
||||
newItem.graph = TextConfig;
|
||||
}
|
||||
if (type === "TimeRange") {
|
||||
newItem.w = 8;
|
||||
newItem.h = 6;
|
||||
newItem.graph = TimeRangeConfig;
|
||||
}
|
||||
this.activedGridItem = newItem.i;
|
||||
this.selectedGrid = newItem;
|
||||
this.layout = this.layout.map((d: LayoutConfig) => {
|
||||
@@ -158,9 +169,11 @@ export const dashboardStore = defineStore({
|
||||
if (!children.length) {
|
||||
index = "0";
|
||||
}
|
||||
const id = `${activedGridItem}-${tabIndex}-${index}`;
|
||||
const newItem: LayoutConfig = {
|
||||
...NewControl,
|
||||
i: index,
|
||||
id,
|
||||
type,
|
||||
metricTypes: [""],
|
||||
metrics: [""],
|
||||
@@ -172,11 +185,14 @@ export const dashboardStore = defineStore({
|
||||
};
|
||||
}
|
||||
if (
|
||||
type === "Trace" ||
|
||||
type === "Profile" ||
|
||||
type === "Log" ||
|
||||
type === "DemandLog" ||
|
||||
type === "Ebpf"
|
||||
[
|
||||
"Trace",
|
||||
"Profile",
|
||||
"Log",
|
||||
"DemandLog",
|
||||
"Ebpf",
|
||||
"NetworkProfiling",
|
||||
].includes(type)
|
||||
) {
|
||||
newItem.h = 32;
|
||||
}
|
||||
@@ -184,6 +200,11 @@ export const dashboardStore = defineStore({
|
||||
newItem.h = 6;
|
||||
newItem.graph = TextConfig;
|
||||
}
|
||||
if (type === "TimeRange") {
|
||||
newItem.w = 8;
|
||||
newItem.h = 6;
|
||||
newItem.graph = TextConfig;
|
||||
}
|
||||
if (this.layout[idx].children) {
|
||||
const items = children.map((d: LayoutConfig) => {
|
||||
d.y = d.y + newItem.h;
|
||||
@@ -198,6 +219,7 @@ export const dashboardStore = defineStore({
|
||||
this.activedGridItem = index;
|
||||
},
|
||||
setActiveTabIndex(index: number, target?: number) {
|
||||
this.currentTabIndex = index;
|
||||
const m = target || this.activedGridItem;
|
||||
const idx = this.layout.findIndex((d: LayoutConfig) => d.i === m);
|
||||
if (idx < 0) {
|
||||
@@ -287,6 +309,28 @@ export const dashboardStore = defineStore({
|
||||
};
|
||||
this.selectedGrid = this.layout[index];
|
||||
},
|
||||
setWidget(param: LayoutConfig) {
|
||||
for (let i = 0; i < this.layout.length; i++) {
|
||||
if (this.layout[i].type === "Tab") {
|
||||
if (this.layout[i].children && this.layout[i].children.length) {
|
||||
for (const child of this.layout[i].children) {
|
||||
if (child.children && child.children.length) {
|
||||
for (let c = 0; c < child.children.length; c++) {
|
||||
if (child.children[c].id === param.id) {
|
||||
child.children.splice(c, 1, param);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (this.layout[i].id === param.id) {
|
||||
this.layout.splice(i, 1, param);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
async fetchMetricType(item: string) {
|
||||
const res: AxiosResponse = await graphql
|
||||
.query("queryTypeOfMetrics")
|
||||
|
@@ -25,8 +25,7 @@ import {
|
||||
import { store } from "@/store";
|
||||
import graphql from "@/graphql";
|
||||
import { AxiosResponse } from "axios";
|
||||
|
||||
interface EbpfStore {
|
||||
interface EbpfState {
|
||||
taskList: EBPFTaskList[];
|
||||
eBPFSchedules: EBPFProfilingSchedule[];
|
||||
currentSchedule: EBPFProfilingSchedule | Record<string, never>;
|
||||
@@ -40,7 +39,7 @@ interface EbpfStore {
|
||||
|
||||
export const ebpfStore = defineStore({
|
||||
id: "eBPF",
|
||||
state: (): EbpfStore => ({
|
||||
state: (): EbpfState => ({
|
||||
taskList: [],
|
||||
eBPFSchedules: [],
|
||||
currentSchedule: {},
|
||||
@@ -53,7 +52,7 @@ export const ebpfStore = defineStore({
|
||||
}),
|
||||
actions: {
|
||||
setSelectedTask(task: EBPFTaskList) {
|
||||
this.selectedTask = task;
|
||||
this.selectedTask = task || {};
|
||||
},
|
||||
setCurrentSchedule(s: EBPFProfilingSchedule) {
|
||||
this.currentSchedule = s;
|
||||
@@ -84,22 +83,31 @@ export const ebpfStore = defineStore({
|
||||
if (res.data.errors) {
|
||||
return res.data;
|
||||
}
|
||||
this.getTaskList(param.serviceId);
|
||||
this.getTaskList({
|
||||
serviceId: param.serviceId,
|
||||
targets: ["ON_CPU", "OFF_CPU"],
|
||||
});
|
||||
return res.data;
|
||||
},
|
||||
async getTaskList(serviceId: string) {
|
||||
if (!serviceId) {
|
||||
async getTaskList(params: {
|
||||
serviceId: string;
|
||||
serviceInstanceId: string;
|
||||
targets: string[];
|
||||
}) {
|
||||
if (!params.serviceId) {
|
||||
return new Promise((resolve) => resolve({}));
|
||||
}
|
||||
const res: AxiosResponse = await graphql
|
||||
.query("getEBPFTasks")
|
||||
.params({ serviceId });
|
||||
.params(params);
|
||||
|
||||
this.tip = "";
|
||||
if (res.data.errors) {
|
||||
return res.data;
|
||||
}
|
||||
this.taskList = res.data.data.queryEBPFTasks || [];
|
||||
this.selectedTask = this.taskList[0] || {};
|
||||
this.setSelectedTask(this.selectedTask);
|
||||
if (!this.taskList.length) {
|
||||
return res.data;
|
||||
}
|
||||
|
@@ -19,16 +19,16 @@ import { store } from "@/store";
|
||||
import graphql from "@/graphql";
|
||||
import { AxiosResponse } from "axios";
|
||||
import { Event, QueryEventCondition } from "@/types/events";
|
||||
import { Instance, Endpoint, Service } from "@/types/selector";
|
||||
import { Instance, Endpoint } from "@/types/selector";
|
||||
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||
import { useSelectorStore } from "@/store/modules/selectors";
|
||||
|
||||
interface eventState {
|
||||
loading: boolean;
|
||||
events: Event[];
|
||||
services: Service[];
|
||||
instances: Instance[];
|
||||
endpoints: Endpoint[];
|
||||
condition: QueryEventCondition | any;
|
||||
condition: Nullable<QueryEventCondition>;
|
||||
}
|
||||
|
||||
export const eventStore = defineStore({
|
||||
@@ -36,32 +36,18 @@ export const eventStore = defineStore({
|
||||
state: (): eventState => ({
|
||||
loading: false,
|
||||
events: [],
|
||||
services: [{ value: "", label: "All" }],
|
||||
instances: [{ value: "", label: "All" }],
|
||||
endpoints: [{ value: "", label: "All" }],
|
||||
condition: {
|
||||
paging: { pageNum: 1, pageSize: 15 },
|
||||
},
|
||||
condition: null,
|
||||
}),
|
||||
actions: {
|
||||
setEventCondition(data: any) {
|
||||
this.condition = { ...this.condition, ...data };
|
||||
setEventCondition(data: QueryEventCondition) {
|
||||
this.condition = data;
|
||||
},
|
||||
async getServices(layer: string) {
|
||||
if (!layer) {
|
||||
this.services = [{ value: "", label: "All" }];
|
||||
return new Promise((resolve) => resolve([]));
|
||||
}
|
||||
const res: AxiosResponse = await graphql.query("queryServices").params({
|
||||
layer,
|
||||
});
|
||||
if (res.data.errors) {
|
||||
return res.data;
|
||||
}
|
||||
this.services = res.data.data.services;
|
||||
return res.data;
|
||||
},
|
||||
async getInstances(serviceId: string) {
|
||||
async getInstances() {
|
||||
const serviceId = useSelectorStore().currentService
|
||||
? useSelectorStore().currentService.id
|
||||
: "";
|
||||
const res: AxiosResponse = await graphql.query("queryInstances").params({
|
||||
serviceId,
|
||||
duration: useAppStoreWithOut().durationTime,
|
||||
@@ -75,7 +61,13 @@ export const eventStore = defineStore({
|
||||
];
|
||||
return res.data;
|
||||
},
|
||||
async getEndpoints(serviceId: string) {
|
||||
async getEndpoints() {
|
||||
const serviceId = useSelectorStore().currentService
|
||||
? useSelectorStore().currentService.id
|
||||
: "";
|
||||
if (!serviceId) {
|
||||
return;
|
||||
}
|
||||
const res: AxiosResponse = await graphql.query("queryEndpoints").params({
|
||||
serviceId,
|
||||
duration: useAppStoreWithOut().durationTime,
|
||||
@@ -112,6 +104,9 @@ export const eventStore = defineStore({
|
||||
scope = "Endpoint";
|
||||
}
|
||||
item.scope = scope;
|
||||
if (!item.endTime || item.endTime === item.startTime) {
|
||||
item.endTime = Number(item.startTime) + 60000;
|
||||
}
|
||||
return item;
|
||||
}
|
||||
);
|
||||
|
@@ -53,6 +53,13 @@ export const logStore = defineStore({
|
||||
setLogCondition(data: any) {
|
||||
this.conditions = { ...this.conditions, ...data };
|
||||
},
|
||||
resetState() {
|
||||
this.logs = [];
|
||||
this.conditions = {
|
||||
queryDuration: useAppStoreWithOut().durationTime,
|
||||
paging: { pageNum: 1, pageSize: 15 },
|
||||
};
|
||||
},
|
||||
async getServices(layer: string) {
|
||||
const res: AxiosResponse = await graphql.query("queryServices").params({
|
||||
layer,
|
||||
|
203
src/store/modules/network-profiling.ts
Normal file
@@ -0,0 +1,203 @@
|
||||
/**
|
||||
* 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 { EBPFTaskList, ProcessNode } from "@/types/ebpf";
|
||||
import { store } from "@/store";
|
||||
import graphql from "@/graphql";
|
||||
import { AxiosResponse } from "axios";
|
||||
import { Call } from "@/types/topology";
|
||||
import { LayoutConfig } from "@/types/dashboard";
|
||||
import { ElMessage } from "element-plus";
|
||||
|
||||
interface NetworkProfilingState {
|
||||
networkTasks: EBPFTaskList[];
|
||||
networkTip: string;
|
||||
selectedNetworkTask: Recordable<EBPFTaskList>;
|
||||
nodes: ProcessNode[];
|
||||
calls: Call[];
|
||||
node: Nullable<ProcessNode>;
|
||||
call: Nullable<Call>;
|
||||
metricsLayout: LayoutConfig[];
|
||||
selectedMetric: Nullable<LayoutConfig>;
|
||||
activeMetricIndex: string;
|
||||
aliveNetwork: boolean;
|
||||
loadNodes: boolean;
|
||||
}
|
||||
|
||||
export const networkProfilingStore = defineStore({
|
||||
id: "networkProfiling",
|
||||
state: (): NetworkProfilingState => ({
|
||||
networkTasks: [],
|
||||
networkTip: "",
|
||||
selectedNetworkTask: {},
|
||||
nodes: [],
|
||||
calls: [],
|
||||
node: null,
|
||||
call: null,
|
||||
metricsLayout: [],
|
||||
selectedMetric: null,
|
||||
activeMetricIndex: "",
|
||||
aliveNetwork: false,
|
||||
loadNodes: false,
|
||||
}),
|
||||
actions: {
|
||||
setSelectedNetworkTask(task: EBPFTaskList) {
|
||||
this.selectedNetworkTask = task || {};
|
||||
},
|
||||
setNode(node: Node) {
|
||||
this.node = node;
|
||||
},
|
||||
setLink(link: Call) {
|
||||
this.call = link;
|
||||
},
|
||||
setMetricsLayout(layout: LayoutConfig[]) {
|
||||
this.metricsLayout = layout;
|
||||
},
|
||||
setSelectedMetric(item: LayoutConfig) {
|
||||
this.selectedMetric = item;
|
||||
},
|
||||
setActiveItem(index: string) {
|
||||
this.activeMetricIndex = index;
|
||||
},
|
||||
setTopology(data: { nodes: ProcessNode[]; calls: Call[] }) {
|
||||
const obj = {} as any;
|
||||
let calls = (data.calls || []).reduce((prev: Call[], next: Call) => {
|
||||
if (!obj[next.id]) {
|
||||
obj[next.id] = true;
|
||||
next.value = next.value || 1;
|
||||
for (const node of data.nodes) {
|
||||
if (next.source === node.id) {
|
||||
next.sourceObj = node;
|
||||
}
|
||||
if (next.target === node.id) {
|
||||
next.targetObj = node;
|
||||
}
|
||||
}
|
||||
next.value = next.value || 1;
|
||||
prev.push(next);
|
||||
}
|
||||
return prev;
|
||||
}, []);
|
||||
const param = {} as any;
|
||||
calls = data.calls.reduce((prev: (Call | any)[], next: Call | any) => {
|
||||
if (param[next.targetId + next.sourceId]) {
|
||||
next.lowerArc = true;
|
||||
}
|
||||
param[next.sourceId + next.targetId] = true;
|
||||
next.sourceId = next.source;
|
||||
next.targetId = next.target;
|
||||
next.source = next.sourceObj;
|
||||
next.target = next.targetObj;
|
||||
delete next.sourceObj;
|
||||
delete next.targetObj;
|
||||
prev.push(next);
|
||||
return prev;
|
||||
}, []);
|
||||
this.calls = calls;
|
||||
this.nodes = data.nodes;
|
||||
},
|
||||
async createNetworkTask(
|
||||
instanceId: string,
|
||||
params: {
|
||||
uriRegex: string;
|
||||
when4xx: string;
|
||||
when5xx: string;
|
||||
minDuration: number;
|
||||
}[]
|
||||
) {
|
||||
const res: AxiosResponse = await graphql
|
||||
.query("newNetworkProfiling")
|
||||
.params({
|
||||
request: {
|
||||
instanceId,
|
||||
samplings: params,
|
||||
},
|
||||
});
|
||||
|
||||
if (res.data.errors) {
|
||||
return res.data;
|
||||
}
|
||||
return res.data;
|
||||
},
|
||||
async getTaskList(params: {
|
||||
serviceId: string;
|
||||
serviceInstanceId: string;
|
||||
targets: string[];
|
||||
}) {
|
||||
if (!params.serviceId) {
|
||||
return new Promise((resolve) => resolve({}));
|
||||
}
|
||||
const res: AxiosResponse = await graphql
|
||||
.query("getEBPFTasks")
|
||||
.params(params);
|
||||
|
||||
this.networkTip = "";
|
||||
if (res.data.errors) {
|
||||
return res.data;
|
||||
}
|
||||
this.networkTasks = res.data.data.queryEBPFTasks || [];
|
||||
this.selectedNetworkTask = this.networkTasks[0] || {};
|
||||
this.setSelectedNetworkTask(this.selectedNetworkTask);
|
||||
if (!this.networkTasks.length) {
|
||||
this.nodes = [];
|
||||
this.calls = [];
|
||||
}
|
||||
return res.data;
|
||||
},
|
||||
async keepNetworkProfiling(taskId: string) {
|
||||
if (!taskId) {
|
||||
return new Promise((resolve) => resolve({}));
|
||||
}
|
||||
const res: AxiosResponse = await graphql
|
||||
.query("aliveNetworkProfiling")
|
||||
.params({ taskId });
|
||||
|
||||
this.aliveMessage = "";
|
||||
if (res.data.errors) {
|
||||
return res.data;
|
||||
}
|
||||
this.aliveNetwork = res.data.data.keepEBPFNetworkProfiling.status;
|
||||
if (!this.aliveNetwork) {
|
||||
ElMessage.warning(res.data.data.keepEBPFNetworkProfiling.errorReason);
|
||||
}
|
||||
return res.data;
|
||||
},
|
||||
async getProcessTopology(params: {
|
||||
duration: any;
|
||||
serviceInstanceId: string;
|
||||
}) {
|
||||
this.loadNodes = true;
|
||||
const res: AxiosResponse = await graphql
|
||||
.query("getProcessTopology")
|
||||
.params(params);
|
||||
this.loadNodes = false;
|
||||
if (res.data.errors) {
|
||||
this.nodes = [];
|
||||
this.calls = [];
|
||||
return res.data;
|
||||
}
|
||||
const { topology } = res.data.data;
|
||||
|
||||
this.setTopology(topology);
|
||||
return res.data;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export function useNetworkProfilingStore(): any {
|
||||
return networkProfilingStore(store);
|
||||
}
|
@@ -83,7 +83,7 @@ export const profileStore = defineStore({
|
||||
if (res.data.errors) {
|
||||
return res.data;
|
||||
}
|
||||
this.endpoints = [{ value: "", label: "All" }, ...res.data.data.pods];
|
||||
this.endpoints = res.data.data.pods || [];
|
||||
return res.data;
|
||||
},
|
||||
async getTaskEndpoints(serviceId: string, keyword?: string) {
|
||||
|
@@ -15,7 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { defineStore } from "pinia";
|
||||
import { Service, Instance, Endpoint } from "@/types/selector";
|
||||
import { Service, Instance, Endpoint, Process } from "@/types/selector";
|
||||
import { store } from "@/store";
|
||||
import graphql from "@/graphql";
|
||||
import { AxiosResponse } from "axios";
|
||||
@@ -24,11 +24,15 @@ interface SelectorState {
|
||||
services: Service[];
|
||||
destServices: Service[];
|
||||
pods: Array<Instance | Endpoint>;
|
||||
processes: Process[];
|
||||
destProcesses: Process[];
|
||||
currentService: Nullable<Service>;
|
||||
currentPod: Nullable<Instance | Endpoint>;
|
||||
currentProcess: Nullable<Process>;
|
||||
currentDestService: Nullable<Service>;
|
||||
currentDestPod: Nullable<Instance | Endpoint>;
|
||||
destPods: Array<Instance | Endpoint>;
|
||||
currentDestProcess: Nullable<Process>;
|
||||
}
|
||||
|
||||
export const selectorStore = defineStore({
|
||||
@@ -38,10 +42,14 @@ export const selectorStore = defineStore({
|
||||
destServices: [],
|
||||
pods: [],
|
||||
destPods: [],
|
||||
processes: [],
|
||||
destProcesses: [],
|
||||
currentService: null,
|
||||
currentPod: null,
|
||||
currentProcess: null,
|
||||
currentDestService: null,
|
||||
currentDestPod: null,
|
||||
currentDestProcess: null,
|
||||
}),
|
||||
actions: {
|
||||
setCurrentService(service: Nullable<Service>) {
|
||||
@@ -56,6 +64,18 @@ export const selectorStore = defineStore({
|
||||
setCurrentDestPod(pod: Nullable<Instance | Endpoint>) {
|
||||
this.currentDestPod = pod;
|
||||
},
|
||||
setCurrentProcess(process: Nullable<Process>) {
|
||||
this.currentProcess = process;
|
||||
},
|
||||
setCurrentDestProcess(process: Nullable<Process>) {
|
||||
this.currentDestProcess = process;
|
||||
},
|
||||
setDestPods(pods: Array<Instance | Endpoint>) {
|
||||
this.destPods = pods;
|
||||
},
|
||||
setDestProcesses(processes: Array<Process>) {
|
||||
this.destProcesses = processes;
|
||||
},
|
||||
async fetchLayers(): Promise<AxiosResponse> {
|
||||
const res: AxiosResponse = await graphql.query("queryLayers").params({});
|
||||
|
||||
@@ -93,6 +113,27 @@ export const selectorStore = defineStore({
|
||||
}
|
||||
return res.data;
|
||||
},
|
||||
async getProcesses(param?: {
|
||||
instanceId: string;
|
||||
isRelation: boolean;
|
||||
}): Promise<Nullable<AxiosResponse>> {
|
||||
const instanceId = param ? param.instanceId : this.currentPod?.id;
|
||||
if (!instanceId) {
|
||||
return null;
|
||||
}
|
||||
const res: AxiosResponse = await graphql.query("queryProcesses").params({
|
||||
instanceId,
|
||||
duration: useAppStoreWithOut().durationTime,
|
||||
});
|
||||
if (!res.data.errors) {
|
||||
if (param && param.isRelation) {
|
||||
this.destProcesses = res.data.data.processes || [];
|
||||
return res.data;
|
||||
}
|
||||
this.processes = res.data.data.processes || [];
|
||||
}
|
||||
return res.data;
|
||||
},
|
||||
async getEndpoints(params: {
|
||||
keyword?: string;
|
||||
serviceId?: string;
|
||||
@@ -176,6 +217,25 @@ export const selectorStore = defineStore({
|
||||
this.pods = [res.data.data.endpoint];
|
||||
}
|
||||
|
||||
return res.data;
|
||||
},
|
||||
async getProcess(instanceId: string, isRelation?: boolean) {
|
||||
if (!instanceId) {
|
||||
return;
|
||||
}
|
||||
const res: AxiosResponse = await graphql.query("queryProcess").params({
|
||||
instanceId,
|
||||
});
|
||||
if (!res.data.errors) {
|
||||
if (isRelation) {
|
||||
this.currentDestProcess = res.data.data.process || null;
|
||||
this.destProcesses = [res.data.data.process];
|
||||
return;
|
||||
}
|
||||
this.currentProcess = res.data.data.process || null;
|
||||
this.processes = [res.data.data.process];
|
||||
}
|
||||
|
||||
return res.data;
|
||||
},
|
||||
},
|
||||
|
@@ -23,7 +23,7 @@ import { useSelectorStore } from "@/store/modules/selectors";
|
||||
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||
import { AxiosResponse } from "axios";
|
||||
import query from "@/graphql/fetch";
|
||||
import { useQueryTopologyMetrics } from "@/hooks/useProcessor";
|
||||
import { useQueryTopologyMetrics } from "@/hooks/useMetricsProcessor";
|
||||
import { ElMessage } from "element-plus";
|
||||
|
||||
interface MetricVal {
|
||||
|
@@ -22,6 +22,7 @@ import graphql from "@/graphql";
|
||||
import { AxiosResponse } from "axios";
|
||||
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||
import { useSelectorStore } from "@/store/modules/selectors";
|
||||
import { QueryOrders } from "@/views/dashboard/data";
|
||||
|
||||
interface TraceState {
|
||||
services: Service[];
|
||||
@@ -47,7 +48,7 @@ export const traceStore = defineStore({
|
||||
conditions: {
|
||||
queryDuration: useAppStoreWithOut().durationTime,
|
||||
traceState: "ALL",
|
||||
queryOrder: "BY_START_TIME",
|
||||
queryOrder: QueryOrders[0].value,
|
||||
paging: { pageNum: 1, pageSize: 20 },
|
||||
},
|
||||
traceSpanLogs: [],
|
||||
@@ -63,6 +64,17 @@ export const traceStore = defineStore({
|
||||
setTraceSpans(spans: Span) {
|
||||
this.traceSpans = spans;
|
||||
},
|
||||
resetState() {
|
||||
this.traceSpans = [];
|
||||
this.traceList = [];
|
||||
this.currentTrace = {};
|
||||
this.conditions = {
|
||||
queryDuration: useAppStoreWithOut().durationTime,
|
||||
paging: { pageNum: 1, pageSize: 20 },
|
||||
traceState: "ALL",
|
||||
queryOrder: QueryOrders[0].value,
|
||||
};
|
||||
},
|
||||
async getServices(layer: string) {
|
||||
const res: AxiosResponse = await graphql.query("queryServices").params({
|
||||
layer,
|
||||
@@ -73,6 +85,36 @@ export const traceStore = defineStore({
|
||||
this.services = res.data.data.services;
|
||||
return res.data;
|
||||
},
|
||||
async getService(serviceId: string) {
|
||||
if (!serviceId) {
|
||||
return;
|
||||
}
|
||||
const res: AxiosResponse = await graphql.query("queryService").params({
|
||||
serviceId,
|
||||
});
|
||||
|
||||
return res.data;
|
||||
},
|
||||
async getInstance(instanceId: string) {
|
||||
if (!instanceId) {
|
||||
return;
|
||||
}
|
||||
const res: AxiosResponse = await graphql.query("queryInstance").params({
|
||||
instanceId,
|
||||
});
|
||||
|
||||
return res.data;
|
||||
},
|
||||
async getEndpoint(endpointId: string) {
|
||||
if (!endpointId) {
|
||||
return;
|
||||
}
|
||||
const res: AxiosResponse = await graphql.query("queryEndpoint").params({
|
||||
endpointId,
|
||||
});
|
||||
|
||||
return res.data;
|
||||
},
|
||||
async getInstances(id: string) {
|
||||
const serviceId = this.selectorStore.currentService
|
||||
? this.selectorStore.currentService.id
|
||||
@@ -133,7 +175,8 @@ export const traceStore = defineStore({
|
||||
if (res.data.errors) {
|
||||
return res.data;
|
||||
}
|
||||
this.setTraceSpans(res.data.data.trace.spans || []);
|
||||
const data = res.data.data.trace.spans;
|
||||
this.setTraceSpans(data || []);
|
||||
return res.data;
|
||||
},
|
||||
async getSpanLogs(params: any) {
|
||||
|
@@ -17,6 +17,7 @@
|
||||
import "element-plus/es/components/message/style/css";
|
||||
import "element-plus/es/components/message-box/style/css";
|
||||
import "element-plus/es/components/notification/style/css";
|
||||
import "element-plus/es/components/drawer/style/css";
|
||||
import "./grid.scss";
|
||||
import "./lib.scss";
|
||||
import "./reset.scss";
|
||||
|
@@ -173,7 +173,7 @@
|
||||
}
|
||||
|
||||
.scroll_bar_style::-webkit-scrollbar {
|
||||
width: 9px;
|
||||
width: 4px;
|
||||
height: 4px;
|
||||
background-color: #eee;
|
||||
}
|
||||
|
@@ -139,8 +139,10 @@ pre {
|
||||
padding-left: 56px !important;
|
||||
}
|
||||
|
||||
.el-icon.menu-icons {
|
||||
margin-top: -3px !important;
|
||||
.el-sub-menu__title {
|
||||
.el-icon.menu-icons {
|
||||
margin-top: -5px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.el-switch__label--left {
|
||||
@@ -151,6 +153,55 @@ pre {
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
.el-switch__label * {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.el-drawer__header {
|
||||
margin-bottom: 0;
|
||||
padding-left: 10px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.el-drawer__body {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.switch {
|
||||
margin: 0 5px;
|
||||
}
|
||||
|
||||
div.vis-tooltip {
|
||||
max-width: 600px;
|
||||
overflow: hidden;
|
||||
background-color: #fff !important;
|
||||
white-space: normal !important;
|
||||
font-size: 12px !important;
|
||||
}
|
||||
|
||||
.vis-item {
|
||||
cursor: pointer;
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
.vis-item.Error {
|
||||
background-color: #e66;
|
||||
opacity: 0.8;
|
||||
border-color: #e66;
|
||||
color: #fff !important;
|
||||
}
|
||||
|
||||
.vis-item.Normal {
|
||||
background-color: #fac858;
|
||||
border-color: #fac858;
|
||||
color: #666 !important;
|
||||
}
|
||||
|
||||
.vis-item .vis-item-content {
|
||||
padding: 0 3px !important;
|
||||
}
|
||||
|
||||
.vis-item.vis-selected.Error,
|
||||
.vis-item.vis-selected.Normal {
|
||||
color: #1a1a1a !important;
|
||||
}
|
||||
|
15
src/types/app.d.ts
vendored
@@ -32,3 +32,18 @@ export type Paging = {
|
||||
pageNum: number;
|
||||
pageSize: number;
|
||||
};
|
||||
|
||||
export type EventParams = {
|
||||
componentType: string;
|
||||
seriesType: string;
|
||||
seriesIndex: number;
|
||||
seriesName: string;
|
||||
name: string;
|
||||
dataIndex: number;
|
||||
data: unknown;
|
||||
dataType: string;
|
||||
value: number | Array;
|
||||
color: string;
|
||||
event: any;
|
||||
dataIndex: number;
|
||||
};
|
||||
|
2
src/types/components.d.ts
vendored
@@ -9,6 +9,7 @@ declare module '@vue/runtime-core' {
|
||||
ElCollapse: typeof import('element-plus/es')['ElCollapse']
|
||||
ElCollapseItem: typeof import('element-plus/es')['ElCollapseItem']
|
||||
ElDialog: typeof import('element-plus/es')['ElDialog']
|
||||
ElDrawer: typeof import('element-plus/es')['ElDrawer']
|
||||
ElDropdown: typeof import('element-plus/es')['ElDropdown']
|
||||
ElDropdownItem: typeof import('element-plus/es')['ElDropdownItem']
|
||||
ElDropdownMenu: typeof import('element-plus/es')['ElDropdownMenu']
|
||||
@@ -24,6 +25,7 @@ declare module '@vue/runtime-core' {
|
||||
ElPopover: typeof import('element-plus/es')['ElPopover']
|
||||
ElProgress: typeof import('element-plus/es')['ElProgress']
|
||||
ElRadio: typeof import('element-plus/es')['ElRadio']
|
||||
ElRadioButton: typeof import('element-plus/es')['ElRadioButton']
|
||||
ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup']
|
||||
ElSelect: typeof import('element-plus/es')['ElSelect']
|
||||
ElSlider: typeof import('element-plus/es')['ElSlider']
|
||||
|
55
src/types/dashboard.d.ts
vendored
@@ -1,3 +1,4 @@
|
||||
import { DurationTime } from "@/types/app";
|
||||
/**
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
@@ -36,7 +37,35 @@ export interface LayoutConfig {
|
||||
children?: { name: string; children: LayoutConfig[] }[];
|
||||
activedTabIndex?: number;
|
||||
metricConfig?: MetricConfigOpt[];
|
||||
id?: string;
|
||||
associate?: { widgetId: string }[];
|
||||
eventAssociate?: boolean;
|
||||
filters?: Filters;
|
||||
relatedTrace?: RelatedTrace;
|
||||
}
|
||||
export type RelatedTrace = {
|
||||
duration: DurationTime;
|
||||
status: string;
|
||||
queryOrder: string;
|
||||
latency: boolean;
|
||||
enableRelate: boolean;
|
||||
};
|
||||
|
||||
export type Filters = {
|
||||
dataIndex: number;
|
||||
sourceId: string;
|
||||
isRange?: boolean;
|
||||
duration?: {
|
||||
startTime: string;
|
||||
endTime: string;
|
||||
};
|
||||
traceId?: string;
|
||||
spanId?: string;
|
||||
segmentId?: string;
|
||||
id?: string;
|
||||
queryOrder?: string;
|
||||
status?: string;
|
||||
};
|
||||
|
||||
export type MetricConfigOpt = {
|
||||
unit?: string;
|
||||
@@ -45,9 +74,11 @@ export type MetricConfigOpt = {
|
||||
labelsIndex: string;
|
||||
sortOrder: string;
|
||||
topN?: number;
|
||||
index?: number;
|
||||
};
|
||||
|
||||
export interface WidgetConfig {
|
||||
name?: string;
|
||||
title?: string;
|
||||
tips?: string;
|
||||
}
|
||||
@@ -64,6 +95,7 @@ export type GraphConfig =
|
||||
export interface BarConfig {
|
||||
type?: string;
|
||||
showBackground?: boolean;
|
||||
legend?: LegendOptions;
|
||||
}
|
||||
export interface LineConfig extends AreaConfig {
|
||||
type?: string;
|
||||
@@ -79,6 +111,7 @@ export interface LineConfig extends AreaConfig {
|
||||
export interface AreaConfig {
|
||||
type?: string;
|
||||
opacity?: number;
|
||||
legend?: LegendOptions;
|
||||
}
|
||||
|
||||
export interface CardConfig {
|
||||
@@ -137,3 +170,25 @@ export interface TopologyConfig {
|
||||
depth?: number;
|
||||
showDepth?: boolean;
|
||||
}
|
||||
export type EventParams = {
|
||||
componentType: string;
|
||||
seriesType: string;
|
||||
seriesIndex: number;
|
||||
seriesName: string;
|
||||
name: string;
|
||||
dataIndex: number;
|
||||
data: Record<string, unknown>;
|
||||
dataType: string;
|
||||
value: number | number[];
|
||||
color: string;
|
||||
};
|
||||
export type LegendOptions = {
|
||||
show: boolean;
|
||||
total: boolean;
|
||||
min: boolean;
|
||||
max: boolean;
|
||||
mean: boolean;
|
||||
asTable: boolean;
|
||||
toTheRight: boolean;
|
||||
width: number;
|
||||
};
|
||||
|
32
src/types/ebpf.d.ts
vendored
@@ -15,6 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Process } from "./selector";
|
||||
export interface EBPFTaskCreationRequest {
|
||||
serviceId: string;
|
||||
processLabels: string[];
|
||||
@@ -43,18 +44,7 @@ export interface EBPFProfilingSchedule {
|
||||
startTime: number;
|
||||
}
|
||||
|
||||
export type Process = {
|
||||
id: string;
|
||||
name: string;
|
||||
serviceId: string;
|
||||
serviceName: string;
|
||||
instanceId: string;
|
||||
instanceName: string;
|
||||
agentId: string;
|
||||
detectType: string;
|
||||
attributes: { name: string; value: string }[];
|
||||
labels: string[];
|
||||
};
|
||||
export type Process = Process;
|
||||
export type StackElement = {
|
||||
id: string;
|
||||
originId: string;
|
||||
@@ -75,3 +65,21 @@ export type AnalyzationTrees = {
|
||||
dumpCount: number;
|
||||
stackType: string;
|
||||
};
|
||||
export type ProcessNode = {
|
||||
id: string;
|
||||
name: string;
|
||||
serviceId: string;
|
||||
serviceName: string;
|
||||
serviceInstanceId: string;
|
||||
serviceInstanceName: string;
|
||||
name: string;
|
||||
isReal: boolean;
|
||||
x?: number;
|
||||
y?: number;
|
||||
};
|
||||
export interface NetworkProfilingRequest {
|
||||
uriRegex: string;
|
||||
when4xx: string;
|
||||
when5xx: string;
|
||||
minDuration: number;
|
||||
}
|
||||
|
13
src/types/selector.d.ts
vendored
@@ -46,3 +46,16 @@ export type Service = {
|
||||
layers: string[];
|
||||
shortName: string;
|
||||
};
|
||||
|
||||
export type Process = {
|
||||
id: string;
|
||||
name: string;
|
||||
serviceId: string;
|
||||
serviceName: string;
|
||||
instanceId: string;
|
||||
instanceName: string;
|
||||
agentId: string;
|
||||
detectType: string;
|
||||
attributes: { name: string; value: string }[];
|
||||
labels: string[];
|
||||
};
|
||||
|
3
src/types/topology.d.ts
vendored
@@ -23,6 +23,9 @@ export interface Call {
|
||||
sourceObj?: any;
|
||||
targetObj?: any;
|
||||
value?: number;
|
||||
lowerArc?: boolean;
|
||||
sourceComponents: string[];
|
||||
targetComponents: string[];
|
||||
}
|
||||
export interface Node {
|
||||
id: string;
|
||||
|
17
src/types/trace.d.ts
vendored
@@ -14,7 +14,6 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export interface Trace {
|
||||
duration: number;
|
||||
isError: boolean;
|
||||
@@ -85,3 +84,19 @@ export class TraceTreeRef {
|
||||
segmentMap: Map<string, Span>;
|
||||
segmentIdGroup: string[];
|
||||
}
|
||||
|
||||
type Instant = {
|
||||
seconds: number;
|
||||
nanos: number;
|
||||
};
|
||||
type KeyValue = {
|
||||
key: string;
|
||||
value: string | number;
|
||||
};
|
||||
export interface SpanAttachedEvent {
|
||||
startTime: Instant;
|
||||
endTime: Instant;
|
||||
event: string;
|
||||
tags: KeyValue[];
|
||||
summary: KeyValue[];
|
||||
}
|
||||
|
@@ -14,6 +14,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import dayjs from "dayjs";
|
||||
export default function dateFormatStep(
|
||||
date: Date,
|
||||
step: string,
|
||||
@@ -99,3 +100,6 @@ export const dateFormatTime = (date: Date, step: string): string => {
|
||||
}
|
||||
return "";
|
||||
};
|
||||
|
||||
export const dateFormat = (date: number, pattern = "YYYY-MM-DD HH:mm:ss") =>
|
||||
dayjs(new Date(date)).format(pattern);
|
||||
|
@@ -16,13 +16,7 @@
|
||||
*/
|
||||
import * as echarts from "echarts/core";
|
||||
|
||||
import {
|
||||
BarChart,
|
||||
LineChart,
|
||||
PieChart,
|
||||
HeatmapChart,
|
||||
SankeyChart,
|
||||
} from "echarts/charts";
|
||||
import { BarChart, LineChart, HeatmapChart, SankeyChart } from "echarts/charts";
|
||||
|
||||
import {
|
||||
TitleComponent,
|
||||
@@ -32,6 +26,7 @@ import {
|
||||
DataZoomComponent,
|
||||
VisualMapComponent,
|
||||
TimelineComponent,
|
||||
MarkAreaComponent,
|
||||
} from "echarts/components";
|
||||
|
||||
import { SVGRenderer } from "echarts/renderers";
|
||||
@@ -43,13 +38,13 @@ echarts.use([
|
||||
GridComponent,
|
||||
BarChart,
|
||||
LineChart,
|
||||
PieChart,
|
||||
HeatmapChart,
|
||||
SankeyChart,
|
||||
SVGRenderer,
|
||||
DataZoomComponent,
|
||||
VisualMapComponent,
|
||||
TimelineComponent,
|
||||
MarkAreaComponent,
|
||||
]);
|
||||
|
||||
export default echarts;
|
||||
|
@@ -24,7 +24,7 @@ import Header from "./alarm/Header.vue";
|
||||
import Content from "./alarm/Content.vue";
|
||||
|
||||
const appStore = useAppStoreWithOut();
|
||||
appStore.setPageTitle("Alarm");
|
||||
appStore.setPageTitle("Alerting");
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.alarm {
|
||||
|
@@ -27,7 +27,6 @@ import { useDashboardStore } from "@/store/modules/dashboard";
|
||||
import Dashboard from "./dashboard/Edit.vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||
import { RoutesMap } from "@/constants/data";
|
||||
|
||||
const route = useRoute();
|
||||
const { t } = useI18n();
|
||||
@@ -38,7 +37,7 @@ const layer = ref<string>("GENERAL");
|
||||
getDashboard();
|
||||
|
||||
async function getDashboard() {
|
||||
layer.value = RoutesMap[String(route.name)];
|
||||
layer.value = String(route.meta.layer);
|
||||
dashboardStore.setLayer(layer.value);
|
||||
dashboardStore.setMode(false);
|
||||
await dashboardStore.setDashboards();
|
||||
|
@@ -69,18 +69,16 @@ limitations under the License. -->
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref, reactive } from "vue";
|
||||
import { ref } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||
import timeFormat from "@/utils/timeFormat";
|
||||
import { Languages } from "@/constants/data";
|
||||
import Selector from "@/components/Selector.vue";
|
||||
import getLocalTime from "@/utils/localtime";
|
||||
|
||||
const { t, locale } = useI18n();
|
||||
const appStore = useAppStoreWithOut();
|
||||
const state = reactive<{ timer: ReturnType<typeof setInterval> | null }>({
|
||||
timer: null,
|
||||
});
|
||||
const lang = ref<string>(locale.value || "en");
|
||||
const autoTime = ref<number>(6);
|
||||
const auto = ref<boolean>(appStore.autoRefresh || false);
|
||||
@@ -91,8 +89,11 @@ appStore.setPageTitle("Setting");
|
||||
const handleReload = () => {
|
||||
const gap =
|
||||
appStore.duration.end.getTime() - appStore.duration.start.getTime();
|
||||
const time: Date[] = [new Date(new Date().getTime() - gap), new Date()];
|
||||
appStore.setDuration(timeFormat(time));
|
||||
const dates: Date[] = [
|
||||
getLocalTime(appStore.utc, new Date(new Date().getTime() - gap)),
|
||||
getLocalTime(appStore.utc, new Date()),
|
||||
];
|
||||
appStore.setDuration(timeFormat(dates));
|
||||
};
|
||||
const handleAuto = () => {
|
||||
if (autoTime.value < 1) {
|
||||
@@ -101,10 +102,10 @@ const handleAuto = () => {
|
||||
appStore.setAutoRefresh(auto.value);
|
||||
if (auto.value) {
|
||||
handleReload();
|
||||
state.timer = setInterval(handleReload, autoTime.value * 1000);
|
||||
appStore.setReloadTimer(setInterval(handleReload, autoTime.value * 1000));
|
||||
} else {
|
||||
if (state.timer) {
|
||||
clearInterval(state.timer);
|
||||
if (appStore.reloadTimer) {
|
||||
clearInterval(appStore.reloadTimer);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -112,12 +113,12 @@ const changeAutoTime = () => {
|
||||
if (autoTime.value < 1) {
|
||||
return;
|
||||
}
|
||||
if (state.timer) {
|
||||
clearInterval(state.timer);
|
||||
if (appStore.reloadTimer) {
|
||||
clearInterval(appStore.reloadTimer);
|
||||
}
|
||||
if (auto.value) {
|
||||
handleReload();
|
||||
state.timer = setInterval(handleReload, autoTime.value * 1000);
|
||||
appStore.setReloadTimer(setInterval(handleReload, autoTime.value * 1000));
|
||||
}
|
||||
};
|
||||
const setLang = (): void => {
|
||||
|
@@ -145,16 +145,14 @@ limitations under the License. -->
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref } from "vue";
|
||||
import dayjs from "dayjs";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { Alarm, Event } from "@/types/alarm";
|
||||
import { useAlarmStore } from "@/store/modules/alarm";
|
||||
import { EventsDetailHeaders, AlarmDetailCol, EventsDetailKeys } from "./data";
|
||||
import { dateFormat } from "@/utils/dateFormat";
|
||||
|
||||
const { t } = useI18n();
|
||||
const alarmStore = useAlarmStore();
|
||||
const dateFormat = (date: number, pattern = "YYYY-MM-DD HH:mm:ss") =>
|
||||
dayjs(date).format(pattern);
|
||||
const isShowDetails = ref<boolean>(false);
|
||||
const showEventDetails = ref<boolean>(false);
|
||||
const currentDetail = ref<Alarm | any>({});
|
||||
|
@@ -15,11 +15,7 @@ limitations under the License. -->
|
||||
<template>
|
||||
<div>
|
||||
<span class="grey">{{ t("tags") }}: </span>
|
||||
<span
|
||||
v-if="tagsList.length"
|
||||
class="trace-tags"
|
||||
:style="type === 'LOG' ? `min-width: 122px;` : ''"
|
||||
>
|
||||
<span v-if="tagsList.length" class="trace-tags">
|
||||
<span class="selected" v-for="(item, index) in tagsList" :key="index">
|
||||
<span>{{ item }}</span>
|
||||
<span class="remove-icon" @click="removeTags(index)">×</span>
|
||||
@@ -33,31 +29,29 @@ limitations under the License. -->
|
||||
@change="addLabels"
|
||||
:placeholder="t('addTags')"
|
||||
/>
|
||||
<span v-else>
|
||||
<el-input
|
||||
size="small"
|
||||
v-model="tags"
|
||||
class="trace-new-tag"
|
||||
@click="showClick"
|
||||
/>
|
||||
<el-dropdown
|
||||
ref="dropdownTag"
|
||||
trigger="contextmenu"
|
||||
:hide-on-click="false"
|
||||
style="margin: 20px 0 0 -130px"
|
||||
v-if="tagArr.length"
|
||||
>
|
||||
<template #dropdown>
|
||||
<el-dropdown-menu>
|
||||
<el-dropdown-item v-for="(item, index) in tagArr" :key="index">
|
||||
<span @click="selectTag(item)" class="tag-item">
|
||||
{{ item }}
|
||||
</span>
|
||||
</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</template>
|
||||
</el-dropdown>
|
||||
</span>
|
||||
<el-popover v-else trigger="click" :visible="visible" width="300px">
|
||||
<template #reference>
|
||||
<el-input
|
||||
size="small"
|
||||
v-model="tags"
|
||||
class="trace-new-tag"
|
||||
@input="inputTags"
|
||||
@blur="visible = false"
|
||||
@focus="visible = true"
|
||||
@change="addTags"
|
||||
/>
|
||||
</template>
|
||||
<div class="content">
|
||||
<span
|
||||
v-for="(item, index) in tagList"
|
||||
:key="index"
|
||||
@click="selectTag(item)"
|
||||
class="tag-item"
|
||||
>
|
||||
{{ item }}
|
||||
</span>
|
||||
</div>
|
||||
</el-popover>
|
||||
<span
|
||||
class="tags-tip"
|
||||
:class="type !== 'ALARM' && tagArr.length ? 'link-tips' : ''"
|
||||
@@ -68,12 +62,12 @@ limitations under the License. -->
|
||||
>
|
||||
{{ t("tagsLink") }}
|
||||
</a>
|
||||
<el-tooltip :content="t(tipsMap[type])">
|
||||
<el-tooltip :content="t((tipsMap as any)[type])">
|
||||
<span>
|
||||
<Icon class="icon-help mr-5" iconName="help" size="middle" />
|
||||
</span>
|
||||
</el-tooltip>
|
||||
<b v-if="type === 'AL'">{{ t("noticeTag") }}</b>
|
||||
<b v-if="type === 'ALARM'">{{ t("noticeTag") }}</b>
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
@@ -85,7 +79,7 @@ import { useLogStore } from "@/store/modules/log";
|
||||
import { ElMessage } from "element-plus";
|
||||
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||
|
||||
/*global Nullable, defineEmits, defineProps */
|
||||
/*global defineEmits, defineProps */
|
||||
const emit = defineEmits(["update"]);
|
||||
const props = defineProps({
|
||||
type: { type: String, default: "TRACE" },
|
||||
@@ -97,13 +91,15 @@ const { t } = useI18n();
|
||||
const tags = ref<string>("");
|
||||
const tagsList = ref<string[]>([]);
|
||||
const tagArr = ref<string[]>([]);
|
||||
const tagList = ref<string[]>([]);
|
||||
const tagKeys = ref<string[]>([]);
|
||||
const keysList = ref<string[]>([]);
|
||||
const visible = ref<boolean>(false);
|
||||
const tipsMap = {
|
||||
LOG: "logTagsTip",
|
||||
TRACE: "traceTagsTip",
|
||||
ALARM: "alarmTagsTip",
|
||||
};
|
||||
const dropdownTag = ref<Nullable<any>>(null);
|
||||
|
||||
fetchTagKeys();
|
||||
|
||||
@@ -143,6 +139,8 @@ async function fetchTagKeys() {
|
||||
}
|
||||
tagArr.value = resp.data.tagKeys;
|
||||
tagKeys.value = resp.data.tagKeys;
|
||||
keysList.value = resp.data.tagKeys;
|
||||
searchTags();
|
||||
}
|
||||
|
||||
async function fetchTagValues() {
|
||||
@@ -159,25 +157,56 @@ async function fetchTagValues() {
|
||||
return;
|
||||
}
|
||||
tagArr.value = resp.data.tagValues;
|
||||
searchTags();
|
||||
}
|
||||
|
||||
function inputTags() {
|
||||
if (!tags.value) {
|
||||
tagArr.value = keysList.value;
|
||||
tagKeys.value = keysList.value;
|
||||
tagList.value = tagArr.value;
|
||||
return;
|
||||
}
|
||||
let search = "";
|
||||
if (tags.value.includes("=")) {
|
||||
search = tags.value.split("=")[1];
|
||||
fetchTagValues();
|
||||
} else {
|
||||
search = tags.value;
|
||||
}
|
||||
tagList.value = tagArr.value.filter((d: string) => d.includes(search));
|
||||
}
|
||||
|
||||
function addTags() {
|
||||
if (!tags.value.includes("=")) {
|
||||
return;
|
||||
}
|
||||
addLabels();
|
||||
tagArr.value = tagKeys.value;
|
||||
searchTags();
|
||||
}
|
||||
|
||||
function selectTag(item: string) {
|
||||
if (tags.value.includes("=")) {
|
||||
tags.value += item;
|
||||
addLabels();
|
||||
tagArr.value = tagKeys.value;
|
||||
dropdownTag.value.handleClose();
|
||||
const key = tags.value.split("=")[0];
|
||||
tags.value = key + "=" + item;
|
||||
addTags();
|
||||
return;
|
||||
}
|
||||
tags.value = item + "=";
|
||||
fetchTagValues();
|
||||
}
|
||||
|
||||
function showClick() {
|
||||
if (dropdownTag.value) {
|
||||
dropdownTag.value.handleOpen();
|
||||
function searchTags() {
|
||||
let search = "";
|
||||
if (tags.value.includes("=")) {
|
||||
search = tags.value.split("=")[1];
|
||||
} else {
|
||||
search = tags.value;
|
||||
}
|
||||
tagList.value = tagArr.value.filter((d: string) => d.includes(search));
|
||||
}
|
||||
|
||||
watch(
|
||||
() => appStore.durationTime,
|
||||
() => {
|
||||
@@ -221,6 +250,12 @@ watch(
|
||||
.tag-item {
|
||||
display: inline-block;
|
||||
min-width: 210px;
|
||||
cursor: pointer;
|
||||
margin-top: 10px;
|
||||
|
||||
&:hover {
|
||||
color: #409eff;
|
||||
}
|
||||
}
|
||||
|
||||
.tags-tip {
|
||||
@@ -229,7 +264,6 @@ watch(
|
||||
|
||||
.link-tips {
|
||||
display: inline-block;
|
||||
margin-left: 130px;
|
||||
}
|
||||
|
||||
.light {
|
||||
@@ -247,4 +281,10 @@ watch(
|
||||
.icon-help {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.content {
|
||||
width: 300px;
|
||||
max-height: 400px;
|
||||
overflow: auto;
|
||||
}
|
||||
</style>
|
||||
|
@@ -41,6 +41,7 @@ import Tool from "./panel/Tool.vue";
|
||||
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||
import Configuration from "./configuration";
|
||||
import { LayoutConfig } from "@/types/dashboard";
|
||||
|
||||
export default defineComponent({
|
||||
name: "Dashboard",
|
||||
@@ -66,7 +67,8 @@ export default defineComponent({
|
||||
sessionStorage.getItem(layoutKey.value) || "{}"
|
||||
);
|
||||
const layout: any = c.configuration || {};
|
||||
dashboardStore.setLayout(layout.children || []);
|
||||
|
||||
dashboardStore.setLayout(setWidgetsID(layout.children || []));
|
||||
appStore.setPageTitle(layout.name);
|
||||
if (p.entity) {
|
||||
dashboardStore.setCurrentDashboard({
|
||||
@@ -78,6 +80,24 @@ export default defineComponent({
|
||||
});
|
||||
}
|
||||
}
|
||||
function setWidgetsID(widgets: LayoutConfig[]) {
|
||||
for (const item of widgets) {
|
||||
item.id = item.i;
|
||||
if (item.type === "Tab") {
|
||||
if (item.children && item.children.length) {
|
||||
for (const [index, child] of item.children.entries()) {
|
||||
if (child.children && child.children.length) {
|
||||
child.children.map((d: { i: string; index: string } | any) => {
|
||||
d.id = `${item.i}-${index}-${d.i}`;
|
||||
return d;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return widgets;
|
||||
}
|
||||
function handleClick(e: any) {
|
||||
e.stopPropagation();
|
||||
if (e.target.className === "ds-main") {
|
||||
|
@@ -20,7 +20,7 @@ limitations under the License. -->
|
||||
placeholder="Please input name"
|
||||
class="input-with-search ml-10"
|
||||
size="small"
|
||||
@change="searchDashboards"
|
||||
@change="searchDashboards(1)"
|
||||
>
|
||||
<template #append>
|
||||
<el-button size="small">
|
||||
@@ -46,7 +46,7 @@ limitations under the License. -->
|
||||
ref="multipleTableRef"
|
||||
:default-sort="{ prop: 'name', order: 'ascending' }"
|
||||
@selection-change="handleSelectionChange"
|
||||
height="637px"
|
||||
height="calc(100% - 60px)"
|
||||
size="small"
|
||||
>
|
||||
<el-table-column type="selection" width="55" />
|
||||
@@ -129,7 +129,8 @@ limitations under the License. -->
|
||||
small
|
||||
layout="prev, pager, next"
|
||||
:page-size="pageSize"
|
||||
:total="dashboardStore.dashboards.length"
|
||||
:total="total"
|
||||
v-model="currentPage"
|
||||
@current-change="changePage"
|
||||
@prev-click="changePage"
|
||||
@next-click="changePage"
|
||||
@@ -155,10 +156,12 @@ import { isEmptyObject } from "@/utils/is";
|
||||
const { t } = useI18n();
|
||||
const appStore = useAppStoreWithOut();
|
||||
const dashboardStore = useDashboardStore();
|
||||
const pageSize = 18;
|
||||
const pageSize = 20;
|
||||
const dashboards = ref<DashboardItem[]>([]);
|
||||
const searchText = ref<string>("");
|
||||
const loading = ref<boolean>(false);
|
||||
const currentPage = ref<number>(1);
|
||||
const total = ref<number>(0);
|
||||
const multipleTableRef = ref<InstanceType<typeof ElTable>>();
|
||||
const multipleSelection = ref<DashboardItem[]>([]);
|
||||
const dashboardFile = ref<Nullable<HTMLDivElement>>(null);
|
||||
@@ -170,7 +173,7 @@ const handleSelectionChange = (val: DashboardItem[]) => {
|
||||
setList();
|
||||
async function setList() {
|
||||
await dashboardStore.setDashboards();
|
||||
searchDashboards();
|
||||
searchDashboards(1);
|
||||
}
|
||||
async function importTemplates(event: any) {
|
||||
const arr: any = await readFile(event);
|
||||
@@ -232,12 +235,20 @@ function exportTemplates() {
|
||||
}, 2000);
|
||||
}
|
||||
function optimizeTemplate(
|
||||
children: (LayoutConfig & { moved?: boolean; standard?: unknown })[]
|
||||
children: (LayoutConfig & {
|
||||
moved?: boolean;
|
||||
standard?: unknown;
|
||||
label?: string;
|
||||
value?: string;
|
||||
})[]
|
||||
) {
|
||||
for (const child of children || []) {
|
||||
delete child.moved;
|
||||
delete child.activedTabIndex;
|
||||
delete child.standard;
|
||||
delete child.id;
|
||||
delete child.label;
|
||||
delete child.value;
|
||||
if (isEmptyObject(child.graph)) {
|
||||
delete child.graph;
|
||||
}
|
||||
@@ -370,7 +381,7 @@ async function setRoot(row: DashboardItem) {
|
||||
items.push(d);
|
||||
}
|
||||
dashboardStore.resetDashboards(items);
|
||||
searchDashboards();
|
||||
searchDashboards(1);
|
||||
loading.value = false;
|
||||
}
|
||||
function handleRename(row: DashboardItem) {
|
||||
@@ -402,6 +413,7 @@ async function updateName(d: DashboardItem, value: string) {
|
||||
name: value,
|
||||
};
|
||||
delete c.id;
|
||||
delete c.filters;
|
||||
const setting = {
|
||||
id: d.id,
|
||||
configuration: JSON.stringify(c),
|
||||
@@ -453,10 +465,13 @@ function searchDashboards(pageIndex?: any) {
|
||||
const arr = list.filter((d: { name: string }) =>
|
||||
d.name.includes(searchText.value)
|
||||
);
|
||||
dashboards.value = arr.splice(
|
||||
(pageIndex - 1 || 0) * pageSize,
|
||||
pageSize * (pageIndex || 1)
|
||||
|
||||
total.value = arr.length;
|
||||
dashboards.value = arr.filter(
|
||||
(d: { name: string }, index: number) =>
|
||||
index < pageIndex * pageSize && index >= (pageIndex - 1) * pageSize
|
||||
);
|
||||
currentPage.value = pageIndex;
|
||||
}
|
||||
|
||||
async function reloadTemplates() {
|
||||
@@ -465,6 +480,7 @@ async function reloadTemplates() {
|
||||
loading.value = false;
|
||||
}
|
||||
function changePage(pageIndex: number) {
|
||||
currentPage.value = pageIndex;
|
||||
searchDashboards(pageIndex);
|
||||
}
|
||||
</script>
|
||||
@@ -484,12 +500,13 @@ function changePage(pageIndex: number) {
|
||||
}
|
||||
|
||||
.table {
|
||||
padding: 20px;
|
||||
padding: 20px 10px;
|
||||
background-color: #fff;
|
||||
box-shadow: 0px 1px 4px 0px #00000029;
|
||||
border-radius: 5px;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.toggle-selection {
|
||||
|
@@ -81,6 +81,10 @@ const onCreate = () => {
|
||||
states.entity === d.entity &&
|
||||
states.selectedLayer === d.layer
|
||||
);
|
||||
if (!states.name) {
|
||||
ElMessage.error(t("nameEmptyError"));
|
||||
return;
|
||||
}
|
||||
if (index > -1) {
|
||||
ElMessage.error(t("nameError"));
|
||||
return;
|
||||
|
82
src/views/dashboard/configuration/Event.vue
Normal file
@@ -0,0 +1,82 @@
|
||||
<!-- 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>
|
||||
<span class="label">{{ t("enableAssociate") }}</span>
|
||||
<el-switch
|
||||
v-model="eventAssociate"
|
||||
active-text="Yes"
|
||||
inactive-text="No"
|
||||
@change="updateConfig"
|
||||
/>
|
||||
</div>
|
||||
<div class="footer">
|
||||
<el-button size="small" @click="cancelConfig">
|
||||
{{ t("cancel") }}
|
||||
</el-button>
|
||||
<el-button size="small" type="primary" @click="applyConfig">
|
||||
{{ t("apply") }}
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { ref } from "vue";
|
||||
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||
|
||||
const { t } = useI18n();
|
||||
const dashboardStore = useDashboardStore();
|
||||
const originConfig = dashboardStore.selectedGrid;
|
||||
const eventAssociate = ref(dashboardStore.selectedGrid.eventAssociate || false);
|
||||
|
||||
function updateConfig() {
|
||||
dashboardStore.selectedGrid = {
|
||||
...dashboardStore.selectedGrid,
|
||||
eventAssociate,
|
||||
};
|
||||
dashboardStore.selectWidget(dashboardStore.selectedGrid);
|
||||
}
|
||||
|
||||
function applyConfig() {
|
||||
dashboardStore.setConfigPanel(false);
|
||||
dashboardStore.setConfigs(dashboardStore.selectedGrid);
|
||||
}
|
||||
|
||||
function cancelConfig() {
|
||||
dashboardStore.selectWidget(originConfig);
|
||||
dashboardStore.setConfigPanel(false);
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.label {
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
display: block;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.item {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
.footer {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
border-top: 1px solid #eee;
|
||||
padding: 10px;
|
||||
text-align: right;
|
||||
width: 100%;
|
||||
background-color: #fff;
|
||||
}
|
||||
</style>
|
161
src/views/dashboard/configuration/TimeRange.vue
Normal file
@@ -0,0 +1,161 @@
|
||||
<!-- Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
(the "License"); you may not use this file except in compliance with
|
||||
the License. You may obtain a copy of the License at
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License. -->
|
||||
<template>
|
||||
<div class="item">
|
||||
<span class="label">{{ t("text") }}</span>
|
||||
<el-input
|
||||
class="input"
|
||||
v-model="text"
|
||||
size="small"
|
||||
@change="changeConfig({ text })"
|
||||
/>
|
||||
</div>
|
||||
<div class="item">
|
||||
<span class="label">{{ t("textAlign") }}</span>
|
||||
<Selector
|
||||
:value="textAlign"
|
||||
:options="AlignStyle"
|
||||
size="small"
|
||||
placeholder="Select a color"
|
||||
class="input"
|
||||
@change="changeConfig({ textAlign: $event[0].value })"
|
||||
/>
|
||||
</div>
|
||||
<div class="item">
|
||||
<span class="label">{{ t("backgroundColors") }}</span>
|
||||
<Selector
|
||||
:value="backgroundColor"
|
||||
:options="Colors"
|
||||
size="small"
|
||||
placeholder="Select a color"
|
||||
class="input"
|
||||
@change="changeConfig({ backgroundColor: $event[0].value })"
|
||||
/>
|
||||
</div>
|
||||
<div class="item">
|
||||
<span class="label">{{ t("fontSize") }}</span>
|
||||
<el-slider
|
||||
class="slider"
|
||||
v-model="fontSize"
|
||||
show-input
|
||||
input-size="small"
|
||||
:min="12"
|
||||
:max="30"
|
||||
:step="1"
|
||||
@change="changeConfig({ fontSize })"
|
||||
/>
|
||||
</div>
|
||||
<div class="item">
|
||||
<span class="label">{{ t("fontColors") }}</span>
|
||||
<Selector
|
||||
:value="fontColor"
|
||||
:options="Colors"
|
||||
size="small"
|
||||
placeholder="Select a color"
|
||||
class="input"
|
||||
@change="changeConfig({ fontColor: $event[0].value })"
|
||||
/>
|
||||
</div>
|
||||
<div class="footer">
|
||||
<el-button size="small" @click="cancelConfig">
|
||||
{{ t("cancel") }}
|
||||
</el-button>
|
||||
<el-button size="small" type="primary" @click="applyConfig">
|
||||
{{ t("apply") }}
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { ref } from "vue";
|
||||
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||
|
||||
const { t } = useI18n();
|
||||
const dashboardStore = useDashboardStore();
|
||||
const originConfig = dashboardStore.selectedGrid;
|
||||
const graph = originConfig.graph || {};
|
||||
const backgroundColor = ref(graph.backgroundColor || "green");
|
||||
const fontColor = ref(graph.fontColor || "white");
|
||||
const fontSize = ref<number>(graph.fontSize || 12);
|
||||
const textAlign = ref(graph.textAlign || "left");
|
||||
const text = ref<string>(graph.text || "");
|
||||
const Colors = [
|
||||
{
|
||||
label: "Green",
|
||||
value: "green",
|
||||
},
|
||||
{ label: "Blue", value: "blue" },
|
||||
{ label: "Red", value: "red" },
|
||||
{ label: "Grey", value: "grey" },
|
||||
{ label: "White", value: "white" },
|
||||
{ label: "Black", value: "black" },
|
||||
{ label: "Orange", value: "orange" },
|
||||
];
|
||||
const AlignStyle = [
|
||||
{
|
||||
label: "Left",
|
||||
value: "left",
|
||||
},
|
||||
{ label: "Center", value: "center" },
|
||||
{ label: "Right", value: "right" },
|
||||
];
|
||||
function changeConfig(param: { [key: string]: unknown }) {
|
||||
const { selectedGrid } = dashboardStore;
|
||||
const graph = {
|
||||
...selectedGrid.graph,
|
||||
...param,
|
||||
};
|
||||
dashboardStore.selectWidget({ ...selectedGrid, graph });
|
||||
}
|
||||
function applyConfig() {
|
||||
dashboardStore.setConfigPanel(false);
|
||||
dashboardStore.setConfigs(dashboardStore.selectedGrid);
|
||||
}
|
||||
|
||||
function cancelConfig() {
|
||||
dashboardStore.selectWidget(originConfig);
|
||||
dashboardStore.setConfigPanel(false);
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.slider {
|
||||
width: 500px;
|
||||
margin-top: -3px;
|
||||
}
|
||||
|
||||
.label {
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
display: block;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.input {
|
||||
width: 500px;
|
||||
}
|
||||
|
||||
.item {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.footer {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
border-top: 1px solid #eee;
|
||||
padding: 10px;
|
||||
text-align: right;
|
||||
width: 100%;
|
||||
background-color: #fff;
|
||||
}
|
||||
</style>
|
@@ -32,10 +32,12 @@ limitations under the License. -->
|
||||
:data="states.source"
|
||||
:config="{
|
||||
...graph,
|
||||
legend: (dashboardStore.selectedGrid.graph || {}).legend,
|
||||
i: dashboardStore.selectedGrid.i,
|
||||
metrics: dashboardStore.selectedGrid.metrics,
|
||||
metricTypes: dashboardStore.selectedGrid.metricTypes,
|
||||
metricConfig: dashboardStore.selectedGrid.metricConfig,
|
||||
relatedTrace: dashboardStore.selectedGrid.relatedTrace,
|
||||
}"
|
||||
:needQuery="true"
|
||||
/>
|
||||
@@ -58,6 +60,20 @@ limitations under the License. -->
|
||||
<el-collapse-item :title="t('widgetOptions')" name="3">
|
||||
<WidgetOptions />
|
||||
</el-collapse-item>
|
||||
<el-collapse-item
|
||||
:title="t('associateOptions')"
|
||||
name="4"
|
||||
v-if="hasAssociate"
|
||||
>
|
||||
<AssociateOptions />
|
||||
</el-collapse-item>
|
||||
<el-collapse-item
|
||||
:title="t('relatedTraceOptions')"
|
||||
name="5"
|
||||
v-if="hasAssociate"
|
||||
>
|
||||
<RelatedTraceOptions />
|
||||
</el-collapse-item>
|
||||
</el-collapse>
|
||||
</div>
|
||||
<div class="footer">
|
||||
@@ -77,20 +93,16 @@ import { useDashboardStore } from "@/store/modules/dashboard";
|
||||
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||
import { Option } from "@/types/app";
|
||||
import graphs from "../graphs";
|
||||
import configs from "./widget/graph-styles";
|
||||
import WidgetOptions from "./widget/WidgetOptions.vue";
|
||||
import MetricOptions from "./widget/metric/Index.vue";
|
||||
import CustomOptions from "./widget/index";
|
||||
|
||||
export default defineComponent({
|
||||
name: "WidgetEdit",
|
||||
components: {
|
||||
...graphs,
|
||||
...configs,
|
||||
WidgetOptions,
|
||||
MetricOptions,
|
||||
...CustomOptions,
|
||||
},
|
||||
setup() {
|
||||
const configHeight = document.documentElement.clientHeight - 520;
|
||||
const configHeight = document.documentElement.clientHeight - 540;
|
||||
const { t } = useI18n();
|
||||
const dashboardStore = useDashboardStore();
|
||||
const appStoreWithOut = useAppStoreWithOut();
|
||||
@@ -111,6 +123,12 @@ export default defineComponent({
|
||||
const graph = computed(() => dashboardStore.selectedGrid.graph || {});
|
||||
const title = computed(() => encodeURIComponent(widget.value.title || ""));
|
||||
const tips = computed(() => encodeURIComponent(widget.value.tips || ""));
|
||||
const hasAssociate = computed(() =>
|
||||
["Bar", "Line", "Area", "TopList"].includes(
|
||||
dashboardStore.selectedGrid.graph &&
|
||||
dashboardStore.selectedGrid.graph.type
|
||||
)
|
||||
);
|
||||
|
||||
function getSource(source: unknown) {
|
||||
states.source = source;
|
||||
@@ -145,6 +163,7 @@ export default defineComponent({
|
||||
graph,
|
||||
title,
|
||||
tips,
|
||||
hasAssociate,
|
||||
};
|
||||
},
|
||||
});
|
||||
|
@@ -18,9 +18,13 @@
|
||||
import Text from "./Text.vue";
|
||||
import Widget from "./Widget.vue";
|
||||
import Topology from "./Topology.vue";
|
||||
import Event from "./Event.vue";
|
||||
import TimeRange from "./TimeRange.vue";
|
||||
|
||||
export default {
|
||||
Text,
|
||||
Widget,
|
||||
Topology,
|
||||
Event,
|
||||
TimeRange,
|
||||
};
|
||||
|