Compare commits
43 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
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 |
1356
package-lock.json
generated
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "skywalking-booster-ui",
|
"name": "skywalking-booster-ui",
|
||||||
"version": "9.1.0",
|
"version": "9.3.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"serve": "vue-cli-service serve",
|
"serve": "vue-cli-service serve",
|
||||||
@@ -19,12 +19,12 @@
|
|||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"monaco-editor": "^0.27.0",
|
"monaco-editor": "^0.27.0",
|
||||||
"pinia": "^2.0.5",
|
"pinia": "^2.0.5",
|
||||||
|
"vis-timeline": "^7.5.1",
|
||||||
"vue": "^3.0.0",
|
"vue": "^3.0.0",
|
||||||
"vue-grid-layout": "^3.0.0-beta1",
|
"vue-grid-layout": "^3.0.0-beta1",
|
||||||
"vue-i18n": "^9.1.9",
|
"vue-i18n": "^9.1.9",
|
||||||
"vue-router": "^4.0.0-0",
|
"vue-router": "^4.0.0-0",
|
||||||
"vue-types": "^4.1.1",
|
"vue-types": "^4.1.1"
|
||||||
"vuex": "^4.0.0-0"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/d3": "^7.1.0",
|
"@types/d3": "^7.1.0",
|
||||||
@@ -36,7 +36,7 @@
|
|||||||
"@typescript-eslint/eslint-plugin": "^4.18.0",
|
"@typescript-eslint/eslint-plugin": "^4.18.0",
|
||||||
"@typescript-eslint/parser": "^4.18.0",
|
"@typescript-eslint/parser": "^4.18.0",
|
||||||
"@vue/cli-plugin-babel": "~4.5.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-eslint": "~4.5.0",
|
||||||
"@vue/cli-plugin-router": "~4.5.0",
|
"@vue/cli-plugin-router": "~4.5.0",
|
||||||
"@vue/cli-plugin-typescript": "~4.5.0",
|
"@vue/cli-plugin-typescript": "~4.5.0",
|
||||||
|
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 |
@@ -12,4 +12,4 @@ distributed under the License is distributed on an "AS IS" BASIS,
|
|||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
See the License for the specific language governing permissions and
|
See the License for the specific language governing permissions and
|
||||||
limitations under the License. -->
|
limitations under the License. -->
|
||||||
<svg t="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/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 |
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 |
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/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/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) {
|
if (props.right && _time.getTime() / 100000 > start.value) {
|
||||||
emit("setDates", _time, "right");
|
emit("setDates", _time, "right");
|
||||||
}
|
}
|
||||||
if (!(props.left && props.right)) {
|
if (!(props.left || props.right)) {
|
||||||
emit("setDates", _time);
|
emit("setDates", _time);
|
||||||
}
|
}
|
||||||
emit("ok", info === "h");
|
emit("ok", info === "h");
|
||||||
|
@@ -44,6 +44,17 @@ const props = defineProps({
|
|||||||
type: Object as PropType<{ [key: string]: any }>,
|
type: Object as PropType<{ [key: string]: any }>,
|
||||||
default: () => ({}),
|
default: () => ({}),
|
||||||
},
|
},
|
||||||
|
filters: {
|
||||||
|
type: Object as PropType<{
|
||||||
|
duration: {
|
||||||
|
startTime: string;
|
||||||
|
endTime: string;
|
||||||
|
};
|
||||||
|
isRange: boolean;
|
||||||
|
dataIndex?: number;
|
||||||
|
sourceId: string;
|
||||||
|
}>,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
const available = computed(
|
const available = computed(
|
||||||
() =>
|
() =>
|
||||||
@@ -61,12 +72,93 @@ onMounted(async () => {
|
|||||||
if (!instance) {
|
if (!instance) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
instance.on("click", (params: any) => {
|
instance.on("click", (params: unknown) => {
|
||||||
emits("select", params);
|
emits("select", params);
|
||||||
});
|
});
|
||||||
|
document.addEventListener(
|
||||||
|
"click",
|
||||||
|
() => {
|
||||||
|
if (instance.isDisposed()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
instance.dispatchAction({
|
||||||
|
type: "hideTip",
|
||||||
|
});
|
||||||
|
instance.dispatchAction({
|
||||||
|
type: "updateAxisPointer",
|
||||||
|
currTrigger: "leave",
|
||||||
|
});
|
||||||
|
},
|
||||||
|
true
|
||||||
|
);
|
||||||
}, 1000);
|
}, 1000);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function updateOptions() {
|
||||||
|
const instance = getInstance();
|
||||||
|
if (!instance) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!props.filters) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (props.filters.isRange) {
|
||||||
|
const options = eventAssociate();
|
||||||
|
setOptions(options || props.option);
|
||||||
|
} else {
|
||||||
|
instance.dispatchAction({
|
||||||
|
type: "showTip",
|
||||||
|
dataIndex: props.filters.dataIndex,
|
||||||
|
seriesIndex: 0,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => props.option,
|
() => props.option,
|
||||||
(newVal, oldVal) => {
|
(newVal, oldVal) => {
|
||||||
@@ -76,7 +168,17 @@ watch(
|
|||||||
if (JSON.stringify(newVal) === JSON.stringify(oldVal)) {
|
if (JSON.stringify(newVal) === JSON.stringify(oldVal)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setOptions(newVal);
|
let options;
|
||||||
|
if (props.filters && props.filters.isRange) {
|
||||||
|
options = eventAssociate();
|
||||||
|
}
|
||||||
|
setOptions(options || props.option);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
watch(
|
||||||
|
() => props.filters,
|
||||||
|
() => {
|
||||||
|
updateOptions();
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@@ -29,9 +29,9 @@ limitations under the License. -->
|
|||||||
>
|
>
|
||||||
<el-option
|
<el-option
|
||||||
v-for="item in options"
|
v-for="item in options"
|
||||||
:key="item.value"
|
:key="item.value || ''"
|
||||||
:label="item.label"
|
:label="item.label || ''"
|
||||||
:value="item.value"
|
:value="item.value || ''"
|
||||||
>
|
>
|
||||||
</el-option>
|
</el-option>
|
||||||
</el-select>
|
</el-select>
|
||||||
|
@@ -28,15 +28,30 @@ export const Languages = [
|
|||||||
|
|
||||||
export const RoutesMap: { [key: string]: string } = {
|
export const RoutesMap: { [key: string]: string } = {
|
||||||
GeneralServices: "GENERAL",
|
GeneralServices: "GENERAL",
|
||||||
Database: "VIRTUAL_DATABASE",
|
GeneralServicesActiveTabIndex: "GENERAL",
|
||||||
|
VirtualDatabase: "VIRTUAL_DATABASE",
|
||||||
|
VirtualDatabaseActiveTabIndex: "VIRTUAL_DATABASE",
|
||||||
MeshServices: "MESH",
|
MeshServices: "MESH",
|
||||||
|
MeshServicesActiveTabIndex: "MESH",
|
||||||
ControlPanel: "MESH_CP",
|
ControlPanel: "MESH_CP",
|
||||||
|
ControlPanelActiveTabIndex: "MESH_CP",
|
||||||
DataPanel: "MESH_DP",
|
DataPanel: "MESH_DP",
|
||||||
|
DataPanelActiveTabIndex: "MESH_DP",
|
||||||
Linux: "OS_LINUX",
|
Linux: "OS_LINUX",
|
||||||
SkyWalkingServer: "SO11Y_OAP",
|
SkyWalkingServer: "SO11Y_OAP",
|
||||||
|
SkyWalkingServerActiveTabIndex: "SO11Y_OAP",
|
||||||
|
SatelliteActiveTabIndex: "SO11Y_SATELLITE",
|
||||||
Satellite: "SO11Y_SATELLITE",
|
Satellite: "SO11Y_SATELLITE",
|
||||||
Functions: "FAAS",
|
Functions: "FAAS",
|
||||||
|
FunctionsActiveTabIndex: "FAAS",
|
||||||
Browser: "BROWSER",
|
Browser: "BROWSER",
|
||||||
|
BrowserActiveTabIndex: "BROWSER",
|
||||||
KubernetesCluster: "K8S",
|
KubernetesCluster: "K8S",
|
||||||
|
KubernetesClusterActiveTabIndex: "K8S",
|
||||||
KubernetesService: "K8S_SERVICE",
|
KubernetesService: "K8S_SERVICE",
|
||||||
|
KubernetesServiceActiveTabIndex: "K8S_SERVICE",
|
||||||
|
MySQL: "MYSQL",
|
||||||
|
MySQLActiveTabIndex: "MYSQL",
|
||||||
|
PostgreSQL: "POSTGRESQL",
|
||||||
|
PostgreSQLActiveTabIndex: "POSTGRESQL",
|
||||||
};
|
};
|
||||||
|
@@ -33,12 +33,15 @@ export const createEBPFTask = {
|
|||||||
}`,
|
}`,
|
||||||
};
|
};
|
||||||
export const queryEBPFTasks = {
|
export const queryEBPFTasks = {
|
||||||
variable: "$serviceId: ID!",
|
variable:
|
||||||
|
"$serviceId: ID, $serviceInstanceId: ID, $targets: [EBPFProfilingTargetType!]",
|
||||||
query: `
|
query: `
|
||||||
queryEBPFTasks: queryEBPFProfilingTasks(serviceId: $serviceId) {
|
queryEBPFTasks: queryEBPFProfilingTasks(serviceId: $serviceId, serviceInstanceId: $serviceInstanceId, targets: $targets) {
|
||||||
taskId
|
taskId
|
||||||
serviceName
|
serviceName
|
||||||
serviceId
|
serviceId
|
||||||
|
serviceInstanceId
|
||||||
|
serviceInstanceName
|
||||||
processLabels
|
processLabels
|
||||||
taskStartTime
|
taskStartTime
|
||||||
triggerType
|
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 = {
|
export const Endpoints = {
|
||||||
variable: "$serviceId: ID!, $keyword: String!",
|
variable: "$serviceId: ID!, $keyword: String!",
|
||||||
query: `
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
};
|
||||||
|
@@ -21,6 +21,8 @@ import {
|
|||||||
queryEBPFTasks,
|
queryEBPFTasks,
|
||||||
queryEBPFSchedules,
|
queryEBPFSchedules,
|
||||||
analysisEBPFResult,
|
analysisEBPFResult,
|
||||||
|
createNetworkProfiling,
|
||||||
|
keepNetworkProfiling,
|
||||||
} from "../fragments/ebpf";
|
} from "../fragments/ebpf";
|
||||||
|
|
||||||
export const getCreateTaskData = `query queryCreateTaskData(${queryCreateTaskData.variable}) {${queryCreateTaskData.query}}`;
|
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 getEBPFSchedules = `query queryEBPFSchedules(${queryEBPFSchedules.variable}) {${queryEBPFSchedules.query}}`;
|
||||||
|
|
||||||
export const getEBPFResult = `query analysisEBPFResult(${analysisEBPFResult.variable}) {${analysisEBPFResult.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,
|
getService,
|
||||||
getInstance,
|
getInstance,
|
||||||
getEndpoint,
|
getEndpoint,
|
||||||
|
Processes,
|
||||||
|
getProcess,
|
||||||
} from "../fragments/selector";
|
} from "../fragments/selector";
|
||||||
|
|
||||||
export const queryServices = `query queryServices(${Services.variable}) {${Services.query}}`;
|
export const queryServices = `query queryServices(${Services.variable}) {${Services.query}}`;
|
||||||
@@ -31,3 +33,5 @@ export const queryLayers = `query listLayer {${Layers.query}}`;
|
|||||||
export const queryService = `query queryService(${getService.variable}) {${getService.query}}`;
|
export const queryService = `query queryService(${getService.variable}) {${getService.query}}`;
|
||||||
export const queryInstance = `query queryInstance(${getInstance.variable}) {${getInstance.query}}`;
|
export const queryInstance = `query queryInstance(${getInstance.variable}) {${getInstance.query}}`;
|
||||||
export const queryEndpoint = `query queryInstance(${getEndpoint.variable}) {${getEndpoint.query}}`;
|
export const queryEndpoint = `query queryInstance(${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,
|
InstanceTopology,
|
||||||
EndpointTopology,
|
EndpointTopology,
|
||||||
ServicesTopology,
|
ServicesTopology,
|
||||||
|
ProcessTopology,
|
||||||
} from "../fragments/topology";
|
} from "../fragments/topology";
|
||||||
|
|
||||||
export const getInstanceTopology = `query queryData(${InstanceTopology.variable}) {${InstanceTopology.query}}`;
|
export const getInstanceTopology = `query queryData(${InstanceTopology.variable}) {${InstanceTopology.query}}`;
|
||||||
export const getEndpointTopology = `query queryData(${EndpointTopology.variable}) {${EndpointTopology.query}}`;
|
export const getEndpointTopology = `query queryData(${EndpointTopology.variable}) {${EndpointTopology.query}}`;
|
||||||
export const getServicesTopology = `query queryData(${ServicesTopology.variable}) {${ServicesTopology.query}}`;
|
export const getServicesTopology = `query queryData(${ServicesTopology.variable}) {${ServicesTopology.query}}`;
|
||||||
|
export const getProcessTopology = `query queryData(${ProcessTopology.variable}) {${ProcessTopology.query}}`;
|
||||||
|
@@ -32,10 +32,12 @@ export enum Calculations {
|
|||||||
Precision = "precision",
|
Precision = "precision",
|
||||||
ConvertSeconds = "convertSeconds",
|
ConvertSeconds = "convertSeconds",
|
||||||
ConvertMilliseconds = "convertMilliseconds",
|
ConvertMilliseconds = "convertMilliseconds",
|
||||||
MsTos = "msTos",
|
MsToS = "msTos",
|
||||||
Average = "average",
|
Average = "average",
|
||||||
PercentageAvg = "percentageAvg",
|
PercentageAvg = "percentageAvg",
|
||||||
ApdexAvg = "apdexAvg",
|
ApdexAvg = "apdexAvg",
|
||||||
|
SecondToDay = "secondToDay",
|
||||||
|
NanosecondToMillisecond = "nanosecondToMillisecond",
|
||||||
}
|
}
|
||||||
export enum sizeEnum {
|
export enum sizeEnum {
|
||||||
XS = "XS",
|
XS = "XS",
|
||||||
|
@@ -14,19 +14,68 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
import { 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;
|
name: string;
|
||||||
layer: string;
|
layer: string;
|
||||||
entity: string;
|
entity: string;
|
||||||
}) {
|
}) {
|
||||||
|
const dashboardStore = useDashboardStore();
|
||||||
|
const opt = param || dashboardStore.currentDashboard;
|
||||||
const list = JSON.parse(sessionStorage.getItem("dashboards") || "[]");
|
const list = JSON.parse(sessionStorage.getItem("dashboards") || "[]");
|
||||||
const dashboard = list.find(
|
const dashboard = list.find(
|
||||||
(d: { name: string; layer: string; entity: string }) =>
|
(d: { name: string; layer: string; entity: string }) =>
|
||||||
d.name === param.name &&
|
d.name === opt.name && d.entity === opt.entity && d.layer === opt.layer
|
||||||
d.entity === param.entity &&
|
|
||||||
d.layer === param.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,
|
BarSeriesOption,
|
||||||
LineSeriesOption,
|
LineSeriesOption,
|
||||||
HeatmapSeriesOption,
|
HeatmapSeriesOption,
|
||||||
PieSeriesOption,
|
|
||||||
SankeySeriesOption,
|
SankeySeriesOption,
|
||||||
} from "echarts/charts";
|
} from "echarts/charts";
|
||||||
import {
|
import {
|
||||||
@@ -46,7 +45,6 @@ export type ECOption = echarts.ComposeOption<
|
|||||||
| DatasetComponentOption
|
| DatasetComponentOption
|
||||||
| LegendComponentOption
|
| LegendComponentOption
|
||||||
| HeatmapSeriesOption
|
| HeatmapSeriesOption
|
||||||
| PieSeriesOption
|
|
||||||
| SankeySeriesOption
|
| SankeySeriesOption
|
||||||
>;
|
>;
|
||||||
|
|
||||||
|
@@ -46,6 +46,7 @@ export function useQueryProcessor(config: any) {
|
|||||||
"ServiceRelation",
|
"ServiceRelation",
|
||||||
"ServiceInstanceRelation",
|
"ServiceInstanceRelation",
|
||||||
"EndpointRelation",
|
"EndpointRelation",
|
||||||
|
"ProcessRelation",
|
||||||
].includes(dashboardStore.entity);
|
].includes(dashboardStore.entity);
|
||||||
if (isRelation && !selectorStore.currentDestService) {
|
if (isRelation && !selectorStore.currentDestService) {
|
||||||
return;
|
return;
|
||||||
@@ -93,28 +94,40 @@ export function useQueryProcessor(config: any) {
|
|||||||
dashboardStore.entity === "All"
|
dashboardStore.entity === "All"
|
||||||
? undefined
|
? undefined
|
||||||
: selectorStore.currentService.normal,
|
: selectorStore.currentService.normal,
|
||||||
serviceInstanceName: dashboardStore.entity.includes("ServiceInstance")
|
serviceInstanceName: [
|
||||||
|
"ServiceInstance",
|
||||||
|
"ServiceInstanceRelation",
|
||||||
|
"ProcessRelation",
|
||||||
|
].includes(dashboardStore.entity)
|
||||||
? selectorStore.currentPod && selectorStore.currentPod.value
|
? selectorStore.currentPod && selectorStore.currentPod.value
|
||||||
: undefined,
|
: undefined,
|
||||||
endpointName: dashboardStore.entity.includes("Endpoint")
|
endpointName: dashboardStore.entity.includes("Endpoint")
|
||||||
? selectorStore.currentPod && selectorStore.currentPod.value
|
? selectorStore.currentPod && selectorStore.currentPod.value
|
||||||
: undefined,
|
: undefined,
|
||||||
|
processName: dashboardStore.entity.includes("Process")
|
||||||
|
? selectorStore.currentProcess && selectorStore.currentProcess.value
|
||||||
|
: undefined,
|
||||||
destNormal: isRelation
|
destNormal: isRelation
|
||||||
? selectorStore.currentDestService.normal
|
? selectorStore.currentDestService.normal
|
||||||
: undefined,
|
: undefined,
|
||||||
destServiceName: isRelation
|
destServiceName: isRelation
|
||||||
? selectorStore.currentDestService.value
|
? selectorStore.currentDestService.value
|
||||||
: undefined,
|
: undefined,
|
||||||
destServiceInstanceName:
|
destServiceInstanceName: [
|
||||||
dashboardStore.entity === "ServiceInstanceRelation"
|
"ServiceInstanceRelation",
|
||||||
? selectorStore.currentDestPod &&
|
"ProcessRelation",
|
||||||
selectorStore.currentDestPod.value
|
].includes(dashboardStore.entity)
|
||||||
: undefined,
|
? selectorStore.currentDestPod && selectorStore.currentDestPod.value
|
||||||
|
: undefined,
|
||||||
destEndpointName:
|
destEndpointName:
|
||||||
dashboardStore.entity === "EndpointRelation"
|
dashboardStore.entity === "EndpointRelation"
|
||||||
? selectorStore.currentDestPod &&
|
? selectorStore.currentDestPod &&
|
||||||
selectorStore.currentDestPod.value
|
selectorStore.currentDestPod.value
|
||||||
: undefined,
|
: undefined,
|
||||||
|
destProcessName: dashboardStore.entity.includes("ProcessRelation")
|
||||||
|
? selectorStore.currentDestProcess &&
|
||||||
|
selectorStore.currentDestProcess.value
|
||||||
|
: undefined,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -142,6 +155,10 @@ export function useSourceProcessor(
|
|||||||
ElMessage.error(resp.errors);
|
ElMessage.error(resp.errors);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
if (!resp.data) {
|
||||||
|
ElMessage.error("The query is wrong");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
const source: { [key: string]: unknown } = {};
|
const source: { [key: string]: unknown } = {};
|
||||||
const keys = Object.keys(resp.data);
|
const keys = Object.keys(resp.data);
|
||||||
|
|
||||||
@@ -150,7 +167,10 @@ export function useSourceProcessor(
|
|||||||
const c = (config.metricConfig && config.metricConfig[index]) || {};
|
const c = (config.metricConfig && config.metricConfig[index]) || {};
|
||||||
|
|
||||||
if (type === MetricQueryTypes.ReadMetricsValues) {
|
if (type === MetricQueryTypes.ReadMetricsValues) {
|
||||||
source[m] = calculateExp(resp.data[keys[index]].values.values, c);
|
source[m] =
|
||||||
|
(resp.data[keys[index]] &&
|
||||||
|
calculateExp(resp.data[keys[index]].values.values, c)) ||
|
||||||
|
[];
|
||||||
}
|
}
|
||||||
if (type === MetricQueryTypes.ReadLabeledMetricsValues) {
|
if (type === MetricQueryTypes.ReadLabeledMetricsValues) {
|
||||||
const resVal = Object.values(resp.data)[0] || [];
|
const resVal = Object.values(resp.data)[0] || [];
|
||||||
@@ -377,23 +397,26 @@ export function aggregation(
|
|||||||
data = (val / 1024 / 1024 / 1024).toFixed(2);
|
data = (val / 1024 / 1024 / 1024).toFixed(2);
|
||||||
break;
|
break;
|
||||||
case Calculations.Apdex:
|
case Calculations.Apdex:
|
||||||
data = val / 10000;
|
data = (val / 10000).toFixed(2);
|
||||||
break;
|
|
||||||
case Calculations.ApdexAvg:
|
|
||||||
data = val / 10000;
|
|
||||||
break;
|
break;
|
||||||
case Calculations.ConvertSeconds:
|
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;
|
break;
|
||||||
case Calculations.ConvertMilliseconds:
|
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;
|
break;
|
||||||
case Calculations.Precision:
|
case Calculations.Precision:
|
||||||
data = data.toFixed(2);
|
data = data.toFixed(2);
|
||||||
break;
|
break;
|
||||||
case Calculations.MsTos:
|
case Calculations.MsToS:
|
||||||
data = (val / 1000).toFixed(2);
|
data = (val / 1000).toFixed(2);
|
||||||
break;
|
break;
|
||||||
|
case Calculations.SecondToDay:
|
||||||
|
data = (val / 86400).toFixed(2);
|
||||||
|
break;
|
||||||
|
case Calculations.NanosecondToMillisecond:
|
||||||
|
data = (val / 1000 / 1000).toFixed(2);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
data;
|
data;
|
||||||
break;
|
break;
|
||||||
|
@@ -13,7 +13,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|||||||
See the License for the specific language governing permissions and
|
See the License for the specific language governing permissions and
|
||||||
limitations under the License. -->
|
limitations under the License. -->
|
||||||
<template>
|
<template>
|
||||||
<div class="nav-bar flex-h" :class="{ dark: theme === 'dark' }">
|
<div class="nav-bar flex-h">
|
||||||
<div class="title">{{ appStore.pageTitle || t(pageName) }}</div>
|
<div class="title">{{ appStore.pageTitle || t(pageName) }}</div>
|
||||||
<div class="app-config">
|
<div class="app-config">
|
||||||
<span class="red" v-show="timeRange">{{ t("timeTips") }}</span>
|
<span class="red" v-show="timeRange">{{ t("timeTips") }}</span>
|
||||||
@@ -49,34 +49,38 @@ limitations under the License. -->
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref, watch, computed } from "vue";
|
import { ref, watch } from "vue";
|
||||||
import { useRoute } from "vue-router";
|
import { useRoute } from "vue-router";
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
import timeFormat from "@/utils/timeFormat";
|
import timeFormat from "@/utils/timeFormat";
|
||||||
import { useAppStoreWithOut } from "@/store/modules/app";
|
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||||
import { ElMessage } from "element-plus";
|
import { ElMessage } from "element-plus";
|
||||||
|
import getLocalTime from "@/utils/localtime";
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const appStore = useAppStoreWithOut();
|
const appStore = useAppStoreWithOut();
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const pageName = ref<string>("");
|
const pageName = ref<string>("");
|
||||||
const timeRange = ref<number>(0);
|
const timeRange = ref<number>(0);
|
||||||
const theme = ref<string>("light");
|
const time = ref<Date[]>([
|
||||||
|
|
||||||
getVersion();
|
|
||||||
const setConfig = (value: string) => {
|
|
||||||
pageName.value = value || "";
|
|
||||||
// theme.value = route.path.includes("/infrastructure/") ? "dark" : "light";
|
|
||||||
};
|
|
||||||
const time = computed(() => [
|
|
||||||
appStore.durationRow.start,
|
appStore.durationRow.start,
|
||||||
appStore.durationRow.end,
|
appStore.durationRow.end,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
resetDuration();
|
||||||
|
getVersion();
|
||||||
|
const setConfig = (value: string) => {
|
||||||
|
pageName.value = value || "";
|
||||||
|
};
|
||||||
|
|
||||||
const handleReload = () => {
|
const handleReload = () => {
|
||||||
const gap =
|
const gap =
|
||||||
appStore.duration.end.getTime() - appStore.duration.start.getTime();
|
appStore.duration.end.getTime() - appStore.duration.start.getTime();
|
||||||
const time: Date[] = [new Date(new Date().getTime() - gap), new Date()];
|
const dates: Date[] = [
|
||||||
appStore.setDuration(timeFormat(time));
|
getLocalTime(appStore.utc, new Date(new Date().getTime() - gap)),
|
||||||
|
getLocalTime(appStore.utc, new Date()),
|
||||||
|
];
|
||||||
|
appStore.setDuration(timeFormat(dates));
|
||||||
};
|
};
|
||||||
function changeTimeRange(val: Date[] | any) {
|
function changeTimeRange(val: Date[] | any) {
|
||||||
timeRange.value =
|
timeRange.value =
|
||||||
@@ -99,6 +103,20 @@ async function getVersion() {
|
|||||||
ElMessage.error(res.errors);
|
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);
|
||||||
|
time.value = [new Date(d.start), new Date(d.end)];
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.nav-bar {
|
.nav-bar {
|
||||||
|
@@ -55,9 +55,9 @@ limitations under the License. -->
|
|||||||
<router-link
|
<router-link
|
||||||
class="items"
|
class="items"
|
||||||
:to="m.path"
|
:to="m.path"
|
||||||
:exact="m.meta.exact || false"
|
:exact="(m.meta && m.meta.exact) || false"
|
||||||
>
|
>
|
||||||
<span class="title">{{ t(m.meta.title) }}</span>
|
<span class="title">{{ m.meta && t(m.meta.title) }}</span>
|
||||||
</router-link>
|
</router-link>
|
||||||
</el-menu-item>
|
</el-menu-item>
|
||||||
</el-menu-item-group>
|
</el-menu-item-group>
|
||||||
|
@@ -32,6 +32,7 @@ const msg = {
|
|||||||
dashboards: "Dashboards",
|
dashboards: "Dashboards",
|
||||||
profiles: "Profiles",
|
profiles: "Profiles",
|
||||||
database: "Database",
|
database: "Database",
|
||||||
|
mySQL: "MySQL",
|
||||||
serviceName: "Service Name",
|
serviceName: "Service Name",
|
||||||
technologies: "Technologies",
|
technologies: "Technologies",
|
||||||
generalServicePanel: "General Service Panel",
|
generalServicePanel: "General Service Panel",
|
||||||
@@ -142,6 +143,15 @@ const msg = {
|
|||||||
interval: "Refresh Interval",
|
interval: "Refresh Interval",
|
||||||
pause: "Pause",
|
pause: "Pause",
|
||||||
begin: "Start",
|
begin: "Start",
|
||||||
|
associateOptions: "Association Options",
|
||||||
|
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",
|
||||||
seconds: "Seconds",
|
seconds: "Seconds",
|
||||||
hourTip: "Select Hour",
|
hourTip: "Select Hour",
|
||||||
minuteTip: "Select Minute",
|
minuteTip: "Select Minute",
|
||||||
@@ -151,8 +161,6 @@ const msg = {
|
|||||||
monthsHead: "Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec",
|
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",
|
months: "Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec",
|
||||||
weeks: "Mon_Tue_Wed_Thu_Fri_Sat_Sun",
|
weeks: "Mon_Tue_Wed_Thu_Fri_Sat_Sun",
|
||||||
hello: "Hello",
|
|
||||||
helloMessage: "Welcome Back, Apache SkyWalking APM System !",
|
|
||||||
username: "Username",
|
username: "Username",
|
||||||
password: "Password",
|
password: "Password",
|
||||||
title: "Title",
|
title: "Title",
|
||||||
@@ -161,7 +169,7 @@ const msg = {
|
|||||||
dashboard: "Dashboard",
|
dashboard: "Dashboard",
|
||||||
topology: "Topology",
|
topology: "Topology",
|
||||||
trace: "Trace",
|
trace: "Trace",
|
||||||
alarm: "Alarms",
|
alarm: "Alerting",
|
||||||
auto: "Auto",
|
auto: "Auto",
|
||||||
reload: "Reload",
|
reload: "Reload",
|
||||||
version: "Version",
|
version: "Version",
|
||||||
|
@@ -32,6 +32,7 @@ const msg = {
|
|||||||
dashboards: "Paneles",
|
dashboards: "Paneles",
|
||||||
profiles: "Perfiles",
|
profiles: "Perfiles",
|
||||||
database: "Base de Datos",
|
database: "Base de Datos",
|
||||||
|
mySQL: "MySQL",
|
||||||
serviceName: "Nombre Servicio",
|
serviceName: "Nombre Servicio",
|
||||||
technologies: "Tecnologías",
|
technologies: "Tecnologías",
|
||||||
generalServicePanel: "Panel Servicio General",
|
generalServicePanel: "Panel Servicio General",
|
||||||
@@ -142,6 +143,15 @@ const msg = {
|
|||||||
interval: "Intervalo de actualización",
|
interval: "Intervalo de actualización",
|
||||||
pause: "Pausa",
|
pause: "Pausa",
|
||||||
begin: "Inicio",
|
begin: "Inicio",
|
||||||
|
associateOptions: "Opciones de asociació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",
|
||||||
seconds: "Segundos",
|
seconds: "Segundos",
|
||||||
hourTip: "Seleccione Hora",
|
hourTip: "Seleccione Hora",
|
||||||
minuteTip: "Seleccione Minuto",
|
minuteTip: "Seleccione Minuto",
|
||||||
@@ -151,8 +161,6 @@ const msg = {
|
|||||||
monthsHead: "Ene_Feb_Mar_Abr_May_Jun_Jul_Ago_Set_Oct_Nov_Dic",
|
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",
|
months: "Ene_Feb_Mar_Abr_May_Jun_Jul_Ago_Set_Oct_Nov_Dic",
|
||||||
weeks: "Lun_Mar_Mier_Jue_Vie_Sáb_Dom",
|
weeks: "Lun_Mar_Mier_Jue_Vie_Sáb_Dom",
|
||||||
hello: "Hola",
|
|
||||||
helloMessage: "Bienvenido de vuelta, Apache SkyWalking APM System !",
|
|
||||||
username: "Usuario",
|
username: "Usuario",
|
||||||
password: "Contraseña",
|
password: "Contraseña",
|
||||||
title: "Título",
|
title: "Título",
|
||||||
@@ -161,7 +169,7 @@ const msg = {
|
|||||||
dashboard: "Panel",
|
dashboard: "Panel",
|
||||||
topology: "Topología",
|
topology: "Topología",
|
||||||
trace: "Traza",
|
trace: "Traza",
|
||||||
alarm: "Alarmas",
|
alarm: "Recordatorio en curso",
|
||||||
auto: "Auto",
|
auto: "Auto",
|
||||||
reload: "Recargar",
|
reload: "Recargar",
|
||||||
version: "Versión",
|
version: "Versión",
|
||||||
|
@@ -32,6 +32,7 @@ const msg = {
|
|||||||
dashboards: "仪表盘",
|
dashboards: "仪表盘",
|
||||||
profiles: "性能剖析",
|
profiles: "性能剖析",
|
||||||
database: "数据库",
|
database: "数据库",
|
||||||
|
mySQL: "MySQL",
|
||||||
serviceName: "服务名称",
|
serviceName: "服务名称",
|
||||||
technologies: "技术",
|
technologies: "技术",
|
||||||
health: "健康",
|
health: "健康",
|
||||||
@@ -140,6 +141,14 @@ const msg = {
|
|||||||
interval: "刷新间隔时间",
|
interval: "刷新间隔时间",
|
||||||
pause: "暂停",
|
pause: "暂停",
|
||||||
begin: "开始",
|
begin: "开始",
|
||||||
|
associateOptions: "关联选项",
|
||||||
|
widget: "部件",
|
||||||
|
enableAssociate: "启用关联",
|
||||||
|
nameTip: "该名称仅支持中文和英文、横线和下划线, 并且限制长度为300个字符",
|
||||||
|
duplicateName: "重复的名称",
|
||||||
|
text: "文本",
|
||||||
|
query: "查询",
|
||||||
|
postgreSQL: "PostgreSQL",
|
||||||
seconds: "秒",
|
seconds: "秒",
|
||||||
hourTip: "选择小时",
|
hourTip: "选择小时",
|
||||||
minuteTip: "选择分钟",
|
minuteTip: "选择分钟",
|
||||||
@@ -149,8 +158,6 @@ const msg = {
|
|||||||
monthsHead: "1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月",
|
monthsHead: "1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月",
|
||||||
months: "一月_二月_三月_四月_五月_六月_七月_八月_九月_十月_十一月_十二月",
|
months: "一月_二月_三月_四月_五月_六月_七月_八月_九月_十月_十一月_十二月",
|
||||||
weeks: "一_二_三_四_五_六_日",
|
weeks: "一_二_三_四_五_六_日",
|
||||||
hello: "你好",
|
|
||||||
helloMessage: "欢迎来到, Apache SkyWalking APM 系统 !",
|
|
||||||
username: "用户名",
|
username: "用户名",
|
||||||
password: "密码",
|
password: "密码",
|
||||||
title: "标题",
|
title: "标题",
|
||||||
|
@@ -30,13 +30,13 @@ export const routesAlarm: Array<RouteRecordRaw> = [
|
|||||||
component: Layout,
|
component: Layout,
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: "/alarm",
|
path: "/alerting",
|
||||||
name: "Alarm",
|
name: "Alarm",
|
||||||
meta: {
|
meta: {
|
||||||
exact: false,
|
exact: false,
|
||||||
},
|
},
|
||||||
component: () =>
|
component: () =>
|
||||||
import(/* webpackChunkName: "alarms" */ "@/views/Alarm.vue"),
|
import(/* webpackChunkName: "alerting" */ "@/views/Alarm.vue"),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
@@ -33,12 +33,20 @@ export const routesBrowser: Array<RouteRecordRaw> = [
|
|||||||
name: "Browser",
|
name: "Browser",
|
||||||
meta: {
|
meta: {
|
||||||
title: "browser",
|
title: "browser",
|
||||||
headPath: "/browser",
|
|
||||||
exact: true,
|
exact: true,
|
||||||
},
|
},
|
||||||
component: () =>
|
component: () =>
|
||||||
import(/* webpackChunkName: "layer" */ "@/views/Layer.vue"),
|
import(/* webpackChunkName: "layer" */ "@/views/Layer.vue"),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: "/browser/tab/:activeTabIndex",
|
||||||
|
name: "BrowserActiveTabIndex",
|
||||||
|
meta: {
|
||||||
|
notShow: true,
|
||||||
|
},
|
||||||
|
component: () =>
|
||||||
|
import(/* webpackChunkName: "layer" */ "@/views/Layer.vue"),
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
@@ -54,69 +54,195 @@ export const routesDashboard: Array<RouteRecordRaw> = [
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: "/dashboard/:layerId/:entity/:name",
|
path: "",
|
||||||
|
redirect: "/dashboard/:layerId/:entity/:name",
|
||||||
|
name: "Create",
|
||||||
component: () =>
|
component: () =>
|
||||||
import(
|
import(
|
||||||
/* webpackChunkName: "dashboards" */ "@/views/dashboard/Edit.vue"
|
/* webpackChunkName: "dashboards" */ "@/views/dashboard/Edit.vue"
|
||||||
),
|
),
|
||||||
name: "Create",
|
|
||||||
meta: {
|
meta: {
|
||||||
title: "dashboardEdit",
|
|
||||||
exact: false,
|
|
||||||
notShow: true,
|
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: () =>
|
component: () =>
|
||||||
import(
|
import(
|
||||||
/* webpackChunkName: "dashboards" */ "@/views/dashboard/Edit.vue"
|
/* webpackChunkName: "dashboards" */ "@/views/dashboard/Edit.vue"
|
||||||
),
|
),
|
||||||
name: "View",
|
name: "View",
|
||||||
|
redirect: "/dashboard/:layerId/:entity/:serviceId/:name",
|
||||||
meta: {
|
meta: {
|
||||||
title: "dashboardEdit",
|
|
||||||
exact: false,
|
|
||||||
notShow: true,
|
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: () =>
|
component: () =>
|
||||||
import(
|
import(
|
||||||
/* webpackChunkName: "dashboards" */ "@/views/dashboard/Edit.vue"
|
/* webpackChunkName: "dashboards" */ "@/views/dashboard/Edit.vue"
|
||||||
),
|
),
|
||||||
name: "ViewServiceRelation",
|
name: "ViewServiceRelation",
|
||||||
meta: {
|
meta: {
|
||||||
title: "dashboardEdit",
|
|
||||||
exact: false,
|
|
||||||
notShow: true,
|
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: () =>
|
component: () =>
|
||||||
import(
|
import(
|
||||||
/* webpackChunkName: "dashboards" */ "@/views/dashboard/Edit.vue"
|
/* webpackChunkName: "dashboards" */ "@/views/dashboard/Edit.vue"
|
||||||
),
|
),
|
||||||
name: "ViewPod",
|
name: "ViewPod",
|
||||||
meta: {
|
meta: {
|
||||||
title: "dashboardEdit",
|
|
||||||
exact: false,
|
|
||||||
notShow: true,
|
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: () =>
|
component: () =>
|
||||||
import(
|
import(
|
||||||
/* webpackChunkName: "dashboards" */ "@/views/dashboard/Edit.vue"
|
/* webpackChunkName: "dashboards" */ "@/views/dashboard/Edit.vue"
|
||||||
),
|
),
|
||||||
name: "ViewPodRelation",
|
name: "PodRelation",
|
||||||
meta: {
|
meta: {
|
||||||
title: "dashboardEdit",
|
|
||||||
exact: true,
|
|
||||||
notShow: 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",
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
@@ -26,20 +26,47 @@ export const routesDatabase: Array<RouteRecordRaw> = [
|
|||||||
icon: "storage",
|
icon: "storage",
|
||||||
hasGroup: true,
|
hasGroup: true,
|
||||||
},
|
},
|
||||||
redirect: "/database",
|
redirect: "/mySQL",
|
||||||
component: Layout,
|
component: Layout,
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: "/database",
|
path: "/mySQL",
|
||||||
name: "Database",
|
name: "MySQL",
|
||||||
meta: {
|
meta: {
|
||||||
title: "virtualDatabase",
|
title: "mySQL",
|
||||||
headPath: "/database",
|
|
||||||
exact: true,
|
exact: true,
|
||||||
},
|
},
|
||||||
component: () =>
|
component: () =>
|
||||||
import(/* webpackChunkName: "layer" */ "@/views/Layer.vue"),
|
import(/* webpackChunkName: "layer" */ "@/views/Layer.vue"),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: "/mySQL/tab/:activeTabIndex",
|
||||||
|
name: "MySQLActiveTabIndex",
|
||||||
|
meta: {
|
||||||
|
notShow: true,
|
||||||
|
},
|
||||||
|
component: () =>
|
||||||
|
import(/* webpackChunkName: "layer" */ "@/views/Layer.vue"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "/postgreSQL",
|
||||||
|
name: "PostgreSQL",
|
||||||
|
meta: {
|
||||||
|
title: "postgreSQL",
|
||||||
|
exact: true,
|
||||||
|
},
|
||||||
|
component: () =>
|
||||||
|
import(/* webpackChunkName: "layer" */ "@/views/Layer.vue"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "/postgreSQL/tab/:activeTabIndex",
|
||||||
|
name: "PostgreSQLActiveTabIndex",
|
||||||
|
meta: {
|
||||||
|
notShow: true,
|
||||||
|
},
|
||||||
|
component: () =>
|
||||||
|
import(/* webpackChunkName: "layer" */ "@/views/Layer.vue"),
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
@@ -32,13 +32,17 @@ export const routesFunctions: Array<RouteRecordRaw> = [
|
|||||||
path: "/functions",
|
path: "/functions",
|
||||||
name: "Functions",
|
name: "Functions",
|
||||||
meta: {
|
meta: {
|
||||||
title: "functions",
|
|
||||||
headPath: "/functions",
|
|
||||||
exact: true,
|
exact: true,
|
||||||
},
|
},
|
||||||
component: () =>
|
component: () =>
|
||||||
import(/* webpackChunkName: "layer" */ "@/views/Layer.vue"),
|
import(/* webpackChunkName: "layer" */ "@/views/Layer.vue"),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: "/functions/tab/:activeTabIndex",
|
||||||
|
name: "FunctionsActiveTabIndex",
|
||||||
|
component: () =>
|
||||||
|
import(/* webpackChunkName: "layer" */ "@/views/Layer.vue"),
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
@@ -24,7 +24,7 @@ export const routesGen: Array<RouteRecordRaw> = [
|
|||||||
meta: {
|
meta: {
|
||||||
title: "general",
|
title: "general",
|
||||||
icon: "chart",
|
icon: "chart",
|
||||||
hasGroup: false,
|
hasGroup: true,
|
||||||
exact: true,
|
exact: true,
|
||||||
},
|
},
|
||||||
component: Layout,
|
component: Layout,
|
||||||
@@ -33,13 +33,41 @@ export const routesGen: Array<RouteRecordRaw> = [
|
|||||||
path: "/general",
|
path: "/general",
|
||||||
name: "GeneralServices",
|
name: "GeneralServices",
|
||||||
meta: {
|
meta: {
|
||||||
title: "services",
|
|
||||||
headPath: "/general/service",
|
|
||||||
exact: true,
|
exact: true,
|
||||||
|
title: "services",
|
||||||
},
|
},
|
||||||
component: () =>
|
component: () =>
|
||||||
import(/* webpackChunkName: "layers" */ "@/views/Layer.vue"),
|
import(/* webpackChunkName: "layers" */ "@/views/Layer.vue"),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: "/general/tab/:activeTabIndex",
|
||||||
|
name: "GeneralServicesActiveTabIndex",
|
||||||
|
meta: {
|
||||||
|
exact: true,
|
||||||
|
notShow: true,
|
||||||
|
},
|
||||||
|
component: () =>
|
||||||
|
import(/* webpackChunkName: "layers" */ "@/views/Layer.vue"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "/database",
|
||||||
|
name: "VirtualDatabase",
|
||||||
|
meta: {
|
||||||
|
title: "virtualDatabase",
|
||||||
|
exact: true,
|
||||||
|
},
|
||||||
|
component: () =>
|
||||||
|
import(/* webpackChunkName: "layer" */ "@/views/Layer.vue"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "/database/tab/:activeTabIndex",
|
||||||
|
name: "VirtualDatabaseActiveTabIndex",
|
||||||
|
meta: {
|
||||||
|
notShow: true,
|
||||||
|
},
|
||||||
|
component: () =>
|
||||||
|
import(/* webpackChunkName: "layer" */ "@/views/Layer.vue"),
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
@@ -20,7 +20,6 @@ import { routesMesh } from "./serviceMesh";
|
|||||||
import { routesDatabase } from "./database";
|
import { routesDatabase } from "./database";
|
||||||
import { routesInfra } from "./infrastructure";
|
import { routesInfra } from "./infrastructure";
|
||||||
import { routesDashboard } from "./dashboard";
|
import { routesDashboard } from "./dashboard";
|
||||||
import { routesEvent } from "./event";
|
|
||||||
import { routesSetting } from "./setting";
|
import { routesSetting } from "./setting";
|
||||||
import { routesAlarm } from "./alarm";
|
import { routesAlarm } from "./alarm";
|
||||||
import { routesSelf } from "./selfObservability";
|
import { routesSelf } from "./selfObservability";
|
||||||
@@ -39,7 +38,6 @@ const routes: Array<RouteRecordRaw> = [
|
|||||||
...routesSelf,
|
...routesSelf,
|
||||||
...routesDashboard,
|
...routesDashboard,
|
||||||
...routesAlarm,
|
...routesAlarm,
|
||||||
...routesEvent,
|
|
||||||
...routesSetting,
|
...routesSetting,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@@ -39,6 +39,16 @@ export const routesInfra: Array<RouteRecordRaw> = [
|
|||||||
component: () =>
|
component: () =>
|
||||||
import(/* webpackChunkName: "layer" */ "@/views/Layer.vue"),
|
import(/* webpackChunkName: "layer" */ "@/views/Layer.vue"),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: "/linux/tab/:activeTabIndex",
|
||||||
|
name: "LinuxActiveTabIndex",
|
||||||
|
meta: {
|
||||||
|
title: "linux",
|
||||||
|
notShow: true,
|
||||||
|
},
|
||||||
|
component: () =>
|
||||||
|
import(/* webpackChunkName: "layer" */ "@/views/Layer.vue"),
|
||||||
|
},
|
||||||
// {
|
// {
|
||||||
// path: "/infrastructure/vm",
|
// path: "/infrastructure/vm",
|
||||||
// name: "VirtualMachine",
|
// name: "VirtualMachine",
|
||||||
|
@@ -33,20 +33,42 @@ export const routesK8s: Array<RouteRecordRaw> = [
|
|||||||
path: "/kubernetes/cluster",
|
path: "/kubernetes/cluster",
|
||||||
name: "KubernetesCluster",
|
name: "KubernetesCluster",
|
||||||
meta: {
|
meta: {
|
||||||
|
notShow: false,
|
||||||
title: "kubernetesCluster",
|
title: "kubernetesCluster",
|
||||||
},
|
},
|
||||||
component: () =>
|
component: () =>
|
||||||
import(/* webpackChunkName: "layer" */ "@/views/Layer.vue"),
|
import(/* webpackChunkName: "layer" */ "@/views/Layer.vue"),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: "/kubernetes/cluster/tab/:activeTabIndex",
|
||||||
|
name: "KubernetesClusterActiveTabIndex",
|
||||||
|
meta: {
|
||||||
|
notShow: true,
|
||||||
|
title: "kubernetesClusterActiveTabIndex",
|
||||||
|
},
|
||||||
|
component: () =>
|
||||||
|
import(/* webpackChunkName: "layer" */ "@/views/Layer.vue"),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: "/kubernetes/service",
|
path: "/kubernetes/service",
|
||||||
name: "KubernetesService",
|
name: "KubernetesService",
|
||||||
meta: {
|
meta: {
|
||||||
|
notShow: false,
|
||||||
title: "kubernetesService",
|
title: "kubernetesService",
|
||||||
},
|
},
|
||||||
component: () =>
|
component: () =>
|
||||||
import(/* webpackChunkName: "layer" */ "@/views/Layer.vue"),
|
import(/* webpackChunkName: "layer" */ "@/views/Layer.vue"),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: "/kubernetes/service/tab/:activeTabIndex",
|
||||||
|
name: "KubernetesServiceActiveTabIndex",
|
||||||
|
meta: {
|
||||||
|
notShow: true,
|
||||||
|
title: "kubernetesServiceActiveTabIndex",
|
||||||
|
},
|
||||||
|
component: () =>
|
||||||
|
import(/* webpackChunkName: "layer" */ "@/views/Layer.vue"),
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
@@ -34,7 +34,15 @@ export const routesSelf: Array<RouteRecordRaw> = [
|
|||||||
name: "SkyWalkingServer",
|
name: "SkyWalkingServer",
|
||||||
meta: {
|
meta: {
|
||||||
title: "skyWalkingServer",
|
title: "skyWalkingServer",
|
||||||
headPath: "/mesh/services",
|
},
|
||||||
|
component: () =>
|
||||||
|
import(/* webpackChunkName: "layer" */ "@/views/Layer.vue"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "/self/skyWalkingServer/tab/:activeTabIndex",
|
||||||
|
name: "SkyWalkingServerActiveTabIndex",
|
||||||
|
meta: {
|
||||||
|
notShow: true,
|
||||||
},
|
},
|
||||||
component: () =>
|
component: () =>
|
||||||
import(/* webpackChunkName: "layer" */ "@/views/Layer.vue"),
|
import(/* webpackChunkName: "layer" */ "@/views/Layer.vue"),
|
||||||
@@ -44,7 +52,15 @@ export const routesSelf: Array<RouteRecordRaw> = [
|
|||||||
name: "Satellite",
|
name: "Satellite",
|
||||||
meta: {
|
meta: {
|
||||||
title: "satellite",
|
title: "satellite",
|
||||||
headPath: "/mesh/controlPanel",
|
},
|
||||||
|
component: () =>
|
||||||
|
import(/* webpackChunkName: "layer" */ "@/views/Layer.vue"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "/self/satellite/tab/:activeTabIndex",
|
||||||
|
name: "SatelliteActiveTabIndex",
|
||||||
|
meta: {
|
||||||
|
notShow: true,
|
||||||
},
|
},
|
||||||
component: () =>
|
component: () =>
|
||||||
import(/* webpackChunkName: "layer" */ "@/views/Layer.vue"),
|
import(/* webpackChunkName: "layer" */ "@/views/Layer.vue"),
|
||||||
|
@@ -33,8 +33,17 @@ export const routesMesh: Array<RouteRecordRaw> = [
|
|||||||
path: "/mesh/services",
|
path: "/mesh/services",
|
||||||
name: "MeshServices",
|
name: "MeshServices",
|
||||||
meta: {
|
meta: {
|
||||||
|
notShow: false,
|
||||||
title: "services",
|
title: "services",
|
||||||
headPath: "/mesh/services",
|
},
|
||||||
|
component: () =>
|
||||||
|
import(/* webpackChunkName: "layer" */ "@/views/Layer.vue"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "/mesh/services/tab/:activeTabIndex",
|
||||||
|
name: "MeshServicesActiveTabIndex",
|
||||||
|
meta: {
|
||||||
|
notShow: true,
|
||||||
},
|
},
|
||||||
component: () =>
|
component: () =>
|
||||||
import(/* webpackChunkName: "layer" */ "@/views/Layer.vue"),
|
import(/* webpackChunkName: "layer" */ "@/views/Layer.vue"),
|
||||||
@@ -43,8 +52,17 @@ export const routesMesh: Array<RouteRecordRaw> = [
|
|||||||
path: "/mesh/controlPanel",
|
path: "/mesh/controlPanel",
|
||||||
name: "ControlPanel",
|
name: "ControlPanel",
|
||||||
meta: {
|
meta: {
|
||||||
|
notShow: false,
|
||||||
title: "controlPanel",
|
title: "controlPanel",
|
||||||
headPath: "/mesh/controlPanel",
|
},
|
||||||
|
component: () =>
|
||||||
|
import(/* webpackChunkName: "layer" */ "@/views/Layer.vue"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "/mesh/controlPanel/tab/:activeTabIndex",
|
||||||
|
name: "ControlPanelActiveTabIndex",
|
||||||
|
meta: {
|
||||||
|
notShow: true,
|
||||||
},
|
},
|
||||||
component: () =>
|
component: () =>
|
||||||
import(/* webpackChunkName: "layer" */ "@/views/Layer.vue"),
|
import(/* webpackChunkName: "layer" */ "@/views/Layer.vue"),
|
||||||
@@ -53,10 +71,21 @@ export const routesMesh: Array<RouteRecordRaw> = [
|
|||||||
path: "/mesh/dataPanel",
|
path: "/mesh/dataPanel",
|
||||||
name: "DataPanel",
|
name: "DataPanel",
|
||||||
meta: {
|
meta: {
|
||||||
|
notShow: false,
|
||||||
title: "dataPanel",
|
title: "dataPanel",
|
||||||
headPath: "/mesh/dataPanel",
|
|
||||||
},
|
},
|
||||||
component: () => import("@/views/Layer.vue"),
|
component: () =>
|
||||||
|
import(/* webpackChunkName: "layer" */ "@/views/Layer.vue"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "/mesh/dataPanel/tab/:activeTabIndex",
|
||||||
|
name: "DataPanelActiveTabIndex",
|
||||||
|
meta: {
|
||||||
|
notShow: true,
|
||||||
|
title: "dataPanelActiveTabIndex",
|
||||||
|
},
|
||||||
|
component: () =>
|
||||||
|
import(/* webpackChunkName: "layer" */ "@/views/Layer.vue"),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
@@ -29,3 +29,11 @@ export const TextConfig = {
|
|||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
textAlign: "left",
|
textAlign: "left",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const TimeRangeConfig = {
|
||||||
|
fontColor: "black",
|
||||||
|
backgroundColor: "white",
|
||||||
|
fontSize: 14,
|
||||||
|
textAlign: "center",
|
||||||
|
text: "text",
|
||||||
|
};
|
||||||
|
@@ -34,6 +34,7 @@ interface AppState {
|
|||||||
pageTitle: string;
|
pageTitle: string;
|
||||||
version: string;
|
version: string;
|
||||||
isMobile: boolean;
|
isMobile: boolean;
|
||||||
|
reloadTimer: Nullable<any>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const appStore = defineStore({
|
export const appStore = defineStore({
|
||||||
@@ -53,6 +54,7 @@ export const appStore = defineStore({
|
|||||||
pageTitle: "",
|
pageTitle: "",
|
||||||
version: "",
|
version: "",
|
||||||
isMobile: false,
|
isMobile: false,
|
||||||
|
reloadTimer: null,
|
||||||
}),
|
}),
|
||||||
getters: {
|
getters: {
|
||||||
duration(): Duration {
|
duration(): Duration {
|
||||||
@@ -117,12 +119,18 @@ export const appStore = defineStore({
|
|||||||
}
|
}
|
||||||
this.runEventStack();
|
this.runEventStack();
|
||||||
},
|
},
|
||||||
|
updateDurationRow(data: Duration) {
|
||||||
|
this.durationRow = data;
|
||||||
|
},
|
||||||
setUTC(utcHour: number, utcMin: number): void {
|
setUTC(utcHour: number, utcMin: number): void {
|
||||||
this.runEventStack();
|
this.runEventStack();
|
||||||
this.utcMin = utcMin;
|
this.utcMin = utcMin;
|
||||||
this.utcHour = utcHour;
|
this.utcHour = utcHour;
|
||||||
this.utc = `${utcHour}:${utcMin}`;
|
this.utc = `${utcHour}:${utcMin}`;
|
||||||
},
|
},
|
||||||
|
updateUTC(data: string) {
|
||||||
|
this.utc = data;
|
||||||
|
},
|
||||||
setIsMobile(mode: boolean) {
|
setIsMobile(mode: boolean) {
|
||||||
this.isMobile = mode;
|
this.isMobile = mode;
|
||||||
},
|
},
|
||||||
@@ -153,10 +161,9 @@ export const appStore = defineStore({
|
|||||||
.params({});
|
.params({});
|
||||||
if (res.data.errors) {
|
if (res.data.errors) {
|
||||||
this.utc = -(new Date().getTimezoneOffset() / 60) + ":0";
|
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(":");
|
const utcArr = this.utc.split(":");
|
||||||
this.utcHour = isNaN(Number(utcArr[0])) ? 0 : Number(utcArr[0]);
|
this.utcHour = isNaN(Number(utcArr[0])) ? 0 : Number(utcArr[0]);
|
||||||
this.utcMin = isNaN(Number(utcArr[1])) ? 0 : Number(utcArr[1]);
|
this.utcMin = isNaN(Number(utcArr[1])) ? 0 : Number(utcArr[1]);
|
||||||
@@ -173,6 +180,9 @@ export const appStore = defineStore({
|
|||||||
this.version = res.data.data.version;
|
this.version = res.data.data.version;
|
||||||
return res.data;
|
return res.data;
|
||||||
},
|
},
|
||||||
|
setReloadTimer(timer: any): void {
|
||||||
|
this.reloadTimer = timer;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
export function useAppStoreWithOut(): any {
|
export function useAppStoreWithOut(): any {
|
||||||
|
@@ -21,7 +21,7 @@ import graphql from "@/graphql";
|
|||||||
import query from "@/graphql/fetch";
|
import query from "@/graphql/fetch";
|
||||||
import { DashboardItem } from "@/types/dashboard";
|
import { DashboardItem } from "@/types/dashboard";
|
||||||
import { useSelectorStore } from "@/store/modules/selectors";
|
import { useSelectorStore } from "@/store/modules/selectors";
|
||||||
import { NewControl, TextConfig } from "../data";
|
import { NewControl, TextConfig, TimeRangeConfig } from "../data";
|
||||||
import { AxiosResponse } from "axios";
|
import { AxiosResponse } from "axios";
|
||||||
import { ElMessage } from "element-plus";
|
import { ElMessage } from "element-plus";
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
@@ -39,6 +39,7 @@ interface DashboardState {
|
|||||||
dashboards: DashboardItem[];
|
dashboards: DashboardItem[];
|
||||||
currentDashboard: Nullable<DashboardItem>;
|
currentDashboard: Nullable<DashboardItem>;
|
||||||
editMode: boolean;
|
editMode: boolean;
|
||||||
|
currentTabIndex: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const dashboardStore = defineStore({
|
export const dashboardStore = defineStore({
|
||||||
@@ -56,6 +57,7 @@ export const dashboardStore = defineStore({
|
|||||||
dashboards: [],
|
dashboards: [],
|
||||||
currentDashboard: null,
|
currentDashboard: null,
|
||||||
editMode: false,
|
editMode: false,
|
||||||
|
currentTabIndex: 0,
|
||||||
}),
|
}),
|
||||||
actions: {
|
actions: {
|
||||||
setLayout(data: LayoutConfig[]) {
|
setLayout(data: LayoutConfig[]) {
|
||||||
@@ -80,6 +82,7 @@ export const dashboardStore = defineStore({
|
|||||||
const newItem: LayoutConfig = {
|
const newItem: LayoutConfig = {
|
||||||
...NewControl,
|
...NewControl,
|
||||||
i: index,
|
i: index,
|
||||||
|
id: index,
|
||||||
type,
|
type,
|
||||||
metricTypes: [""],
|
metricTypes: [""],
|
||||||
metrics: [""],
|
metrics: [""],
|
||||||
@@ -111,11 +114,14 @@ export const dashboardStore = defineStore({
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
type === "Trace" ||
|
[
|
||||||
type === "Profile" ||
|
"Trace",
|
||||||
type === "Log" ||
|
"Profile",
|
||||||
type === "Ebpf" ||
|
"Log",
|
||||||
type === "DemandLog"
|
"DemandLog",
|
||||||
|
"Ebpf",
|
||||||
|
"NetworkProfiling",
|
||||||
|
].includes(type)
|
||||||
) {
|
) {
|
||||||
newItem.h = 36;
|
newItem.h = 36;
|
||||||
}
|
}
|
||||||
@@ -123,6 +129,11 @@ export const dashboardStore = defineStore({
|
|||||||
newItem.h = 6;
|
newItem.h = 6;
|
||||||
newItem.graph = TextConfig;
|
newItem.graph = TextConfig;
|
||||||
}
|
}
|
||||||
|
if (type === "TimeRange") {
|
||||||
|
newItem.w = 8;
|
||||||
|
newItem.h = 6;
|
||||||
|
newItem.graph = TimeRangeConfig;
|
||||||
|
}
|
||||||
this.activedGridItem = newItem.i;
|
this.activedGridItem = newItem.i;
|
||||||
this.selectedGrid = newItem;
|
this.selectedGrid = newItem;
|
||||||
this.layout = this.layout.map((d: LayoutConfig) => {
|
this.layout = this.layout.map((d: LayoutConfig) => {
|
||||||
@@ -158,9 +169,11 @@ export const dashboardStore = defineStore({
|
|||||||
if (!children.length) {
|
if (!children.length) {
|
||||||
index = "0";
|
index = "0";
|
||||||
}
|
}
|
||||||
|
const id = `${activedGridItem}-${tabIndex}-${index}`;
|
||||||
const newItem: LayoutConfig = {
|
const newItem: LayoutConfig = {
|
||||||
...NewControl,
|
...NewControl,
|
||||||
i: index,
|
i: index,
|
||||||
|
id,
|
||||||
type,
|
type,
|
||||||
metricTypes: [""],
|
metricTypes: [""],
|
||||||
metrics: [""],
|
metrics: [""],
|
||||||
@@ -172,11 +185,14 @@ export const dashboardStore = defineStore({
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
type === "Trace" ||
|
[
|
||||||
type === "Profile" ||
|
"Trace",
|
||||||
type === "Log" ||
|
"Profile",
|
||||||
type === "DemandLog" ||
|
"Log",
|
||||||
type === "Ebpf"
|
"DemandLog",
|
||||||
|
"Ebpf",
|
||||||
|
"NetworkProfiling",
|
||||||
|
].includes(type)
|
||||||
) {
|
) {
|
||||||
newItem.h = 32;
|
newItem.h = 32;
|
||||||
}
|
}
|
||||||
@@ -184,6 +200,11 @@ export const dashboardStore = defineStore({
|
|||||||
newItem.h = 6;
|
newItem.h = 6;
|
||||||
newItem.graph = TextConfig;
|
newItem.graph = TextConfig;
|
||||||
}
|
}
|
||||||
|
if (type === "TimeRange") {
|
||||||
|
newItem.w = 8;
|
||||||
|
newItem.h = 6;
|
||||||
|
newItem.graph = TextConfig;
|
||||||
|
}
|
||||||
if (this.layout[idx].children) {
|
if (this.layout[idx].children) {
|
||||||
const items = children.map((d: LayoutConfig) => {
|
const items = children.map((d: LayoutConfig) => {
|
||||||
d.y = d.y + newItem.h;
|
d.y = d.y + newItem.h;
|
||||||
@@ -198,6 +219,7 @@ export const dashboardStore = defineStore({
|
|||||||
this.activedGridItem = index;
|
this.activedGridItem = index;
|
||||||
},
|
},
|
||||||
setActiveTabIndex(index: number, target?: number) {
|
setActiveTabIndex(index: number, target?: number) {
|
||||||
|
this.currentTabIndex = index;
|
||||||
const m = target || this.activedGridItem;
|
const m = target || this.activedGridItem;
|
||||||
const idx = this.layout.findIndex((d: LayoutConfig) => d.i === m);
|
const idx = this.layout.findIndex((d: LayoutConfig) => d.i === m);
|
||||||
if (idx < 0) {
|
if (idx < 0) {
|
||||||
@@ -287,6 +309,28 @@ export const dashboardStore = defineStore({
|
|||||||
};
|
};
|
||||||
this.selectedGrid = this.layout[index];
|
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) {
|
async fetchMetricType(item: string) {
|
||||||
const res: AxiosResponse = await graphql
|
const res: AxiosResponse = await graphql
|
||||||
.query("queryTypeOfMetrics")
|
.query("queryTypeOfMetrics")
|
||||||
|
@@ -25,8 +25,7 @@ import {
|
|||||||
import { store } from "@/store";
|
import { store } from "@/store";
|
||||||
import graphql from "@/graphql";
|
import graphql from "@/graphql";
|
||||||
import { AxiosResponse } from "axios";
|
import { AxiosResponse } from "axios";
|
||||||
|
interface EbpfState {
|
||||||
interface EbpfStore {
|
|
||||||
taskList: EBPFTaskList[];
|
taskList: EBPFTaskList[];
|
||||||
eBPFSchedules: EBPFProfilingSchedule[];
|
eBPFSchedules: EBPFProfilingSchedule[];
|
||||||
currentSchedule: EBPFProfilingSchedule | Record<string, never>;
|
currentSchedule: EBPFProfilingSchedule | Record<string, never>;
|
||||||
@@ -40,7 +39,7 @@ interface EbpfStore {
|
|||||||
|
|
||||||
export const ebpfStore = defineStore({
|
export const ebpfStore = defineStore({
|
||||||
id: "eBPF",
|
id: "eBPF",
|
||||||
state: (): EbpfStore => ({
|
state: (): EbpfState => ({
|
||||||
taskList: [],
|
taskList: [],
|
||||||
eBPFSchedules: [],
|
eBPFSchedules: [],
|
||||||
currentSchedule: {},
|
currentSchedule: {},
|
||||||
@@ -53,7 +52,7 @@ export const ebpfStore = defineStore({
|
|||||||
}),
|
}),
|
||||||
actions: {
|
actions: {
|
||||||
setSelectedTask(task: EBPFTaskList) {
|
setSelectedTask(task: EBPFTaskList) {
|
||||||
this.selectedTask = task;
|
this.selectedTask = task || {};
|
||||||
},
|
},
|
||||||
setCurrentSchedule(s: EBPFProfilingSchedule) {
|
setCurrentSchedule(s: EBPFProfilingSchedule) {
|
||||||
this.currentSchedule = s;
|
this.currentSchedule = s;
|
||||||
@@ -84,22 +83,31 @@ export const ebpfStore = defineStore({
|
|||||||
if (res.data.errors) {
|
if (res.data.errors) {
|
||||||
return res.data;
|
return res.data;
|
||||||
}
|
}
|
||||||
this.getTaskList(param.serviceId);
|
this.getTaskList({
|
||||||
|
serviceId: param.serviceId,
|
||||||
|
targets: ["ON_CPU", "OFF_CPU"],
|
||||||
|
});
|
||||||
return res.data;
|
return res.data;
|
||||||
},
|
},
|
||||||
async getTaskList(serviceId: string) {
|
async getTaskList(params: {
|
||||||
if (!serviceId) {
|
serviceId: string;
|
||||||
|
serviceInstanceId: string;
|
||||||
|
targets: string[];
|
||||||
|
}) {
|
||||||
|
if (!params.serviceId) {
|
||||||
return new Promise((resolve) => resolve({}));
|
return new Promise((resolve) => resolve({}));
|
||||||
}
|
}
|
||||||
const res: AxiosResponse = await graphql
|
const res: AxiosResponse = await graphql
|
||||||
.query("getEBPFTasks")
|
.query("getEBPFTasks")
|
||||||
.params({ serviceId });
|
.params(params);
|
||||||
|
|
||||||
this.tip = "";
|
this.tip = "";
|
||||||
if (res.data.errors) {
|
if (res.data.errors) {
|
||||||
return res.data;
|
return res.data;
|
||||||
}
|
}
|
||||||
this.taskList = res.data.data.queryEBPFTasks || [];
|
this.taskList = res.data.data.queryEBPFTasks || [];
|
||||||
|
this.selectedTask = this.taskList[0] || {};
|
||||||
|
this.setSelectedTask(this.selectedTask);
|
||||||
if (!this.taskList.length) {
|
if (!this.taskList.length) {
|
||||||
return res.data;
|
return res.data;
|
||||||
}
|
}
|
||||||
|
@@ -19,16 +19,16 @@ import { store } from "@/store";
|
|||||||
import graphql from "@/graphql";
|
import graphql from "@/graphql";
|
||||||
import { AxiosResponse } from "axios";
|
import { AxiosResponse } from "axios";
|
||||||
import { Event, QueryEventCondition } from "@/types/events";
|
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 { useAppStoreWithOut } from "@/store/modules/app";
|
||||||
|
import { useSelectorStore } from "@/store/modules/selectors";
|
||||||
|
|
||||||
interface eventState {
|
interface eventState {
|
||||||
loading: boolean;
|
loading: boolean;
|
||||||
events: Event[];
|
events: Event[];
|
||||||
services: Service[];
|
|
||||||
instances: Instance[];
|
instances: Instance[];
|
||||||
endpoints: Endpoint[];
|
endpoints: Endpoint[];
|
||||||
condition: QueryEventCondition | any;
|
condition: Nullable<QueryEventCondition>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const eventStore = defineStore({
|
export const eventStore = defineStore({
|
||||||
@@ -36,32 +36,18 @@ export const eventStore = defineStore({
|
|||||||
state: (): eventState => ({
|
state: (): eventState => ({
|
||||||
loading: false,
|
loading: false,
|
||||||
events: [],
|
events: [],
|
||||||
services: [{ value: "", label: "All" }],
|
|
||||||
instances: [{ value: "", label: "All" }],
|
instances: [{ value: "", label: "All" }],
|
||||||
endpoints: [{ value: "", label: "All" }],
|
endpoints: [{ value: "", label: "All" }],
|
||||||
condition: {
|
condition: null,
|
||||||
paging: { pageNum: 1, pageSize: 15 },
|
|
||||||
},
|
|
||||||
}),
|
}),
|
||||||
actions: {
|
actions: {
|
||||||
setEventCondition(data: any) {
|
setEventCondition(data: QueryEventCondition) {
|
||||||
this.condition = { ...this.condition, ...data };
|
this.condition = data;
|
||||||
},
|
},
|
||||||
async getServices(layer: string) {
|
async getInstances() {
|
||||||
if (!layer) {
|
const serviceId = useSelectorStore().currentService
|
||||||
this.services = [{ value: "", label: "All" }];
|
? useSelectorStore().currentService.id
|
||||||
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) {
|
|
||||||
const res: AxiosResponse = await graphql.query("queryInstances").params({
|
const res: AxiosResponse = await graphql.query("queryInstances").params({
|
||||||
serviceId,
|
serviceId,
|
||||||
duration: useAppStoreWithOut().durationTime,
|
duration: useAppStoreWithOut().durationTime,
|
||||||
@@ -75,7 +61,13 @@ export const eventStore = defineStore({
|
|||||||
];
|
];
|
||||||
return res.data;
|
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({
|
const res: AxiosResponse = await graphql.query("queryEndpoints").params({
|
||||||
serviceId,
|
serviceId,
|
||||||
duration: useAppStoreWithOut().durationTime,
|
duration: useAppStoreWithOut().durationTime,
|
||||||
@@ -112,6 +104,9 @@ export const eventStore = defineStore({
|
|||||||
scope = "Endpoint";
|
scope = "Endpoint";
|
||||||
}
|
}
|
||||||
item.scope = scope;
|
item.scope = scope;
|
||||||
|
if (!item.endTime || item.endTime === item.startTime) {
|
||||||
|
item.endTime = Number(item.startTime) + 60000;
|
||||||
|
}
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@@ -53,6 +53,13 @@ export const logStore = defineStore({
|
|||||||
setLogCondition(data: any) {
|
setLogCondition(data: any) {
|
||||||
this.conditions = { ...this.conditions, ...data };
|
this.conditions = { ...this.conditions, ...data };
|
||||||
},
|
},
|
||||||
|
resetState() {
|
||||||
|
this.logs = [];
|
||||||
|
this.conditions = {
|
||||||
|
queryDuration: useAppStoreWithOut().durationTime,
|
||||||
|
paging: { pageNum: 1, pageSize: 15 },
|
||||||
|
};
|
||||||
|
},
|
||||||
async getServices(layer: string) {
|
async getServices(layer: string) {
|
||||||
const res: AxiosResponse = await graphql.query("queryServices").params({
|
const res: AxiosResponse = await graphql.query("queryServices").params({
|
||||||
layer,
|
layer,
|
||||||
|
183
src/store/modules/network-profiling.ts
Normal file
@@ -0,0 +1,183 @@
|
|||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
}, []);
|
||||||
|
calls = calls.map((d: any) => {
|
||||||
|
d.sourceId = d.source;
|
||||||
|
d.targetId = d.target;
|
||||||
|
d.source = d.sourceObj;
|
||||||
|
d.target = d.targetObj;
|
||||||
|
delete d.sourceObj;
|
||||||
|
delete d.targetObj;
|
||||||
|
return d;
|
||||||
|
});
|
||||||
|
this.calls = calls;
|
||||||
|
this.nodes = data.nodes;
|
||||||
|
},
|
||||||
|
async createNetworkTask(param: {
|
||||||
|
serviceId: string;
|
||||||
|
serviceInstanceId: string;
|
||||||
|
}) {
|
||||||
|
const res: AxiosResponse = await graphql
|
||||||
|
.query("newNetworkProfiling")
|
||||||
|
.params({ request: { instanceId: param.serviceInstanceId } });
|
||||||
|
|
||||||
|
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);
|
||||||
|
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);
|
||||||
|
}
|
@@ -15,7 +15,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
import { defineStore } from "pinia";
|
import { defineStore } from "pinia";
|
||||||
import { Service, Instance, Endpoint } from "@/types/selector";
|
import { Service, Instance, Endpoint, Process } from "@/types/selector";
|
||||||
import { store } from "@/store";
|
import { store } from "@/store";
|
||||||
import graphql from "@/graphql";
|
import graphql from "@/graphql";
|
||||||
import { AxiosResponse } from "axios";
|
import { AxiosResponse } from "axios";
|
||||||
@@ -24,11 +24,15 @@ interface SelectorState {
|
|||||||
services: Service[];
|
services: Service[];
|
||||||
destServices: Service[];
|
destServices: Service[];
|
||||||
pods: Array<Instance | Endpoint>;
|
pods: Array<Instance | Endpoint>;
|
||||||
|
processes: Process[];
|
||||||
|
destProcesses: Process[];
|
||||||
currentService: Nullable<Service>;
|
currentService: Nullable<Service>;
|
||||||
currentPod: Nullable<Instance | Endpoint>;
|
currentPod: Nullable<Instance | Endpoint>;
|
||||||
|
currentProcess: Nullable<Process>;
|
||||||
currentDestService: Nullable<Service>;
|
currentDestService: Nullable<Service>;
|
||||||
currentDestPod: Nullable<Instance | Endpoint>;
|
currentDestPod: Nullable<Instance | Endpoint>;
|
||||||
destPods: Array<Instance | Endpoint>;
|
destPods: Array<Instance | Endpoint>;
|
||||||
|
currentDestProcess: Nullable<Process>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const selectorStore = defineStore({
|
export const selectorStore = defineStore({
|
||||||
@@ -38,10 +42,14 @@ export const selectorStore = defineStore({
|
|||||||
destServices: [],
|
destServices: [],
|
||||||
pods: [],
|
pods: [],
|
||||||
destPods: [],
|
destPods: [],
|
||||||
|
processes: [],
|
||||||
|
destProcesses: [],
|
||||||
currentService: null,
|
currentService: null,
|
||||||
currentPod: null,
|
currentPod: null,
|
||||||
|
currentProcess: null,
|
||||||
currentDestService: null,
|
currentDestService: null,
|
||||||
currentDestPod: null,
|
currentDestPod: null,
|
||||||
|
currentDestProcess: null,
|
||||||
}),
|
}),
|
||||||
actions: {
|
actions: {
|
||||||
setCurrentService(service: Nullable<Service>) {
|
setCurrentService(service: Nullable<Service>) {
|
||||||
@@ -56,6 +64,18 @@ export const selectorStore = defineStore({
|
|||||||
setCurrentDestPod(pod: Nullable<Instance | Endpoint>) {
|
setCurrentDestPod(pod: Nullable<Instance | Endpoint>) {
|
||||||
this.currentDestPod = pod;
|
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> {
|
async fetchLayers(): Promise<AxiosResponse> {
|
||||||
const res: AxiosResponse = await graphql.query("queryLayers").params({});
|
const res: AxiosResponse = await graphql.query("queryLayers").params({});
|
||||||
|
|
||||||
@@ -93,6 +113,27 @@ export const selectorStore = defineStore({
|
|||||||
}
|
}
|
||||||
return res.data;
|
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: {
|
async getEndpoints(params: {
|
||||||
keyword?: string;
|
keyword?: string;
|
||||||
serviceId?: string;
|
serviceId?: string;
|
||||||
@@ -176,6 +217,25 @@ export const selectorStore = defineStore({
|
|||||||
this.pods = [res.data.data.endpoint];
|
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;
|
return res.data;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@@ -63,6 +63,17 @@ export const traceStore = defineStore({
|
|||||||
setTraceSpans(spans: Span) {
|
setTraceSpans(spans: Span) {
|
||||||
this.traceSpans = spans;
|
this.traceSpans = spans;
|
||||||
},
|
},
|
||||||
|
resetState() {
|
||||||
|
this.traceSpans = [];
|
||||||
|
this.traceList = [];
|
||||||
|
this.currentTrace = {};
|
||||||
|
this.conditions = {
|
||||||
|
queryDuration: useAppStoreWithOut().durationTime,
|
||||||
|
paging: { pageNum: 1, pageSize: 20 },
|
||||||
|
traceState: "ALL",
|
||||||
|
queryOrder: "BY_START_TIME",
|
||||||
|
};
|
||||||
|
},
|
||||||
async getServices(layer: string) {
|
async getServices(layer: string) {
|
||||||
const res: AxiosResponse = await graphql.query("queryServices").params({
|
const res: AxiosResponse = await graphql.query("queryServices").params({
|
||||||
layer,
|
layer,
|
||||||
|
@@ -139,8 +139,10 @@ pre {
|
|||||||
padding-left: 56px !important;
|
padding-left: 56px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.el-icon.menu-icons {
|
.el-sub-menu__title {
|
||||||
margin-top: -3px !important;
|
.el-icon.menu-icons {
|
||||||
|
margin-top: -5px !important;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.el-switch__label--left {
|
.el-switch__label--left {
|
||||||
@@ -154,3 +156,38 @@ pre {
|
|||||||
.switch {
|
.switch {
|
||||||
margin: 0 5px;
|
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: 17px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.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 5px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vis-item.vis-selected.Error,
|
||||||
|
.vis-item.vis-selected.Normal {
|
||||||
|
color: #1a1a1a !important;
|
||||||
|
}
|
||||||
|
28
src/types/dashboard.d.ts
vendored
@@ -36,6 +36,21 @@ export interface LayoutConfig {
|
|||||||
children?: { name: string; children: LayoutConfig[] }[];
|
children?: { name: string; children: LayoutConfig[] }[];
|
||||||
activedTabIndex?: number;
|
activedTabIndex?: number;
|
||||||
metricConfig?: MetricConfigOpt[];
|
metricConfig?: MetricConfigOpt[];
|
||||||
|
id?: string;
|
||||||
|
associate?: { widgetId: string }[];
|
||||||
|
eventAssociate?: boolean;
|
||||||
|
filters?: {
|
||||||
|
dataIndex: number;
|
||||||
|
sourceId: string;
|
||||||
|
isRange?: boolean;
|
||||||
|
duration?: {
|
||||||
|
startTime: string;
|
||||||
|
endTime: string;
|
||||||
|
};
|
||||||
|
traceId?: string;
|
||||||
|
spanId?: string;
|
||||||
|
segmentId?: string;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export type MetricConfigOpt = {
|
export type MetricConfigOpt = {
|
||||||
@@ -48,6 +63,7 @@ export type MetricConfigOpt = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export interface WidgetConfig {
|
export interface WidgetConfig {
|
||||||
|
name?: string;
|
||||||
title?: string;
|
title?: string;
|
||||||
tips?: string;
|
tips?: string;
|
||||||
}
|
}
|
||||||
@@ -137,3 +153,15 @@ export interface TopologyConfig {
|
|||||||
depth?: number;
|
depth?: number;
|
||||||
showDepth?: boolean;
|
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;
|
||||||
|
};
|
||||||
|
24
src/types/ebpf.d.ts
vendored
@@ -15,6 +15,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { Process } from "./selector";
|
||||||
export interface EBPFTaskCreationRequest {
|
export interface EBPFTaskCreationRequest {
|
||||||
serviceId: string;
|
serviceId: string;
|
||||||
processLabels: string[];
|
processLabels: string[];
|
||||||
@@ -43,18 +44,7 @@ export interface EBPFProfilingSchedule {
|
|||||||
startTime: number;
|
startTime: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Process = {
|
export type Process = Process;
|
||||||
id: string;
|
|
||||||
name: string;
|
|
||||||
serviceId: string;
|
|
||||||
serviceName: string;
|
|
||||||
instanceId: string;
|
|
||||||
instanceName: string;
|
|
||||||
agentId: string;
|
|
||||||
detectType: string;
|
|
||||||
attributes: { name: string; value: string }[];
|
|
||||||
labels: string[];
|
|
||||||
};
|
|
||||||
export type StackElement = {
|
export type StackElement = {
|
||||||
id: string;
|
id: string;
|
||||||
originId: string;
|
originId: string;
|
||||||
@@ -75,3 +65,13 @@ export type AnalyzationTrees = {
|
|||||||
dumpCount: number;
|
dumpCount: number;
|
||||||
stackType: string;
|
stackType: string;
|
||||||
};
|
};
|
||||||
|
export type ProcessNode = {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
serviceId: string;
|
||||||
|
serviceName: string;
|
||||||
|
serviceInstanceId: string;
|
||||||
|
serviceInstanceName: string;
|
||||||
|
name: string;
|
||||||
|
isReal: boolean;
|
||||||
|
};
|
||||||
|
13
src/types/selector.d.ts
vendored
@@ -46,3 +46,16 @@ export type Service = {
|
|||||||
layers: string[];
|
layers: string[];
|
||||||
shortName: 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;
|
sourceObj?: any;
|
||||||
targetObj?: any;
|
targetObj?: any;
|
||||||
value?: number;
|
value?: number;
|
||||||
|
lowerArc?: boolean;
|
||||||
|
sourceComponents: string[];
|
||||||
|
targetComponents: string[];
|
||||||
}
|
}
|
||||||
export interface Node {
|
export interface Node {
|
||||||
id: string;
|
id: string;
|
||||||
|
@@ -14,6 +14,7 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
import dayjs from "dayjs";
|
||||||
export default function dateFormatStep(
|
export default function dateFormatStep(
|
||||||
date: Date,
|
date: Date,
|
||||||
step: string,
|
step: string,
|
||||||
@@ -99,3 +100,6 @@ export const dateFormatTime = (date: Date, step: string): string => {
|
|||||||
}
|
}
|
||||||
return "";
|
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 * as echarts from "echarts/core";
|
||||||
|
|
||||||
import {
|
import { BarChart, LineChart, HeatmapChart, SankeyChart } from "echarts/charts";
|
||||||
BarChart,
|
|
||||||
LineChart,
|
|
||||||
PieChart,
|
|
||||||
HeatmapChart,
|
|
||||||
SankeyChart,
|
|
||||||
} from "echarts/charts";
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
TitleComponent,
|
TitleComponent,
|
||||||
@@ -32,6 +26,7 @@ import {
|
|||||||
DataZoomComponent,
|
DataZoomComponent,
|
||||||
VisualMapComponent,
|
VisualMapComponent,
|
||||||
TimelineComponent,
|
TimelineComponent,
|
||||||
|
MarkAreaComponent,
|
||||||
} from "echarts/components";
|
} from "echarts/components";
|
||||||
|
|
||||||
import { SVGRenderer } from "echarts/renderers";
|
import { SVGRenderer } from "echarts/renderers";
|
||||||
@@ -43,13 +38,13 @@ echarts.use([
|
|||||||
GridComponent,
|
GridComponent,
|
||||||
BarChart,
|
BarChart,
|
||||||
LineChart,
|
LineChart,
|
||||||
PieChart,
|
|
||||||
HeatmapChart,
|
HeatmapChart,
|
||||||
SankeyChart,
|
SankeyChart,
|
||||||
SVGRenderer,
|
SVGRenderer,
|
||||||
DataZoomComponent,
|
DataZoomComponent,
|
||||||
VisualMapComponent,
|
VisualMapComponent,
|
||||||
TimelineComponent,
|
TimelineComponent,
|
||||||
|
MarkAreaComponent,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
export default echarts;
|
export default echarts;
|
||||||
|
@@ -24,7 +24,7 @@ import Header from "./alarm/Header.vue";
|
|||||||
import Content from "./alarm/Content.vue";
|
import Content from "./alarm/Content.vue";
|
||||||
|
|
||||||
const appStore = useAppStoreWithOut();
|
const appStore = useAppStoreWithOut();
|
||||||
appStore.setPageTitle("Alarm");
|
appStore.setPageTitle("Alerting");
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.alarm {
|
.alarm {
|
||||||
|
@@ -69,18 +69,16 @@ limitations under the License. -->
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref, reactive } from "vue";
|
import { ref } from "vue";
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
import { useAppStoreWithOut } from "@/store/modules/app";
|
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||||
import timeFormat from "@/utils/timeFormat";
|
import timeFormat from "@/utils/timeFormat";
|
||||||
import { Languages } from "@/constants/data";
|
import { Languages } from "@/constants/data";
|
||||||
import Selector from "@/components/Selector.vue";
|
import Selector from "@/components/Selector.vue";
|
||||||
|
import getLocalTime from "@/utils/localtime";
|
||||||
|
|
||||||
const { t, locale } = useI18n();
|
const { t, locale } = useI18n();
|
||||||
const appStore = useAppStoreWithOut();
|
const appStore = useAppStoreWithOut();
|
||||||
const state = reactive<{ timer: ReturnType<typeof setInterval> | null }>({
|
|
||||||
timer: null,
|
|
||||||
});
|
|
||||||
const lang = ref<string>(locale.value || "en");
|
const lang = ref<string>(locale.value || "en");
|
||||||
const autoTime = ref<number>(6);
|
const autoTime = ref<number>(6);
|
||||||
const auto = ref<boolean>(appStore.autoRefresh || false);
|
const auto = ref<boolean>(appStore.autoRefresh || false);
|
||||||
@@ -91,8 +89,11 @@ appStore.setPageTitle("Setting");
|
|||||||
const handleReload = () => {
|
const handleReload = () => {
|
||||||
const gap =
|
const gap =
|
||||||
appStore.duration.end.getTime() - appStore.duration.start.getTime();
|
appStore.duration.end.getTime() - appStore.duration.start.getTime();
|
||||||
const time: Date[] = [new Date(new Date().getTime() - gap), new Date()];
|
const dates: Date[] = [
|
||||||
appStore.setDuration(timeFormat(time));
|
getLocalTime(appStore.utc, new Date(new Date().getTime() - gap)),
|
||||||
|
getLocalTime(appStore.utc, new Date()),
|
||||||
|
];
|
||||||
|
appStore.setDuration(timeFormat(dates));
|
||||||
};
|
};
|
||||||
const handleAuto = () => {
|
const handleAuto = () => {
|
||||||
if (autoTime.value < 1) {
|
if (autoTime.value < 1) {
|
||||||
@@ -101,10 +102,10 @@ const handleAuto = () => {
|
|||||||
appStore.setAutoRefresh(auto.value);
|
appStore.setAutoRefresh(auto.value);
|
||||||
if (auto.value) {
|
if (auto.value) {
|
||||||
handleReload();
|
handleReload();
|
||||||
state.timer = setInterval(handleReload, autoTime.value * 1000);
|
appStore.setReloadTimer(setInterval(handleReload, autoTime.value * 1000));
|
||||||
} else {
|
} else {
|
||||||
if (state.timer) {
|
if (appStore.reloadTimer) {
|
||||||
clearInterval(state.timer);
|
clearInterval(appStore.reloadTimer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -112,12 +113,12 @@ const changeAutoTime = () => {
|
|||||||
if (autoTime.value < 1) {
|
if (autoTime.value < 1) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (state.timer) {
|
if (appStore.reloadTimer) {
|
||||||
clearInterval(state.timer);
|
clearInterval(appStore.reloadTimer);
|
||||||
}
|
}
|
||||||
if (auto.value) {
|
if (auto.value) {
|
||||||
handleReload();
|
handleReload();
|
||||||
state.timer = setInterval(handleReload, autoTime.value * 1000);
|
appStore.setReloadTimer(setInterval(handleReload, autoTime.value * 1000));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const setLang = (): void => {
|
const setLang = (): void => {
|
||||||
|
@@ -145,16 +145,14 @@ limitations under the License. -->
|
|||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref } from "vue";
|
import { ref } from "vue";
|
||||||
import dayjs from "dayjs";
|
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
import { Alarm, Event } from "@/types/alarm";
|
import { Alarm, Event } from "@/types/alarm";
|
||||||
import { useAlarmStore } from "@/store/modules/alarm";
|
import { useAlarmStore } from "@/store/modules/alarm";
|
||||||
import { EventsDetailHeaders, AlarmDetailCol, EventsDetailKeys } from "./data";
|
import { EventsDetailHeaders, AlarmDetailCol, EventsDetailKeys } from "./data";
|
||||||
|
import { dateFormat } from "@/utils/dateFormat";
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const alarmStore = useAlarmStore();
|
const alarmStore = useAlarmStore();
|
||||||
const dateFormat = (date: number, pattern = "YYYY-MM-DD HH:mm:ss") =>
|
|
||||||
dayjs(date).format(pattern);
|
|
||||||
const isShowDetails = ref<boolean>(false);
|
const isShowDetails = ref<boolean>(false);
|
||||||
const showEventDetails = ref<boolean>(false);
|
const showEventDetails = ref<boolean>(false);
|
||||||
const currentDetail = ref<Alarm | any>({});
|
const currentDetail = ref<Alarm | any>({});
|
||||||
|
@@ -15,11 +15,7 @@ limitations under the License. -->
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<span class="grey">{{ t("tags") }}: </span>
|
<span class="grey">{{ t("tags") }}: </span>
|
||||||
<span
|
<span v-if="tagsList.length" class="trace-tags">
|
||||||
v-if="tagsList.length"
|
|
||||||
class="trace-tags"
|
|
||||||
:style="type === 'LOG' ? `min-width: 122px;` : ''"
|
|
||||||
>
|
|
||||||
<span class="selected" v-for="(item, index) in tagsList" :key="index">
|
<span class="selected" v-for="(item, index) in tagsList" :key="index">
|
||||||
<span>{{ item }}</span>
|
<span>{{ item }}</span>
|
||||||
<span class="remove-icon" @click="removeTags(index)">×</span>
|
<span class="remove-icon" @click="removeTags(index)">×</span>
|
||||||
@@ -33,31 +29,28 @@ limitations under the License. -->
|
|||||||
@change="addLabels"
|
@change="addLabels"
|
||||||
:placeholder="t('addTags')"
|
:placeholder="t('addTags')"
|
||||||
/>
|
/>
|
||||||
<span v-else>
|
<el-popover v-else trigger="click" :visible="visible" width="300px">
|
||||||
<el-input
|
<template #reference>
|
||||||
size="small"
|
<el-input
|
||||||
v-model="tags"
|
size="small"
|
||||||
class="trace-new-tag"
|
v-model="tags"
|
||||||
@click="showClick"
|
class="trace-new-tag"
|
||||||
/>
|
@input="searchTags"
|
||||||
<el-dropdown
|
@blur="visible = false"
|
||||||
ref="dropdownTag"
|
@focus="visible = true"
|
||||||
trigger="contextmenu"
|
/>
|
||||||
:hide-on-click="false"
|
</template>
|
||||||
style="margin: 20px 0 0 -130px"
|
<div class="content">
|
||||||
v-if="tagArr.length"
|
<span
|
||||||
>
|
v-for="(item, index) in tagList"
|
||||||
<template #dropdown>
|
:key="index"
|
||||||
<el-dropdown-menu>
|
@click="selectTag(item)"
|
||||||
<el-dropdown-item v-for="(item, index) in tagArr" :key="index">
|
class="tag-item"
|
||||||
<span @click="selectTag(item)" class="tag-item">
|
>
|
||||||
{{ item }}
|
{{ item }}
|
||||||
</span>
|
</span>
|
||||||
</el-dropdown-item>
|
</div>
|
||||||
</el-dropdown-menu>
|
</el-popover>
|
||||||
</template>
|
|
||||||
</el-dropdown>
|
|
||||||
</span>
|
|
||||||
<span
|
<span
|
||||||
class="tags-tip"
|
class="tags-tip"
|
||||||
:class="type !== 'ALARM' && tagArr.length ? 'link-tips' : ''"
|
:class="type !== 'ALARM' && tagArr.length ? 'link-tips' : ''"
|
||||||
@@ -68,12 +61,12 @@ limitations under the License. -->
|
|||||||
>
|
>
|
||||||
{{ t("tagsLink") }}
|
{{ t("tagsLink") }}
|
||||||
</a>
|
</a>
|
||||||
<el-tooltip :content="t(tipsMap[type])">
|
<el-tooltip :content="t((tipsMap as any)[type])">
|
||||||
<span>
|
<span>
|
||||||
<Icon class="icon-help mr-5" iconName="help" size="middle" />
|
<Icon class="icon-help mr-5" iconName="help" size="middle" />
|
||||||
</span>
|
</span>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
<b v-if="type === 'AL'">{{ t("noticeTag") }}</b>
|
<b v-if="type === 'ALARM'">{{ t("noticeTag") }}</b>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -85,7 +78,7 @@ import { useLogStore } from "@/store/modules/log";
|
|||||||
import { ElMessage } from "element-plus";
|
import { ElMessage } from "element-plus";
|
||||||
import { useAppStoreWithOut } from "@/store/modules/app";
|
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||||
|
|
||||||
/*global Nullable, defineEmits, defineProps */
|
/*global defineEmits, defineProps */
|
||||||
const emit = defineEmits(["update"]);
|
const emit = defineEmits(["update"]);
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
type: { type: String, default: "TRACE" },
|
type: { type: String, default: "TRACE" },
|
||||||
@@ -97,13 +90,14 @@ const { t } = useI18n();
|
|||||||
const tags = ref<string>("");
|
const tags = ref<string>("");
|
||||||
const tagsList = ref<string[]>([]);
|
const tagsList = ref<string[]>([]);
|
||||||
const tagArr = ref<string[]>([]);
|
const tagArr = ref<string[]>([]);
|
||||||
|
const tagList = ref<string[]>([]);
|
||||||
const tagKeys = ref<string[]>([]);
|
const tagKeys = ref<string[]>([]);
|
||||||
|
const visible = ref<boolean>(false);
|
||||||
const tipsMap = {
|
const tipsMap = {
|
||||||
LOG: "logTagsTip",
|
LOG: "logTagsTip",
|
||||||
TRACE: "traceTagsTip",
|
TRACE: "traceTagsTip",
|
||||||
ALARM: "alarmTagsTip",
|
ALARM: "alarmTagsTip",
|
||||||
};
|
};
|
||||||
const dropdownTag = ref<Nullable<any>>(null);
|
|
||||||
|
|
||||||
fetchTagKeys();
|
fetchTagKeys();
|
||||||
|
|
||||||
@@ -143,6 +137,7 @@ async function fetchTagKeys() {
|
|||||||
}
|
}
|
||||||
tagArr.value = resp.data.tagKeys;
|
tagArr.value = resp.data.tagKeys;
|
||||||
tagKeys.value = resp.data.tagKeys;
|
tagKeys.value = resp.data.tagKeys;
|
||||||
|
searchTags();
|
||||||
}
|
}
|
||||||
|
|
||||||
async function fetchTagValues() {
|
async function fetchTagValues() {
|
||||||
@@ -159,25 +154,36 @@ async function fetchTagValues() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
tagArr.value = resp.data.tagValues;
|
tagArr.value = resp.data.tagValues;
|
||||||
|
searchTags();
|
||||||
}
|
}
|
||||||
|
|
||||||
function selectTag(item: string) {
|
function selectTag(item: string) {
|
||||||
if (tags.value.includes("=")) {
|
if (tags.value.includes("=")) {
|
||||||
tags.value += item;
|
const key = tags.value.split("=")[0];
|
||||||
|
tags.value = key + "=" + item;
|
||||||
addLabels();
|
addLabels();
|
||||||
tagArr.value = tagKeys.value;
|
tagArr.value = tagKeys.value;
|
||||||
dropdownTag.value.handleClose();
|
searchTags();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
tags.value = item + "=";
|
tags.value = item + "=";
|
||||||
fetchTagValues();
|
fetchTagValues();
|
||||||
}
|
}
|
||||||
|
|
||||||
function showClick() {
|
function searchTags() {
|
||||||
if (dropdownTag.value) {
|
if (!tags.value) {
|
||||||
dropdownTag.value.handleOpen();
|
tagList.value = tagArr.value;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
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(
|
watch(
|
||||||
() => appStore.durationTime,
|
() => appStore.durationTime,
|
||||||
() => {
|
() => {
|
||||||
@@ -221,6 +227,12 @@ watch(
|
|||||||
.tag-item {
|
.tag-item {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
min-width: 210px;
|
min-width: 210px;
|
||||||
|
cursor: pointer;
|
||||||
|
margin-top: 10px;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: #409eff;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.tags-tip {
|
.tags-tip {
|
||||||
@@ -229,7 +241,6 @@ watch(
|
|||||||
|
|
||||||
.link-tips {
|
.link-tips {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
margin-left: 130px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.light {
|
.light {
|
||||||
@@ -247,4 +258,10 @@ watch(
|
|||||||
.icon-help {
|
.icon-help {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
width: 300px;
|
||||||
|
max-height: 400px;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@@ -41,6 +41,7 @@ import Tool from "./panel/Tool.vue";
|
|||||||
import { useDashboardStore } from "@/store/modules/dashboard";
|
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||||
import { useAppStoreWithOut } from "@/store/modules/app";
|
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||||
import Configuration from "./configuration";
|
import Configuration from "./configuration";
|
||||||
|
import { LayoutConfig } from "@/types/dashboard";
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: "Dashboard",
|
name: "Dashboard",
|
||||||
@@ -66,7 +67,8 @@ export default defineComponent({
|
|||||||
sessionStorage.getItem(layoutKey.value) || "{}"
|
sessionStorage.getItem(layoutKey.value) || "{}"
|
||||||
);
|
);
|
||||||
const layout: any = c.configuration || {};
|
const layout: any = c.configuration || {};
|
||||||
dashboardStore.setLayout(layout.children || []);
|
|
||||||
|
dashboardStore.setLayout(setWidgetsID(layout.children || []));
|
||||||
appStore.setPageTitle(layout.name);
|
appStore.setPageTitle(layout.name);
|
||||||
if (p.entity) {
|
if (p.entity) {
|
||||||
dashboardStore.setCurrentDashboard({
|
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) {
|
function handleClick(e: any) {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
if (e.target.className === "ds-main") {
|
if (e.target.className === "ds-main") {
|
||||||
|
@@ -20,7 +20,7 @@ limitations under the License. -->
|
|||||||
placeholder="Please input name"
|
placeholder="Please input name"
|
||||||
class="input-with-search ml-10"
|
class="input-with-search ml-10"
|
||||||
size="small"
|
size="small"
|
||||||
@change="searchDashboards"
|
@change="searchDashboards(1)"
|
||||||
>
|
>
|
||||||
<template #append>
|
<template #append>
|
||||||
<el-button size="small">
|
<el-button size="small">
|
||||||
@@ -129,7 +129,8 @@ limitations under the License. -->
|
|||||||
small
|
small
|
||||||
layout="prev, pager, next"
|
layout="prev, pager, next"
|
||||||
:page-size="pageSize"
|
:page-size="pageSize"
|
||||||
:total="dashboardStore.dashboards.length"
|
:total="total"
|
||||||
|
v-model="currentPage"
|
||||||
@current-change="changePage"
|
@current-change="changePage"
|
||||||
@prev-click="changePage"
|
@prev-click="changePage"
|
||||||
@next-click="changePage"
|
@next-click="changePage"
|
||||||
@@ -159,6 +160,8 @@ const pageSize = 18;
|
|||||||
const dashboards = ref<DashboardItem[]>([]);
|
const dashboards = ref<DashboardItem[]>([]);
|
||||||
const searchText = ref<string>("");
|
const searchText = ref<string>("");
|
||||||
const loading = ref<boolean>(false);
|
const loading = ref<boolean>(false);
|
||||||
|
const currentPage = ref<number>(1);
|
||||||
|
const total = ref<number>(0);
|
||||||
const multipleTableRef = ref<InstanceType<typeof ElTable>>();
|
const multipleTableRef = ref<InstanceType<typeof ElTable>>();
|
||||||
const multipleSelection = ref<DashboardItem[]>([]);
|
const multipleSelection = ref<DashboardItem[]>([]);
|
||||||
const dashboardFile = ref<Nullable<HTMLDivElement>>(null);
|
const dashboardFile = ref<Nullable<HTMLDivElement>>(null);
|
||||||
@@ -170,7 +173,7 @@ const handleSelectionChange = (val: DashboardItem[]) => {
|
|||||||
setList();
|
setList();
|
||||||
async function setList() {
|
async function setList() {
|
||||||
await dashboardStore.setDashboards();
|
await dashboardStore.setDashboards();
|
||||||
searchDashboards();
|
searchDashboards(1);
|
||||||
}
|
}
|
||||||
async function importTemplates(event: any) {
|
async function importTemplates(event: any) {
|
||||||
const arr: any = await readFile(event);
|
const arr: any = await readFile(event);
|
||||||
@@ -232,12 +235,20 @@ function exportTemplates() {
|
|||||||
}, 2000);
|
}, 2000);
|
||||||
}
|
}
|
||||||
function optimizeTemplate(
|
function optimizeTemplate(
|
||||||
children: (LayoutConfig & { moved?: boolean; standard?: unknown })[]
|
children: (LayoutConfig & {
|
||||||
|
moved?: boolean;
|
||||||
|
standard?: unknown;
|
||||||
|
label?: string;
|
||||||
|
value?: string;
|
||||||
|
})[]
|
||||||
) {
|
) {
|
||||||
for (const child of children || []) {
|
for (const child of children || []) {
|
||||||
delete child.moved;
|
delete child.moved;
|
||||||
delete child.activedTabIndex;
|
delete child.activedTabIndex;
|
||||||
delete child.standard;
|
delete child.standard;
|
||||||
|
delete child.id;
|
||||||
|
delete child.label;
|
||||||
|
delete child.value;
|
||||||
if (isEmptyObject(child.graph)) {
|
if (isEmptyObject(child.graph)) {
|
||||||
delete child.graph;
|
delete child.graph;
|
||||||
}
|
}
|
||||||
@@ -370,7 +381,7 @@ async function setRoot(row: DashboardItem) {
|
|||||||
items.push(d);
|
items.push(d);
|
||||||
}
|
}
|
||||||
dashboardStore.resetDashboards(items);
|
dashboardStore.resetDashboards(items);
|
||||||
searchDashboards();
|
searchDashboards(1);
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
}
|
}
|
||||||
function handleRename(row: DashboardItem) {
|
function handleRename(row: DashboardItem) {
|
||||||
@@ -402,6 +413,7 @@ async function updateName(d: DashboardItem, value: string) {
|
|||||||
name: value,
|
name: value,
|
||||||
};
|
};
|
||||||
delete c.id;
|
delete c.id;
|
||||||
|
delete c.filters;
|
||||||
const setting = {
|
const setting = {
|
||||||
id: d.id,
|
id: d.id,
|
||||||
configuration: JSON.stringify(c),
|
configuration: JSON.stringify(c),
|
||||||
@@ -453,10 +465,13 @@ function searchDashboards(pageIndex?: any) {
|
|||||||
const arr = list.filter((d: { name: string }) =>
|
const arr = list.filter((d: { name: string }) =>
|
||||||
d.name.includes(searchText.value)
|
d.name.includes(searchText.value)
|
||||||
);
|
);
|
||||||
dashboards.value = arr.splice(
|
|
||||||
(pageIndex - 1 || 0) * pageSize,
|
total.value = arr.length;
|
||||||
pageSize * (pageIndex || 1)
|
dashboards.value = arr.filter(
|
||||||
|
(d: { name: string }, index: number) =>
|
||||||
|
index < pageIndex * pageSize && index >= (pageIndex - 1) * pageSize
|
||||||
);
|
);
|
||||||
|
currentPage.value = pageIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function reloadTemplates() {
|
async function reloadTemplates() {
|
||||||
@@ -465,6 +480,7 @@ async function reloadTemplates() {
|
|||||||
loading.value = false;
|
loading.value = false;
|
||||||
}
|
}
|
||||||
function changePage(pageIndex: number) {
|
function changePage(pageIndex: number) {
|
||||||
|
currentPage.value = pageIndex;
|
||||||
searchDashboards(pageIndex);
|
searchDashboards(pageIndex);
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
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>
|
@@ -58,6 +58,13 @@ limitations under the License. -->
|
|||||||
<el-collapse-item :title="t('widgetOptions')" name="3">
|
<el-collapse-item :title="t('widgetOptions')" name="3">
|
||||||
<WidgetOptions />
|
<WidgetOptions />
|
||||||
</el-collapse-item>
|
</el-collapse-item>
|
||||||
|
<el-collapse-item
|
||||||
|
:title="t('associateOptions')"
|
||||||
|
name="4"
|
||||||
|
v-if="hasAssociate"
|
||||||
|
>
|
||||||
|
<AssociateOptions />
|
||||||
|
</el-collapse-item>
|
||||||
</el-collapse>
|
</el-collapse>
|
||||||
</div>
|
</div>
|
||||||
<div class="footer">
|
<div class="footer">
|
||||||
@@ -77,17 +84,13 @@ import { useDashboardStore } from "@/store/modules/dashboard";
|
|||||||
import { useAppStoreWithOut } from "@/store/modules/app";
|
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||||
import { Option } from "@/types/app";
|
import { Option } from "@/types/app";
|
||||||
import graphs from "../graphs";
|
import graphs from "../graphs";
|
||||||
import configs from "./widget/graph-styles";
|
import CustomOptions from "./widget/index";
|
||||||
import WidgetOptions from "./widget/WidgetOptions.vue";
|
|
||||||
import MetricOptions from "./widget/metric/Index.vue";
|
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: "WidgetEdit",
|
name: "WidgetEdit",
|
||||||
components: {
|
components: {
|
||||||
...graphs,
|
...graphs,
|
||||||
...configs,
|
...CustomOptions,
|
||||||
WidgetOptions,
|
|
||||||
MetricOptions,
|
|
||||||
},
|
},
|
||||||
setup() {
|
setup() {
|
||||||
const configHeight = document.documentElement.clientHeight - 520;
|
const configHeight = document.documentElement.clientHeight - 520;
|
||||||
@@ -111,6 +114,12 @@ export default defineComponent({
|
|||||||
const graph = computed(() => dashboardStore.selectedGrid.graph || {});
|
const graph = computed(() => dashboardStore.selectedGrid.graph || {});
|
||||||
const title = computed(() => encodeURIComponent(widget.value.title || ""));
|
const title = computed(() => encodeURIComponent(widget.value.title || ""));
|
||||||
const tips = computed(() => encodeURIComponent(widget.value.tips || ""));
|
const tips = computed(() => encodeURIComponent(widget.value.tips || ""));
|
||||||
|
const hasAssociate = computed(() =>
|
||||||
|
["Bar", "Line", "Area"].includes(
|
||||||
|
dashboardStore.selectedGrid.graph &&
|
||||||
|
dashboardStore.selectedGrid.graph.type
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
function getSource(source: unknown) {
|
function getSource(source: unknown) {
|
||||||
states.source = source;
|
states.source = source;
|
||||||
@@ -145,6 +154,7 @@ export default defineComponent({
|
|||||||
graph,
|
graph,
|
||||||
title,
|
title,
|
||||||
tips,
|
tips,
|
||||||
|
hasAssociate,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@@ -18,9 +18,13 @@
|
|||||||
import Text from "./Text.vue";
|
import Text from "./Text.vue";
|
||||||
import Widget from "./Widget.vue";
|
import Widget from "./Widget.vue";
|
||||||
import Topology from "./Topology.vue";
|
import Topology from "./Topology.vue";
|
||||||
|
import Event from "./Event.vue";
|
||||||
|
import TimeRange from "./TimeRange.vue";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
Text,
|
Text,
|
||||||
Widget,
|
Widget,
|
||||||
Topology,
|
Topology,
|
||||||
|
Event,
|
||||||
|
TimeRange,
|
||||||
};
|
};
|
||||||
|
112
src/views/dashboard/configuration/widget/AssociateOptions.vue
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
<!-- 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("widget") }}</span>
|
||||||
|
<Selector
|
||||||
|
:multiple="true"
|
||||||
|
:value="widgetIds"
|
||||||
|
:options="widgets"
|
||||||
|
size="small"
|
||||||
|
placeholder="Select a widget"
|
||||||
|
class="selectors"
|
||||||
|
@change="updateWidgetConfig"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { ref, computed } from "vue";
|
||||||
|
import { useI18n } from "vue-i18n";
|
||||||
|
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||||
|
import getDashboard from "@/hooks/useDashboardsSession";
|
||||||
|
import { Option } from "@/types/app";
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
const dashboardStore = useDashboardStore();
|
||||||
|
const associate = dashboardStore.selectedGrid.associate || [];
|
||||||
|
const widgetIds = ref<string[]>(
|
||||||
|
associate.map((d: { widgetId: string }) => d.widgetId)
|
||||||
|
);
|
||||||
|
const widgets: any = computed(() => {
|
||||||
|
const widgetList = getDashboard(dashboardStore.currentDashboard).widgets;
|
||||||
|
const items = [];
|
||||||
|
for (const d of widgetList) {
|
||||||
|
const isLinear = ["Bar", "Line", "Area"].includes(
|
||||||
|
(d.graph && d.graph.type) || ""
|
||||||
|
);
|
||||||
|
if (isLinear && d.id && dashboardStore.selectedGrid.id !== d.id) {
|
||||||
|
items.push({ value: d.id, label: (d.widget && d.widget.name) || d.id });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return items;
|
||||||
|
});
|
||||||
|
function updateWidgetConfig(options: Option[]) {
|
||||||
|
const arr: any = getDashboard(dashboardStore.currentDashboard).widgets;
|
||||||
|
const opt = options.map((d: Option) => {
|
||||||
|
return { widgetId: d.value };
|
||||||
|
});
|
||||||
|
const newVal = options.map((d: Option) => d.value);
|
||||||
|
// add association options in the source widget
|
||||||
|
const widget = {
|
||||||
|
...dashboardStore.selectedGrid,
|
||||||
|
associate: opt,
|
||||||
|
};
|
||||||
|
dashboardStore.selectWidget({ ...widget });
|
||||||
|
|
||||||
|
// remove unuse association widget option
|
||||||
|
for (const id of widgetIds.value) {
|
||||||
|
if (!newVal.includes(id)) {
|
||||||
|
const w = arr.find((d: { id: string }) => d.id === id);
|
||||||
|
const config = {
|
||||||
|
...w,
|
||||||
|
associate: [],
|
||||||
|
};
|
||||||
|
dashboardStore.setWidget(config);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// add association options in target widgets
|
||||||
|
for (let i = 0; i < opt.length; i++) {
|
||||||
|
const item = JSON.parse(JSON.stringify(opt));
|
||||||
|
item[i] = { widgetId: dashboardStore.selectedGrid.id };
|
||||||
|
const w = arr.find((d: { id: string }) => d.id === opt[i].widgetId);
|
||||||
|
const config = {
|
||||||
|
...w,
|
||||||
|
associate: item,
|
||||||
|
};
|
||||||
|
dashboardStore.setWidget(config);
|
||||||
|
}
|
||||||
|
widgetIds.value = newVal;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.label {
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 500;
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input {
|
||||||
|
width: 500px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selectors {
|
||||||
|
width: 500px;
|
||||||
|
}
|
||||||
|
</style>
|
@@ -13,6 +13,16 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|||||||
See the License for the specific language governing permissions and
|
See the License for the specific language governing permissions and
|
||||||
limitations under the License. -->
|
limitations under the License. -->
|
||||||
<template>
|
<template>
|
||||||
|
<div class="item">
|
||||||
|
<span class="label">{{ t("name") }}</span>
|
||||||
|
<el-input
|
||||||
|
class="input"
|
||||||
|
v-model="name"
|
||||||
|
size="small"
|
||||||
|
placeholder="Please input name"
|
||||||
|
@change="updateWidgetName({ name: encodeURIComponent(name) })"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
<div class="item">
|
<div class="item">
|
||||||
<span class="label">{{ t("title") }}</span>
|
<span class="label">{{ t("title") }}</span>
|
||||||
<el-input
|
<el-input
|
||||||
@@ -37,13 +47,17 @@ limitations under the License. -->
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref } from "vue";
|
import { ref } from "vue";
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
|
import { ElMessage } from "element-plus";
|
||||||
import { useDashboardStore } from "@/store/modules/dashboard";
|
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||||
|
import getDashboard from "@/hooks/useDashboardsSession";
|
||||||
|
import { LayoutConfig } from "@/types/dashboard";
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const dashboardStore = useDashboardStore();
|
const dashboardStore = useDashboardStore();
|
||||||
const widget = dashboardStore.selectedGrid.widget || {};
|
const widget = dashboardStore.selectedGrid.widget || {};
|
||||||
const title = ref<string>(widget.title || "");
|
const title = ref<string>(widget.title || "");
|
||||||
const tips = ref<string>(widget.tips || "");
|
const tips = ref<string>(widget.tips || "");
|
||||||
|
const name = ref<string>(widget.name || "");
|
||||||
|
|
||||||
function updateWidgetConfig(param: { [key: string]: string }) {
|
function updateWidgetConfig(param: { [key: string]: string }) {
|
||||||
const key = Object.keys(param)[0];
|
const key = Object.keys(param)[0];
|
||||||
@@ -57,6 +71,24 @@ function updateWidgetConfig(param: { [key: string]: string }) {
|
|||||||
};
|
};
|
||||||
dashboardStore.selectWidget({ ...selectedGrid, widget });
|
dashboardStore.selectWidget({ ...selectedGrid, widget });
|
||||||
}
|
}
|
||||||
|
function updateWidgetName(param: { [key: string]: string }) {
|
||||||
|
const key = Object.keys(param)[0];
|
||||||
|
const n = decodeURIComponent(param[key]);
|
||||||
|
const pattern = /^[A-Za-z0-9-_\u4e00-\u9fa5]{1,300}$/;
|
||||||
|
if (!pattern.test(n)) {
|
||||||
|
ElMessage.error(t("nameTip"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const { widgets } = getDashboard(dashboardStore.currentDashboard);
|
||||||
|
const item = widgets.find(
|
||||||
|
(d: LayoutConfig) => d.widget && d.widget.name === n
|
||||||
|
);
|
||||||
|
if (item) {
|
||||||
|
ElMessage.error(t("duplicateName"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
updateWidgetConfig(param);
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.label {
|
.label {
|
||||||
|
28
src/views/dashboard/configuration/widget/index.ts
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
/**
|
||||||
|
* 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 StyleOptions from "./graph-styles";
|
||||||
|
import WidgetOptions from "./WidgetOptions.vue";
|
||||||
|
import MetricOptions from "./metric/Index.vue";
|
||||||
|
import AssociateOptions from "./AssociateOptions.vue";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
...StyleOptions,
|
||||||
|
WidgetOptions,
|
||||||
|
MetricOptions,
|
||||||
|
AssociateOptions,
|
||||||
|
};
|
@@ -179,12 +179,16 @@ const setVisTypes = computed(() => {
|
|||||||
|
|
||||||
async function setMetricType(chart?: any) {
|
async function setMetricType(chart?: any) {
|
||||||
const g = chart || dashboardStore.selectedGrid.graph || {};
|
const g = chart || dashboardStore.selectedGrid.graph || {};
|
||||||
const json = await dashboardStore.fetchMetricList();
|
let arr: any[] = states.metricList;
|
||||||
if (json.errors) {
|
if (!chart) {
|
||||||
ElMessage.error(json.errors);
|
const json = await dashboardStore.fetchMetricList();
|
||||||
return;
|
if (json.errors) {
|
||||||
|
ElMessage.error(json.errors);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
arr = json.data.metrics;
|
||||||
}
|
}
|
||||||
states.metricList = (json.data.metrics || []).filter(
|
states.metricList = (arr || []).filter(
|
||||||
(d: { catalog: string; type: string }) => {
|
(d: { catalog: string; type: string }) => {
|
||||||
if (states.isList) {
|
if (states.isList) {
|
||||||
if (d.type === MetricsType.REGULAR_VALUE) {
|
if (d.type === MetricsType.REGULAR_VALUE) {
|
||||||
|
@@ -22,7 +22,9 @@ limitations under the License. -->
|
|||||||
size="small"
|
size="small"
|
||||||
placeholder="Please input unit"
|
placeholder="Please input unit"
|
||||||
@change="
|
@change="
|
||||||
updateConfig(index, { unit: encodeURIComponent(currentMetric.unit) })
|
updateConfig(index, {
|
||||||
|
unit: encodeURIComponent(currentMetric.unit || ''),
|
||||||
|
})
|
||||||
"
|
"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -35,7 +37,7 @@ limitations under the License. -->
|
|||||||
placeholder="Please input a name"
|
placeholder="Please input a name"
|
||||||
@change="
|
@change="
|
||||||
updateConfig(index, {
|
updateConfig(index, {
|
||||||
label: encodeURIComponent(currentMetric.label),
|
label: encodeURIComponent(currentMetric.label || ''),
|
||||||
})
|
})
|
||||||
"
|
"
|
||||||
/>
|
/>
|
||||||
|
@@ -29,7 +29,7 @@ limitations under the License. -->
|
|||||||
<span>{{ t("delete") }}</span>
|
<span>{{ t("delete") }}</span>
|
||||||
</div>
|
</div>
|
||||||
</el-popover>
|
</el-popover>
|
||||||
<Header />
|
<Header :needQuery="needQuery" />
|
||||||
<Content />
|
<Content />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -47,6 +47,7 @@ const props = defineProps({
|
|||||||
default: () => ({ graph: {} }),
|
default: () => ({ graph: {} }),
|
||||||
},
|
},
|
||||||
activeIndex: { type: String, default: "" },
|
activeIndex: { type: String, default: "" },
|
||||||
|
needQuery: { type: Boolean, default: true },
|
||||||
});
|
});
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const dashboardStore = useDashboardStore();
|
const dashboardStore = useDashboardStore();
|
||||||
|
109
src/views/dashboard/controls/Event.vue
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
<!-- 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="event-wrapper flex-v">
|
||||||
|
<el-popover
|
||||||
|
placement="bottom"
|
||||||
|
trigger="click"
|
||||||
|
:width="100"
|
||||||
|
v-if="dashboardStore.editMode"
|
||||||
|
>
|
||||||
|
<template #reference>
|
||||||
|
<span class="delete cp">
|
||||||
|
<Icon iconName="ellipsis_v" size="middle" class="operation" />
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
<div class="tools" @click="editConfig">
|
||||||
|
<span>{{ t("edit") }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="tools" @click="removeWidget">
|
||||||
|
<span>{{ t("delete") }}</span>
|
||||||
|
</div>
|
||||||
|
</el-popover>
|
||||||
|
<div class="header">
|
||||||
|
<Header :needQuery="needQuery" />
|
||||||
|
</div>
|
||||||
|
<div class="event">
|
||||||
|
<Content :data="data" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { useI18n } from "vue-i18n";
|
||||||
|
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||||
|
import Header from "../related/event/Header.vue";
|
||||||
|
import Content from "../related/event/Content.vue";
|
||||||
|
|
||||||
|
/*global defineProps */
|
||||||
|
const props = defineProps({
|
||||||
|
data: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({}),
|
||||||
|
},
|
||||||
|
activeIndex: { type: String, default: "" },
|
||||||
|
needQuery: { type: Boolean, default: true },
|
||||||
|
});
|
||||||
|
const { t } = useI18n();
|
||||||
|
const dashboardStore = useDashboardStore();
|
||||||
|
|
||||||
|
function removeWidget() {
|
||||||
|
dashboardStore.removeControls(props.data);
|
||||||
|
}
|
||||||
|
function editConfig() {
|
||||||
|
dashboardStore.setConfigPanel(true);
|
||||||
|
dashboardStore.selectWidget(props.data);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.event-wrapper {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
font-size: 12px;
|
||||||
|
position: relative;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.delete {
|
||||||
|
position: absolute;
|
||||||
|
top: 5px;
|
||||||
|
right: 3px;
|
||||||
|
z-index: 9999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
padding: 10px;
|
||||||
|
font-size: 12px;
|
||||||
|
border-bottom: 1px solid #dcdfe6;
|
||||||
|
min-width: 1024px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tools {
|
||||||
|
padding: 5px 0;
|
||||||
|
color: #999;
|
||||||
|
cursor: pointer;
|
||||||
|
position: relative;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: #409eff;
|
||||||
|
background-color: #eee;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.event {
|
||||||
|
width: 100%;
|
||||||
|
height: calc(100% - 80px);
|
||||||
|
}
|
||||||
|
</style>
|
@@ -30,7 +30,7 @@ limitations under the License. -->
|
|||||||
</div>
|
</div>
|
||||||
</el-popover>
|
</el-popover>
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<Header />
|
<Header :needQuery="needQuery" :data="data" />
|
||||||
</div>
|
</div>
|
||||||
<div class="log">
|
<div class="log">
|
||||||
<List />
|
<List />
|
||||||
@@ -38,19 +38,24 @@ limitations under the License. -->
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
import { provide } from "vue";
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
import { useDashboardStore } from "@/store/modules/dashboard";
|
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||||
import Header from "../related/log/Header.vue";
|
import Header from "../related/log/Header.vue";
|
||||||
import List from "../related/log/List.vue";
|
import List from "../related/log/List.vue";
|
||||||
|
import { LayoutConfig } from "@/types/dashboard";
|
||||||
|
import type { PropType } from "vue";
|
||||||
|
|
||||||
/*global defineProps */
|
/*global defineProps */
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
data: {
|
data: {
|
||||||
type: Object,
|
type: Object as PropType<LayoutConfig>,
|
||||||
default: () => ({}),
|
default: () => ({ graph: {} }),
|
||||||
},
|
},
|
||||||
activeIndex: { type: String, default: "" },
|
activeIndex: { type: String, default: "" },
|
||||||
|
needQuery: { type: Boolean, default: true },
|
||||||
});
|
});
|
||||||
|
provide("options", props.data);
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const dashboardStore = useDashboardStore();
|
const dashboardStore = useDashboardStore();
|
||||||
|
|
||||||
@@ -71,6 +76,7 @@ function removeWidget() {
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
top: 5px;
|
top: 5px;
|
||||||
right: 3px;
|
right: 3px;
|
||||||
|
z-index: 1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
.header {
|
.header {
|
||||||
|
97
src/views/dashboard/controls/NetworkProfiling.vue
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
<!-- Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
contributor license agreements. See the NOTICE file distributed with
|
||||||
|
this work for additional information regarding copyright ownership.
|
||||||
|
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
(the "License"); you may not use this file except in compliance with
|
||||||
|
the License. You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License. -->
|
||||||
|
<template>
|
||||||
|
<div class="profile-wrapper flex-v">
|
||||||
|
<div class="title">Network Profiling</div>
|
||||||
|
<el-popover
|
||||||
|
placement="bottom"
|
||||||
|
trigger="click"
|
||||||
|
:width="100"
|
||||||
|
v-if="dashboardStore.editMode"
|
||||||
|
>
|
||||||
|
<template #reference>
|
||||||
|
<span class="operation cp">
|
||||||
|
<Icon iconName="ellipsis_v" size="middle" />
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
<div class="tools" @click="removeWidget">
|
||||||
|
<span>{{ t("delete") }}</span>
|
||||||
|
</div>
|
||||||
|
</el-popover>
|
||||||
|
<Content :config="props.data" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import type { PropType } from "vue";
|
||||||
|
import { useI18n } from "vue-i18n";
|
||||||
|
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||||
|
import Content from "../related/network-profiling/Content.vue";
|
||||||
|
|
||||||
|
/*global defineProps */
|
||||||
|
const props = defineProps({
|
||||||
|
data: {
|
||||||
|
type: Object as PropType<any>,
|
||||||
|
default: () => ({ graph: {} }),
|
||||||
|
},
|
||||||
|
activeIndex: { type: String, default: "" },
|
||||||
|
needQuery: { type: Boolean, default: true },
|
||||||
|
});
|
||||||
|
const { t } = useI18n();
|
||||||
|
const dashboardStore = useDashboardStore();
|
||||||
|
|
||||||
|
function removeWidget() {
|
||||||
|
dashboardStore.removeControls(props.data);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.profile-wrapper {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
font-size: 12px;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.operation {
|
||||||
|
position: absolute;
|
||||||
|
top: 8px;
|
||||||
|
right: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
padding: 10px;
|
||||||
|
font-size: 12px;
|
||||||
|
border-bottom: 1px solid #dcdfe6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tools {
|
||||||
|
padding: 5px 0;
|
||||||
|
color: #999;
|
||||||
|
cursor: pointer;
|
||||||
|
position: relative;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: #409eff;
|
||||||
|
background-color: #eee;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
font-weight: bold;
|
||||||
|
line-height: 40px;
|
||||||
|
padding: 0 10px;
|
||||||
|
border-bottom: 1px solid #dcdfe6;
|
||||||
|
}
|
||||||
|
</style>
|
@@ -29,7 +29,7 @@ limitations under the License. -->
|
|||||||
<span>{{ t("delete") }}</span>
|
<span>{{ t("delete") }}</span>
|
||||||
</div>
|
</div>
|
||||||
</el-popover>
|
</el-popover>
|
||||||
<Header />
|
<Header :needQuery="needQuery" />
|
||||||
<Content />
|
<Content />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -47,6 +47,7 @@ const props = defineProps({
|
|||||||
default: () => ({ graph: {} }),
|
default: () => ({ graph: {} }),
|
||||||
},
|
},
|
||||||
activeIndex: { type: String, default: "" },
|
activeIndex: { type: String, default: "" },
|
||||||
|
needQuery: { type: Boolean, default: true },
|
||||||
});
|
});
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const dashboardStore = useDashboardStore();
|
const dashboardStore = useDashboardStore();
|
||||||
|
@@ -37,10 +37,17 @@ limitations under the License. -->
|
|||||||
v-if="dashboardStore.editMode && canEditTabName"
|
v-if="dashboardStore.editMode && canEditTabName"
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
|
<span class="tab-icons">
|
||||||
|
<el-tooltip content="Copy Link" placement="bottom">
|
||||||
|
<i @click="copyLink">
|
||||||
|
<Icon size="middle" iconName="review-list" class="tab-icon" />
|
||||||
|
</i>
|
||||||
|
</el-tooltip>
|
||||||
|
</span>
|
||||||
<span class="tab-icons" v-if="dashboardStore.editMode">
|
<span class="tab-icons" v-if="dashboardStore.editMode">
|
||||||
<el-tooltip content="Add tab items" placement="bottom">
|
<el-tooltip content="Add tab items" placement="bottom">
|
||||||
<i @click="addTabItem">
|
<i @click="addTabItem">
|
||||||
<Icon size="middle" iconName="add" />
|
<Icon size="middle" iconName="add_fill" class="tab-icon" />
|
||||||
</i>
|
</i>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
</span>
|
</span>
|
||||||
@@ -80,7 +87,7 @@ limitations under the License. -->
|
|||||||
:w="item.w"
|
:w="item.w"
|
||||||
:h="item.h"
|
:h="item.h"
|
||||||
:i="item.i"
|
:i="item.i"
|
||||||
:key="item.i"
|
:key="item.id"
|
||||||
@click="clickTabGrid($event, item)"
|
@click="clickTabGrid($event, item)"
|
||||||
:class="{ active: activeTabWidget === item.i }"
|
:class="{ active: activeTabWidget === item.i }"
|
||||||
:drag-ignore-from="dragIgnoreFrom"
|
:drag-ignore-from="dragIgnoreFrom"
|
||||||
@@ -99,18 +106,13 @@ limitations under the License. -->
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { ref, watch, defineComponent, toRefs } from "vue";
|
import { ref, watch, defineComponent, toRefs } from "vue";
|
||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
|
import { useRoute } from "vue-router";
|
||||||
import type { PropType } from "vue";
|
import type { PropType } from "vue";
|
||||||
import { LayoutConfig } from "@/types/dashboard";
|
import { LayoutConfig } from "@/types/dashboard";
|
||||||
import { useDashboardStore } from "@/store/modules/dashboard";
|
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||||
import Topology from "./Topology.vue";
|
import controls from "./tab";
|
||||||
import Widget from "./Widget.vue";
|
|
||||||
import Trace from "./Trace.vue";
|
|
||||||
import Profile from "./Profile.vue";
|
|
||||||
import Log from "./Log.vue";
|
|
||||||
import Text from "./Text.vue";
|
|
||||||
import Ebpf from "./Ebpf.vue";
|
|
||||||
import { dragIgnoreFrom } from "../data";
|
import { dragIgnoreFrom } from "../data";
|
||||||
import DemandLog from "./DemandLog.vue";
|
import copy from "@/utils/copy";
|
||||||
|
|
||||||
const props = {
|
const props = {
|
||||||
data: {
|
data: {
|
||||||
@@ -121,16 +123,23 @@ const props = {
|
|||||||
};
|
};
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: "Tab",
|
name: "Tab",
|
||||||
components: { Topology, Widget, Trace, Profile, Log, Text, Ebpf, DemandLog },
|
components: {
|
||||||
|
...controls,
|
||||||
|
},
|
||||||
props,
|
props,
|
||||||
setup(props) {
|
setup(props) {
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const dashboardStore = useDashboardStore();
|
const dashboardStore = useDashboardStore();
|
||||||
const activeTabIndex = ref<number>(0);
|
const route = useRoute();
|
||||||
|
const activeTabIndex = ref<number>(
|
||||||
|
Number(route.params.activeTabIndex) || 0
|
||||||
|
);
|
||||||
const activeTabWidget = ref<string>("");
|
const activeTabWidget = ref<string>("");
|
||||||
const editTabIndex = ref<number>(NaN); // edit tab item name
|
const editTabIndex = ref<number>(NaN); // edit tab item name
|
||||||
const canEditTabName = ref<boolean>(false);
|
const canEditTabName = ref<boolean>(false);
|
||||||
const needQuery = ref<boolean>(false);
|
const needQuery = ref<boolean>(false);
|
||||||
|
|
||||||
|
dashboardStore.setActiveTabIndex(activeTabIndex);
|
||||||
const l = dashboardStore.layout.findIndex(
|
const l = dashboardStore.layout.findIndex(
|
||||||
(d: LayoutConfig) => d.i === props.data.i
|
(d: LayoutConfig) => d.i === props.data.i
|
||||||
);
|
);
|
||||||
@@ -154,6 +163,11 @@ export default defineComponent({
|
|||||||
dashboardStore.layout[l].children[activeTabIndex.value].children
|
dashboardStore.layout[l].children[activeTabIndex.value].children
|
||||||
);
|
);
|
||||||
needQuery.value = true;
|
needQuery.value = true;
|
||||||
|
if (route.params.activeTabIndex) {
|
||||||
|
let p = location.href.split("/tab/")[0];
|
||||||
|
p = p + "/tab/" + activeTabIndex.value;
|
||||||
|
history.replaceState({}, "", p);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
function removeTab(e: Event) {
|
function removeTab(e: Event) {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
@@ -180,6 +194,7 @@ export default defineComponent({
|
|||||||
editTabIndex.value = index;
|
editTabIndex.value = index;
|
||||||
}
|
}
|
||||||
function handleClick(el: any) {
|
function handleClick(el: any) {
|
||||||
|
needQuery.value = true;
|
||||||
if (["tab-name", "edit-tab"].includes(el.target.className)) {
|
if (["tab-name", "edit-tab"].includes(el.target.className)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -202,6 +217,16 @@ export default defineComponent({
|
|||||||
dashboardStore.layout[l].children[activeTabIndex.value].children
|
dashboardStore.layout[l].children[activeTabIndex.value].children
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
function copyLink() {
|
||||||
|
let path = "";
|
||||||
|
if (route.params.activeTabIndex === undefined) {
|
||||||
|
path = location.href + "/tab/" + activeTabIndex.value;
|
||||||
|
} else {
|
||||||
|
const p = location.href.split("/tab/")[0];
|
||||||
|
path = p + "/tab/" + activeTabIndex.value;
|
||||||
|
}
|
||||||
|
copy(path);
|
||||||
|
}
|
||||||
document.body.addEventListener("click", handleClick, false);
|
document.body.addEventListener("click", handleClick, false);
|
||||||
watch(
|
watch(
|
||||||
() => dashboardStore.activedGridItem,
|
() => dashboardStore.activedGridItem,
|
||||||
@@ -218,6 +243,26 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
watch(
|
||||||
|
() => dashboardStore.currentTabIndex,
|
||||||
|
() => {
|
||||||
|
activeTabIndex.value = dashboardStore.currentTabIndex;
|
||||||
|
dashboardStore.activeGridItem(props.data.i);
|
||||||
|
dashboardStore.selectWidget(props.data);
|
||||||
|
const l = dashboardStore.layout.findIndex(
|
||||||
|
(d: LayoutConfig) => d.i === props.data.i
|
||||||
|
);
|
||||||
|
dashboardStore.setCurrentTabItems(
|
||||||
|
dashboardStore.layout[l].children[activeTabIndex.value].children
|
||||||
|
);
|
||||||
|
needQuery.value = true;
|
||||||
|
if (route.params.activeTabIndex) {
|
||||||
|
let p = location.href.split("/tab/")[0];
|
||||||
|
p = p + "/tab/" + activeTabIndex.value;
|
||||||
|
history.replaceState({}, "", p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
return {
|
return {
|
||||||
handleClick,
|
handleClick,
|
||||||
layoutUpdatedEvent,
|
layoutUpdatedEvent,
|
||||||
@@ -227,6 +272,7 @@ export default defineComponent({
|
|||||||
deleteTabItem,
|
deleteTabItem,
|
||||||
removeTab,
|
removeTab,
|
||||||
clickTabs,
|
clickTabs,
|
||||||
|
copyLink,
|
||||||
...toRefs(props),
|
...toRefs(props),
|
||||||
activeTabWidget,
|
activeTabWidget,
|
||||||
dashboardStore,
|
dashboardStore,
|
||||||
@@ -330,6 +376,10 @@ export default defineComponent({
|
|||||||
overflow: auto;
|
overflow: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.tab-icon {
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
|
||||||
.vue-grid-item.active {
|
.vue-grid-item.active {
|
||||||
border: 1px solid #409eff;
|
border: 1px solid #409eff;
|
||||||
}
|
}
|
||||||
|
187
src/views/dashboard/controls/TimeRange.vue
Normal file
@@ -0,0 +1,187 @@
|
|||||||
|
<!-- 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="time-range">
|
||||||
|
<div class="header">
|
||||||
|
<el-popover
|
||||||
|
placement="bottom"
|
||||||
|
trigger="click"
|
||||||
|
:width="100"
|
||||||
|
v-if="dashboardStore.editMode"
|
||||||
|
>
|
||||||
|
<template #reference>
|
||||||
|
<span>
|
||||||
|
<Icon iconName="ellipsis_v" size="middle" class="operation" />
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
<div class="tools" @click="editConfig">
|
||||||
|
<span>{{ t("edit") }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="tools" @click="removeTopo">
|
||||||
|
<span>{{ t("delete") }}</span>
|
||||||
|
</div>
|
||||||
|
</el-popover>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="body"
|
||||||
|
:style="{
|
||||||
|
backgroundColor: TextColors[graph.backgroundColor],
|
||||||
|
justifyContent: graph.textAlign,
|
||||||
|
color: TextColors[graph.fontColor],
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
class="mr-5"
|
||||||
|
:style="{
|
||||||
|
fontSize: graph.fontSize + 'px',
|
||||||
|
}"
|
||||||
|
>{{ graph.text }}
|
||||||
|
</span>
|
||||||
|
<Icon iconName="time_range" size="middle" />
|
||||||
|
<span
|
||||||
|
class="ml-5"
|
||||||
|
:style="{
|
||||||
|
fontSize: graph.fontSize + 'px',
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
{{ content }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { computed } from "vue";
|
||||||
|
import type { PropType } from "vue";
|
||||||
|
import { useI18n } from "vue-i18n";
|
||||||
|
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||||
|
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||||
|
import { TextColors } from "@/views/dashboard/data";
|
||||||
|
|
||||||
|
/*global defineProps */
|
||||||
|
const props = defineProps({
|
||||||
|
data: {
|
||||||
|
type: Object as PropType<any>,
|
||||||
|
default: () => ({ graph: {} }),
|
||||||
|
},
|
||||||
|
activeIndex: { type: String, default: "" },
|
||||||
|
});
|
||||||
|
const { t } = useI18n();
|
||||||
|
const graph = computed(() => props.data.graph || {});
|
||||||
|
const dashboardStore = useDashboardStore();
|
||||||
|
const appStore = useAppStoreWithOut();
|
||||||
|
const content = computed(() => {
|
||||||
|
const text = [appStore.durationRow.start, appStore.durationRow.end]
|
||||||
|
.map((date: Date) => tf(date, "YYYY-MM-DD HH:mm"))
|
||||||
|
.join(` ~ `);
|
||||||
|
return text;
|
||||||
|
});
|
||||||
|
|
||||||
|
function removeTopo() {
|
||||||
|
dashboardStore.removeControls(props.data);
|
||||||
|
}
|
||||||
|
function editConfig() {
|
||||||
|
dashboardStore.setConfigPanel(true);
|
||||||
|
dashboardStore.selectWidget(props.data);
|
||||||
|
}
|
||||||
|
function tf(time: Date, format: any): string {
|
||||||
|
const local = {
|
||||||
|
dow: 1, // Monday is the first day of the week
|
||||||
|
hourTip: t("hourTip"), // tip of select hour
|
||||||
|
minuteTip: t("minuteTip"), // tip of select minute
|
||||||
|
secondTip: t("secondTip"), // tip of select second
|
||||||
|
yearSuffix: t("yearSuffix"), // format of head
|
||||||
|
monthsHead: t("monthsHead").split("_"), // months of head
|
||||||
|
months: t("months").split("_"), // months of panel
|
||||||
|
weeks: t("weeks").split("_"), // weeks
|
||||||
|
cancelTip: t("cancel"), // default text for cancel button
|
||||||
|
submitTip: t("confirm"), // default text for submit button
|
||||||
|
quarterHourCutTip: t("quarterHourCutTip"),
|
||||||
|
halfHourCutTip: t("halfHourCutTip"),
|
||||||
|
hourCutTip: t("hourCutTip"),
|
||||||
|
dayCutTip: t("dayCutTip"),
|
||||||
|
weekCutTip: t("weekCutTip"),
|
||||||
|
monthCutTip: t("monthCutTip"),
|
||||||
|
};
|
||||||
|
const year = time.getFullYear();
|
||||||
|
const month = time.getMonth();
|
||||||
|
const day = time.getDate();
|
||||||
|
const hours24 = time.getHours();
|
||||||
|
const hours = hours24 % 12 === 0 ? 12 : hours24 % 12;
|
||||||
|
const minutes = time.getMinutes();
|
||||||
|
const seconds = time.getSeconds();
|
||||||
|
const milliseconds = time.getMilliseconds();
|
||||||
|
const dd = (t: number) => `0${t}`.slice(-2);
|
||||||
|
const map: { [key: string]: string | number } = {
|
||||||
|
YYYY: year,
|
||||||
|
MM: dd(month + 1),
|
||||||
|
MMM: local.months[month],
|
||||||
|
MMMM: local.monthsHead[month],
|
||||||
|
M: month + 1,
|
||||||
|
DD: dd(day),
|
||||||
|
D: day,
|
||||||
|
HH: dd(hours24),
|
||||||
|
H: hours24,
|
||||||
|
hh: dd(hours),
|
||||||
|
h: hours,
|
||||||
|
mm: dd(minutes),
|
||||||
|
m: minutes,
|
||||||
|
ss: dd(seconds),
|
||||||
|
s: seconds,
|
||||||
|
S: milliseconds,
|
||||||
|
};
|
||||||
|
return format.replace(/Y+|M+|D+|H+|h+|m+|s+|S+/g, (str: string) => map[str]);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.time-range {
|
||||||
|
font-size: 12px;
|
||||||
|
height: 100%;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.operation {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
position: absolute;
|
||||||
|
top: 5px;
|
||||||
|
right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.body {
|
||||||
|
padding: 0 20px 0 10px;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
overflow: auto;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tools {
|
||||||
|
padding: 5px 0;
|
||||||
|
color: #999;
|
||||||
|
cursor: pointer;
|
||||||
|
position: relative;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: #409eff;
|
||||||
|
background-color: #eee;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@@ -30,7 +30,7 @@ limitations under the License. -->
|
|||||||
</div>
|
</div>
|
||||||
</el-popover>
|
</el-popover>
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<Filter />
|
<Filter :needQuery="needQuery" :data="data" />
|
||||||
</div>
|
</div>
|
||||||
<div class="trace flex-h">
|
<div class="trace flex-h">
|
||||||
<TraceList />
|
<TraceList />
|
||||||
@@ -39,6 +39,7 @@ limitations under the License. -->
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
import { provide } from "vue";
|
||||||
import type { PropType } from "vue";
|
import type { PropType } from "vue";
|
||||||
import Filter from "../related/trace/Filter.vue";
|
import Filter from "../related/trace/Filter.vue";
|
||||||
import TraceList from "../related/trace/TraceList.vue";
|
import TraceList from "../related/trace/TraceList.vue";
|
||||||
@@ -53,7 +54,9 @@ const props = defineProps({
|
|||||||
default: () => ({ graph: {} }),
|
default: () => ({ graph: {} }),
|
||||||
},
|
},
|
||||||
activeIndex: { type: String, default: "" },
|
activeIndex: { type: String, default: "" },
|
||||||
|
needQuery: { type: Boolean, default: true },
|
||||||
});
|
});
|
||||||
|
provide("options", props.data);
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const dashboardStore = useDashboardStore();
|
const dashboardStore = useDashboardStore();
|
||||||
function removeWidget() {
|
function removeWidget() {
|
||||||
|
@@ -61,9 +61,12 @@ limitations under the License. -->
|
|||||||
metrics: data.metrics || [''],
|
metrics: data.metrics || [''],
|
||||||
metricTypes: data.metricTypes || [''],
|
metricTypes: data.metricTypes || [''],
|
||||||
i: data.i,
|
i: data.i,
|
||||||
|
id: data.id,
|
||||||
metricConfig: data.metricConfig,
|
metricConfig: data.metricConfig,
|
||||||
|
filters: data.filters || {},
|
||||||
}"
|
}"
|
||||||
:needQuery="needQuery"
|
:needQuery="needQuery"
|
||||||
|
@click="clickHandle"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div v-else class="no-data">{{ t("noGraph") }}</div>
|
<div v-else class="no-data">{{ t("noGraph") }}</div>
|
||||||
@@ -84,6 +87,8 @@ import {
|
|||||||
useGetMetricEntity,
|
useGetMetricEntity,
|
||||||
} from "@/hooks/useProcessor";
|
} from "@/hooks/useProcessor";
|
||||||
import { EntityType, ListChartTypes } from "../data";
|
import { EntityType, ListChartTypes } from "../data";
|
||||||
|
import { EventParams } from "@/types/dashboard";
|
||||||
|
import getDashboard from "@/hooks/useDashboardsSession";
|
||||||
|
|
||||||
const props = {
|
const props = {
|
||||||
data: {
|
data: {
|
||||||
@@ -93,6 +98,7 @@ const props = {
|
|||||||
activeIndex: { type: String, default: "" },
|
activeIndex: { type: String, default: "" },
|
||||||
needQuery: { type: Boolean, default: false },
|
needQuery: { type: Boolean, default: false },
|
||||||
};
|
};
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: "Widget",
|
name: "Widget",
|
||||||
components: { ...graphs },
|
components: { ...graphs },
|
||||||
@@ -156,6 +162,24 @@ export default defineComponent({
|
|||||||
dashboardStore.activeGridItem(props.data.i);
|
dashboardStore.activeGridItem(props.data.i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
function clickHandle(params: EventParams | any) {
|
||||||
|
const { widgets } = getDashboard(dashboardStore.currentDashboard);
|
||||||
|
const associate = (props.data.associate && props.data.associate) || [];
|
||||||
|
|
||||||
|
for (const item of associate) {
|
||||||
|
const widget = widgets.find(
|
||||||
|
(d: LayoutConfig) => d.id === item.widgetId
|
||||||
|
);
|
||||||
|
if (widget) {
|
||||||
|
widget.filters = {
|
||||||
|
dataIndex: params.dataIndex,
|
||||||
|
sourceId: props.data.id || "",
|
||||||
|
};
|
||||||
|
|
||||||
|
dashboardStore.setWidget(widget);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
watch(
|
watch(
|
||||||
() => [props.data.metricTypes, props.data.metrics],
|
() => [props.data.metricTypes, props.data.metrics],
|
||||||
() => {
|
() => {
|
||||||
@@ -189,7 +213,10 @@ export default defineComponent({
|
|||||||
watch(
|
watch(
|
||||||
() => [selectorStore.currentPod, selectorStore.currentDestPod],
|
() => [selectorStore.currentPod, selectorStore.currentDestPod],
|
||||||
() => {
|
() => {
|
||||||
if (dashboardStore.entity === EntityType[0].value) {
|
if (
|
||||||
|
dashboardStore.entity === EntityType[0].value ||
|
||||||
|
dashboardStore.entity === EntityType[7].value
|
||||||
|
) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (isList.value) {
|
if (isList.value) {
|
||||||
@@ -198,6 +225,14 @@ export default defineComponent({
|
|||||||
queryMetrics();
|
queryMetrics();
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
watch(
|
||||||
|
() => [selectorStore.currentProcess, selectorStore.currentDestProcess],
|
||||||
|
() => {
|
||||||
|
if (dashboardStore.entity === EntityType[7].value) {
|
||||||
|
queryMetrics();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
watch(
|
watch(
|
||||||
() => appStore.durationTime,
|
() => appStore.durationTime,
|
||||||
() => {
|
() => {
|
||||||
@@ -221,6 +256,7 @@ export default defineComponent({
|
|||||||
t,
|
t,
|
||||||
graph,
|
graph,
|
||||||
widget,
|
widget,
|
||||||
|
clickHandle,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@@ -23,6 +23,9 @@ import Log from "./Log.vue";
|
|||||||
import Text from "./Text.vue";
|
import Text from "./Text.vue";
|
||||||
import Ebpf from "./Ebpf.vue";
|
import Ebpf from "./Ebpf.vue";
|
||||||
import DemandLog from "./DemandLog.vue";
|
import DemandLog from "./DemandLog.vue";
|
||||||
|
import Event from "./Event.vue";
|
||||||
|
import NetworkProfiling from "./NetworkProfiling.vue";
|
||||||
|
import TimeRange from "./TimeRange.vue";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
Tab,
|
Tab,
|
||||||
@@ -34,4 +37,7 @@ export default {
|
|||||||
Text,
|
Text,
|
||||||
Ebpf,
|
Ebpf,
|
||||||
DemandLog,
|
DemandLog,
|
||||||
|
Event,
|
||||||
|
NetworkProfiling,
|
||||||
|
TimeRange,
|
||||||
};
|
};
|
||||||
|
41
src/views/dashboard/controls/tab.ts
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
/**
|
||||||
|
* 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 Topology from "./Topology.vue";
|
||||||
|
import Widget from "./Widget.vue";
|
||||||
|
import Trace from "./Trace.vue";
|
||||||
|
import Profile from "./Profile.vue";
|
||||||
|
import Log from "./Log.vue";
|
||||||
|
import Text from "./Text.vue";
|
||||||
|
import Ebpf from "./Ebpf.vue";
|
||||||
|
import DemandLog from "./DemandLog.vue";
|
||||||
|
import Event from "./Event.vue";
|
||||||
|
import NetworkProfiling from "./NetworkProfiling.vue";
|
||||||
|
import TimeRange from "./TimeRange.vue";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
Widget,
|
||||||
|
Trace,
|
||||||
|
Topology,
|
||||||
|
Profile,
|
||||||
|
Log,
|
||||||
|
Text,
|
||||||
|
Ebpf,
|
||||||
|
DemandLog,
|
||||||
|
Event,
|
||||||
|
NetworkProfiling,
|
||||||
|
TimeRange,
|
||||||
|
};
|
@@ -15,7 +15,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
export const dragIgnoreFrom =
|
export const dragIgnoreFrom =
|
||||||
"svg.d3-trace-tree, .dragger, .micro-topo-chart, .schedules";
|
"svg.d3-trace-tree, .dragger, .micro-topo-chart, .schedules, .vis-item, .vis-timeline, .process-svg";
|
||||||
|
|
||||||
export const PodsChartTypes = ["EndpointList", "InstanceList"];
|
export const PodsChartTypes = ["EndpointList", "InstanceList"];
|
||||||
|
|
||||||
@@ -159,6 +159,7 @@ export const EntityType = [
|
|||||||
key: 4,
|
key: 4,
|
||||||
},
|
},
|
||||||
{ value: "EndpointRelation", label: "Endpoint Relation", key: 4 },
|
{ value: "EndpointRelation", label: "Endpoint Relation", key: 4 },
|
||||||
|
{ value: "ProcessRelation", label: "Process Relation", key: 5 },
|
||||||
];
|
];
|
||||||
export const ListEntity: any = {
|
export const ListEntity: any = {
|
||||||
InstanceList: EntityType[3].value,
|
InstanceList: EntityType[3].value,
|
||||||
@@ -178,15 +179,16 @@ export const AllTools = [
|
|||||||
{ name: "assignment", content: "Add Log", id: "addLog" },
|
{ name: "assignment", content: "Add Log", id: "addLog" },
|
||||||
];
|
];
|
||||||
export const ServiceTools = [
|
export const ServiceTools = [
|
||||||
{ name: "playlist_add", content: "Widget", id: "addWidget" },
|
{ name: "playlist_add", content: "Add Widget", id: "addWidget" },
|
||||||
{ name: "all_inbox", content: "Tab", id: "addTab" },
|
{ name: "all_inbox", content: "Add Tab", id: "addTab" },
|
||||||
{ name: "library_books", content: "Text", id: "addText" },
|
{ name: "library_books", content: "Add Text", id: "addText" },
|
||||||
{ name: "device_hub", content: "Topology", id: "addTopology" },
|
{ name: "device_hub", content: "Add Topology", id: "addTopology" },
|
||||||
{ name: "merge", content: "Trace", id: "addTrace" },
|
{ name: "merge", content: "Add Trace", id: "addTrace" },
|
||||||
{ name: "timeline", content: "Trace Profiling", id: "addProfile" },
|
{ name: "timeline", content: "Add Trace Profiling", id: "addProfile" },
|
||||||
{ name: "insert_chart", content: "eBPF Profiling", id: "addEbpf" },
|
{ name: "insert_chart", content: "Add eBPF Profiling", id: "addEbpf" },
|
||||||
{ name: "assignment", content: "Log", id: "addLog" },
|
{ name: "assignment", content: "Add Log", id: "addLog" },
|
||||||
{ name: "demand", content: "Add On Demand Log", id: "addDemandLog" },
|
{ name: "demand", content: "Add On Demand Log", id: "addDemandLog" },
|
||||||
|
{ name: "event", content: "Add Event", id: "addEvent" },
|
||||||
];
|
];
|
||||||
export const InstanceTools = [
|
export const InstanceTools = [
|
||||||
{ name: "playlist_add", content: "Add Widget", id: "addWidget" },
|
{ name: "playlist_add", content: "Add Widget", id: "addWidget" },
|
||||||
@@ -195,6 +197,12 @@ export const InstanceTools = [
|
|||||||
{ name: "merge", content: "Add Trace", id: "addTrace" },
|
{ name: "merge", content: "Add Trace", id: "addTrace" },
|
||||||
{ name: "assignment", content: "Add Log", id: "addLog" },
|
{ name: "assignment", content: "Add Log", id: "addLog" },
|
||||||
{ name: "demand", content: "Add On Demand Log", id: "addDemandLog" },
|
{ name: "demand", content: "Add On Demand Log", id: "addDemandLog" },
|
||||||
|
{ name: "event", content: "Add Event", id: "addEvent" },
|
||||||
|
{
|
||||||
|
name: "timeline",
|
||||||
|
content: "Add Network Profiling",
|
||||||
|
id: "addNetworkProfiling",
|
||||||
|
},
|
||||||
];
|
];
|
||||||
export const EndpointTools = [
|
export const EndpointTools = [
|
||||||
{ name: "playlist_add", content: "Add Widget", id: "addWidget" },
|
{ name: "playlist_add", content: "Add Widget", id: "addWidget" },
|
||||||
@@ -203,6 +211,13 @@ export const EndpointTools = [
|
|||||||
{ name: "device_hub", content: "Add Topology", id: "addTopology" },
|
{ name: "device_hub", content: "Add Topology", id: "addTopology" },
|
||||||
{ name: "merge", content: "Add Trace", id: "addTrace" },
|
{ name: "merge", content: "Add Trace", id: "addTrace" },
|
||||||
{ name: "assignment", content: "Add Log", id: "addLog" },
|
{ name: "assignment", content: "Add Log", id: "addLog" },
|
||||||
|
{ name: "event", content: "Add Event", id: "addEvent" },
|
||||||
|
];
|
||||||
|
export const ProcessTools = [
|
||||||
|
{ name: "playlist_add", content: "Add Widget", id: "addWidget" },
|
||||||
|
{ name: "all_inbox", content: "Add Tab", id: "addTab" },
|
||||||
|
{ name: "library_books", content: "Add Text", id: "addText" },
|
||||||
|
{ name: "time_range", content: "Add Time Range Text", id: "addTimeRange" },
|
||||||
];
|
];
|
||||||
export const ServiceRelationTools = [
|
export const ServiceRelationTools = [
|
||||||
{ name: "playlist_add", content: "Add Widget", id: "addWidget" },
|
{ name: "playlist_add", content: "Add Widget", id: "addWidget" },
|
||||||
@@ -281,4 +296,6 @@ export const CalculationOpts = [
|
|||||||
{ label: "Seconds to YYYY-MM-DD HH:mm:ss", value: "convertSeconds" },
|
{ label: "Seconds to YYYY-MM-DD HH:mm:ss", value: "convertSeconds" },
|
||||||
{ label: "Precision is 2", value: "precision" },
|
{ label: "Precision is 2", value: "precision" },
|
||||||
{ label: "Milliseconds to seconds", value: "msTos" },
|
{ label: "Milliseconds to seconds", value: "msTos" },
|
||||||
|
{ label: "Seconds to days", value: "secondToDay" },
|
||||||
|
{ label: "Nanoseconds to milliseconds", value: "nanosecondToMillisecond" },
|
||||||
];
|
];
|
||||||
|
@@ -14,14 +14,20 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License. -->
|
limitations under the License. -->
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<Line :data="data" :intervalTime="intervalTime" :config="config" />
|
<Line
|
||||||
|
:data="data"
|
||||||
|
:intervalTime="intervalTime"
|
||||||
|
:config="config"
|
||||||
|
@click="clickEvent"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import type { PropType } from "vue";
|
import type { PropType } from "vue";
|
||||||
import Line from "./Line.vue";
|
import Line from "./Line.vue";
|
||||||
import { AreaConfig } from "@/types/dashboard";
|
import { AreaConfig, EventParams } from "@/types/dashboard";
|
||||||
|
|
||||||
/*global defineProps */
|
/*global defineProps, defineEmits */
|
||||||
|
const emits = defineEmits(["click"]);
|
||||||
defineProps({
|
defineProps({
|
||||||
data: {
|
data: {
|
||||||
type: Object as PropType<{ [key: string]: number[] }>,
|
type: Object as PropType<{ [key: string]: number[] }>,
|
||||||
@@ -29,8 +35,23 @@ defineProps({
|
|||||||
},
|
},
|
||||||
intervalTime: { type: Array as PropType<string[]>, default: () => [] },
|
intervalTime: { type: Array as PropType<string[]>, default: () => [] },
|
||||||
config: {
|
config: {
|
||||||
type: Object as PropType<AreaConfig>,
|
type: Object as PropType<
|
||||||
|
AreaConfig & {
|
||||||
|
filters: {
|
||||||
|
sourceId: string;
|
||||||
|
duration: {
|
||||||
|
startTime: string;
|
||||||
|
endTime: string;
|
||||||
|
};
|
||||||
|
isRange: boolean;
|
||||||
|
dataIndex?: number;
|
||||||
|
};
|
||||||
|
} & { id: string }
|
||||||
|
>,
|
||||||
default: () => ({}),
|
default: () => ({}),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
function clickEvent(params: EventParams) {
|
||||||
|
emits("click", params);
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@@ -13,15 +13,15 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|||||||
See the License for the specific language governing permissions and
|
See the License for the specific language governing permissions and
|
||||||
limitations under the License. -->
|
limitations under the License. -->
|
||||||
<template>
|
<template>
|
||||||
<Graph :option="option" />
|
<Graph :option="option" @select="clickEvent" :filters="config.filters" />
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed } from "vue";
|
import { computed } from "vue";
|
||||||
import type { PropType } from "vue";
|
import type { PropType } from "vue";
|
||||||
import { Event } from "@/types/events";
|
import { BarConfig, EventParams } from "@/types/dashboard";
|
||||||
import { BarConfig } from "@/types/dashboard";
|
|
||||||
|
|
||||||
/*global defineProps */
|
/*global defineProps, defineEmits */
|
||||||
|
const emits = defineEmits(["click"]);
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
data: {
|
data: {
|
||||||
type: Object as PropType<{ [key: string]: number[] }>,
|
type: Object as PropType<{ [key: string]: number[] }>,
|
||||||
@@ -29,9 +29,20 @@ const props = defineProps({
|
|||||||
},
|
},
|
||||||
intervalTime: { type: Array as PropType<string[]>, default: () => [] },
|
intervalTime: { type: Array as PropType<string[]>, default: () => [] },
|
||||||
theme: { type: String, default: "light" },
|
theme: { type: String, default: "light" },
|
||||||
itemEvents: { type: Array as PropType<Event[]>, default: () => [] },
|
|
||||||
config: {
|
config: {
|
||||||
type: Object as PropType<BarConfig>,
|
type: Object as PropType<
|
||||||
|
BarConfig & {
|
||||||
|
filters: {
|
||||||
|
sourceId: string;
|
||||||
|
duration: {
|
||||||
|
startTime: string;
|
||||||
|
endTime: string;
|
||||||
|
};
|
||||||
|
isRange: boolean;
|
||||||
|
dataIndex?: number;
|
||||||
|
};
|
||||||
|
} & { id: string }
|
||||||
|
>,
|
||||||
default: () => ({}),
|
default: () => ({}),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -41,30 +52,7 @@ function getOption() {
|
|||||||
const keys = Object.keys(props.data || {}).filter(
|
const keys = Object.keys(props.data || {}).filter(
|
||||||
(i: any) => Array.isArray(props.data[i]) && props.data[i].length
|
(i: any) => Array.isArray(props.data[i]) && props.data[i].length
|
||||||
);
|
);
|
||||||
const startP = keys.length > 1 ? 50 : 15;
|
const temp = keys.map((i: string) => {
|
||||||
const diff = 15;
|
|
||||||
const markAreas = (props.itemEvents || []).map(
|
|
||||||
(event: Event, index: number) => {
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
name: `${event.name}:${event.type}`,
|
|
||||||
xAxis: event.startTime,
|
|
||||||
y: startP + diff * index,
|
|
||||||
itemStyle: {
|
|
||||||
borderWidth: 2,
|
|
||||||
borderColor: event.type === "Normal" ? "#5dc859" : "#FF0087",
|
|
||||||
color: event.type === "Normal" ? "#5dc859" : "#FF0087",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: event.message,
|
|
||||||
xAxis: event.endTime,
|
|
||||||
y: startP + diff * (index + 1),
|
|
||||||
},
|
|
||||||
];
|
|
||||||
}
|
|
||||||
);
|
|
||||||
const temp = keys.map((i: string, index: number) => {
|
|
||||||
if (!props.intervalTime) {
|
if (!props.intervalTime) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -85,23 +73,6 @@ function getOption() {
|
|||||||
backgroundStyle: {
|
backgroundStyle: {
|
||||||
color: "rgba(180, 180, 180, 0.1)",
|
color: "rgba(180, 180, 180, 0.1)",
|
||||||
},
|
},
|
||||||
markArea:
|
|
||||||
index === 0
|
|
||||||
? {
|
|
||||||
silent: false,
|
|
||||||
data: markAreas,
|
|
||||||
label: {
|
|
||||||
show: false,
|
|
||||||
width: 60,
|
|
||||||
},
|
|
||||||
emphasis: {
|
|
||||||
label: {
|
|
||||||
position: "bottom",
|
|
||||||
show: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
: undefined,
|
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
let color: string[] = [];
|
let color: string[] = [];
|
||||||
@@ -139,11 +110,10 @@ function getOption() {
|
|||||||
trigger: "axis",
|
trigger: "axis",
|
||||||
zlevel: 1000,
|
zlevel: 1000,
|
||||||
z: 60,
|
z: 60,
|
||||||
backgroundColor: "rgb(50,50,50)",
|
|
||||||
confine: true,
|
confine: true,
|
||||||
textStyle: {
|
textStyle: {
|
||||||
fontSize: 13,
|
fontSize: 13,
|
||||||
color: "#ccc",
|
color: "#333",
|
||||||
},
|
},
|
||||||
enterable: true,
|
enterable: true,
|
||||||
extraCssText: "max-height: 300px; overflow: auto; border: none",
|
extraCssText: "max-height: 300px; overflow: auto; border: none",
|
||||||
@@ -186,4 +156,7 @@ function getOption() {
|
|||||||
series: temp,
|
series: temp,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
function clickEvent(params: EventParams) {
|
||||||
|
emits("click", params);
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@@ -46,6 +46,7 @@ limitations under the License. -->
|
|||||||
:intervalTime="intervalTime"
|
:intervalTime="intervalTime"
|
||||||
:colMetrics="colMetrics"
|
:colMetrics="colMetrics"
|
||||||
:config="config"
|
:config="config"
|
||||||
|
v-if="colMetrics.length"
|
||||||
/>
|
/>
|
||||||
</el-table>
|
</el-table>
|
||||||
</div>
|
</div>
|
||||||
@@ -96,7 +97,9 @@ const dashboardStore = useDashboardStore();
|
|||||||
const chartLoading = ref<boolean>(false);
|
const chartLoading = ref<boolean>(false);
|
||||||
const endpoints = ref<Endpoint[]>([]);
|
const endpoints = ref<Endpoint[]>([]);
|
||||||
const searchText = ref<string>("");
|
const searchText = ref<string>("");
|
||||||
const colMetrics = computed(() => props.config.metrics.map((d: string) => d));
|
const colMetrics = computed(() =>
|
||||||
|
(props.config.metrics || []).filter((d: string) => d)
|
||||||
|
);
|
||||||
|
|
||||||
if (props.needQuery) {
|
if (props.needQuery) {
|
||||||
queryEndpoints();
|
queryEndpoints();
|
||||||
@@ -119,7 +122,7 @@ async function queryEndpointMetrics(currentPods: Endpoint[]) {
|
|||||||
if (!currentPods.length) {
|
if (!currentPods.length) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const metrics = (props.config.metrics || []).filter((d: string) => d);
|
const metrics = props.config.metrics || [];
|
||||||
const metricTypes = props.config.metricTypes || [];
|
const metricTypes = props.config.metricTypes || [];
|
||||||
if (metrics.length && metrics[0] && metricTypes.length && metricTypes[0]) {
|
if (metrics.length && metrics[0] && metricTypes.length && metricTypes[0]) {
|
||||||
const params = await useQueryPodsMetrics(
|
const params = await useQueryPodsMetrics(
|
||||||
@@ -144,17 +147,17 @@ async function queryEndpointMetrics(currentPods: Endpoint[]) {
|
|||||||
endpoints.value = currentPods;
|
endpoints.value = currentPods;
|
||||||
}
|
}
|
||||||
function clickEndpoint(scope: any) {
|
function clickEndpoint(scope: any) {
|
||||||
const d = getDashboard({
|
const { dashboard } = getDashboard({
|
||||||
name: props.config.dashboardName,
|
name: props.config.dashboardName,
|
||||||
layer: dashboardStore.layerId,
|
layer: dashboardStore.layerId,
|
||||||
entity: EntityType[2].value,
|
entity: EntityType[2].value,
|
||||||
});
|
});
|
||||||
if (!d) {
|
if (!dashboard) {
|
||||||
ElMessage.error("No this dashboard");
|
ElMessage.error("No this dashboard");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
router.push(
|
router.push(
|
||||||
`/dashboard/${d.layer}/${d.entity}/${selectorStore.currentService.id}/${scope.row.id}/${d.name}`
|
`/dashboard/${dashboard.layer}/${dashboard.entity}/${selectorStore.currentService.id}/${scope.row.id}/${dashboard.name}`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
async function searchList() {
|
async function searchList() {
|
||||||
|
@@ -43,6 +43,7 @@ limitations under the License. -->
|
|||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<ColumnGraph
|
<ColumnGraph
|
||||||
|
v-if="colMetrics.length"
|
||||||
:intervalTime="intervalTime"
|
:intervalTime="intervalTime"
|
||||||
:colMetrics="colMetrics"
|
:colMetrics="colMetrics"
|
||||||
:config="config"
|
:config="config"
|
||||||
@@ -126,7 +127,9 @@ const chartLoading = ref<boolean>(false);
|
|||||||
const instances = ref<Instance[]>([]); // current instances
|
const instances = ref<Instance[]>([]); // current instances
|
||||||
const pageSize = 10;
|
const pageSize = 10;
|
||||||
const searchText = ref<string>("");
|
const searchText = ref<string>("");
|
||||||
const colMetrics = computed(() => props.config.metrics.map((d: string) => d));
|
const colMetrics = computed(() =>
|
||||||
|
(props.config.metrics || []).filter((d: string) => d)
|
||||||
|
);
|
||||||
if (props.needQuery) {
|
if (props.needQuery) {
|
||||||
queryInstance();
|
queryInstance();
|
||||||
}
|
}
|
||||||
@@ -151,7 +154,8 @@ async function queryInstanceMetrics(currentInstances: Instance[]) {
|
|||||||
if (!currentInstances.length) {
|
if (!currentInstances.length) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const { metrics, metricTypes } = props.config;
|
const metrics = props.config.metrics || [];
|
||||||
|
const metricTypes = props.config.metricTypes || [];
|
||||||
|
|
||||||
if (metrics.length && metrics[0] && metricTypes.length && metricTypes[0]) {
|
if (metrics.length && metrics[0] && metricTypes.length && metricTypes[0]) {
|
||||||
const params = await useQueryPodsMetrics(
|
const params = await useQueryPodsMetrics(
|
||||||
@@ -176,19 +180,19 @@ async function queryInstanceMetrics(currentInstances: Instance[]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function clickInstance(scope: any) {
|
function clickInstance(scope: any) {
|
||||||
const d = getDashboard({
|
const { dashboard } = getDashboard({
|
||||||
name: props.config.dashboardName,
|
name: props.config.dashboardName,
|
||||||
layer: dashboardStore.layerId,
|
layer: dashboardStore.layerId,
|
||||||
entity: EntityType[3].value,
|
entity: EntityType[3].value,
|
||||||
});
|
});
|
||||||
if (!d) {
|
if (!dashboard) {
|
||||||
ElMessage.error("No this dashboard");
|
ElMessage.error("No this dashboard");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
router.push(
|
router.push(
|
||||||
`/dashboard/${d.layer}/${d.entity}/${selectorStore.currentService.id}/${
|
`/dashboard/${dashboard.layer}/${dashboard.entity}/${
|
||||||
scope.row.id
|
selectorStore.currentService.id
|
||||||
}/${d.name.split(" ").join("-")}`
|
}/${scope.row.id}/${dashboard.name.split(" ").join("-")}`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -13,15 +13,15 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|||||||
See the License for the specific language governing permissions and
|
See the License for the specific language governing permissions and
|
||||||
limitations under the License. -->
|
limitations under the License. -->
|
||||||
<template>
|
<template>
|
||||||
<Graph :option="option" />
|
<Graph :option="option" @select="clickEvent" :filters="config.filters" />
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed } from "vue";
|
import { computed } from "vue";
|
||||||
import type { PropType } from "vue";
|
import type { PropType } from "vue";
|
||||||
import { Event } from "@/types/events";
|
import { LineConfig, EventParams } from "@/types/dashboard";
|
||||||
import { LineConfig } from "@/types/dashboard";
|
|
||||||
|
|
||||||
/*global defineProps */
|
/*global defineProps, defineEmits */
|
||||||
|
const emits = defineEmits(["click"]);
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
data: {
|
data: {
|
||||||
type: Object as PropType<{ [key: string]: number[] }>,
|
type: Object as PropType<{ [key: string]: number[] }>,
|
||||||
@@ -29,9 +29,20 @@ const props = defineProps({
|
|||||||
},
|
},
|
||||||
intervalTime: { type: Array as PropType<string[]>, default: () => [] },
|
intervalTime: { type: Array as PropType<string[]>, default: () => [] },
|
||||||
theme: { type: String, default: "light" },
|
theme: { type: String, default: "light" },
|
||||||
itemEvents: { type: Array as PropType<Event[]>, default: () => [] },
|
|
||||||
config: {
|
config: {
|
||||||
type: Object as PropType<LineConfig>,
|
type: Object as PropType<
|
||||||
|
LineConfig & {
|
||||||
|
filters: {
|
||||||
|
sourceId: string;
|
||||||
|
duration: {
|
||||||
|
startTime: string;
|
||||||
|
endTime: string;
|
||||||
|
};
|
||||||
|
isRange: boolean;
|
||||||
|
dataIndex?: number;
|
||||||
|
};
|
||||||
|
} & { id: string }
|
||||||
|
>,
|
||||||
default: () => ({
|
default: () => ({
|
||||||
step: false,
|
step: false,
|
||||||
smooth: false,
|
smooth: false,
|
||||||
@@ -49,30 +60,7 @@ function getOption() {
|
|||||||
const keys = Object.keys(props.data || {}).filter(
|
const keys = Object.keys(props.data || {}).filter(
|
||||||
(i: any) => Array.isArray(props.data[i]) && props.data[i].length
|
(i: any) => Array.isArray(props.data[i]) && props.data[i].length
|
||||||
);
|
);
|
||||||
const startP = keys.length > 1 ? 50 : 15;
|
const temp = keys.map((i: any) => {
|
||||||
const diff = 10;
|
|
||||||
const markAreas = (props.itemEvents || []).map(
|
|
||||||
(event: Event, index: number) => {
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
name: `${event.name}:${event.type}`,
|
|
||||||
xAxis: event.startTime,
|
|
||||||
y: startP + diff * index,
|
|
||||||
itemStyle: {
|
|
||||||
borderWidth: 2,
|
|
||||||
borderColor: event.type === "Normal" ? "#5dc859" : "#FF0087",
|
|
||||||
color: event.type === "Normal" ? "#5dc859" : "#FF0087",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: event.message,
|
|
||||||
xAxis: event.endTime,
|
|
||||||
y: startP + diff * (index + 1),
|
|
||||||
},
|
|
||||||
];
|
|
||||||
}
|
|
||||||
);
|
|
||||||
const temp = keys.map((i: any, index: number) => {
|
|
||||||
const serie: any = {
|
const serie: any = {
|
||||||
data: props.data[i].map((item: any, itemIndex: number) => [
|
data: props.data[i].map((item: any, itemIndex: number) => [
|
||||||
props.intervalTime[itemIndex],
|
props.intervalTime[itemIndex],
|
||||||
@@ -81,7 +69,7 @@ function getOption() {
|
|||||||
name: i,
|
name: i,
|
||||||
type: "line",
|
type: "line",
|
||||||
symbol: "circle",
|
symbol: "circle",
|
||||||
symbolSize: 6,
|
symbolSize: 8,
|
||||||
showSymbol: props.config.showSymbol,
|
showSymbol: props.config.showSymbol,
|
||||||
step: props.config.step,
|
step: props.config.step,
|
||||||
smooth: props.config.smooth,
|
smooth: props.config.smooth,
|
||||||
@@ -89,23 +77,6 @@ function getOption() {
|
|||||||
width: 1.5,
|
width: 1.5,
|
||||||
type: "solid",
|
type: "solid",
|
||||||
},
|
},
|
||||||
markArea:
|
|
||||||
index === 0
|
|
||||||
? {
|
|
||||||
silent: false,
|
|
||||||
data: markAreas,
|
|
||||||
label: {
|
|
||||||
show: false,
|
|
||||||
width: 60,
|
|
||||||
},
|
|
||||||
emphasis: {
|
|
||||||
label: {
|
|
||||||
position: "bottom",
|
|
||||||
show: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
: undefined,
|
|
||||||
};
|
};
|
||||||
if (props.config.type === "Area") {
|
if (props.config.type === "Area") {
|
||||||
serie.areaStyle = {
|
serie.areaStyle = {
|
||||||
@@ -145,10 +116,9 @@ function getOption() {
|
|||||||
}
|
}
|
||||||
const tooltip = {
|
const tooltip = {
|
||||||
trigger: "axis",
|
trigger: "axis",
|
||||||
backgroundColor: "rgb(50,50,50)",
|
|
||||||
textStyle: {
|
textStyle: {
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
color: "#ccc",
|
color: "#333",
|
||||||
},
|
},
|
||||||
enterable: true,
|
enterable: true,
|
||||||
confine: true,
|
confine: true,
|
||||||
@@ -215,4 +185,8 @@ function getOption() {
|
|||||||
series: temp,
|
series: temp,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function clickEvent(params: EventParams) {
|
||||||
|
emits("click", params);
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@@ -1,66 +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. -->
|
|
||||||
<template>
|
|
||||||
<Graph :option="option" />
|
|
||||||
</template>
|
|
||||||
<script lang="ts" setup>
|
|
||||||
import { computed } from "vue";
|
|
||||||
import type { PropType } from "vue";
|
|
||||||
|
|
||||||
/*global defineProps */
|
|
||||||
const props = defineProps({
|
|
||||||
data: {
|
|
||||||
type: Array as PropType<{ name: string; value: number }[]>,
|
|
||||||
default: () => [],
|
|
||||||
},
|
|
||||||
config: {
|
|
||||||
type: Object as PropType<{ sortOrder: string }>,
|
|
||||||
default: () => ({}),
|
|
||||||
},
|
|
||||||
});
|
|
||||||
const option = computed(() => getOption());
|
|
||||||
function getOption() {
|
|
||||||
return {
|
|
||||||
tooltip: {
|
|
||||||
trigger: "item",
|
|
||||||
},
|
|
||||||
legend: {
|
|
||||||
type: "scroll",
|
|
||||||
show: props.data.length === 1 ? false : true,
|
|
||||||
icon: "circle",
|
|
||||||
top: 0,
|
|
||||||
left: 0,
|
|
||||||
itemWidth: 12,
|
|
||||||
textStyle: {
|
|
||||||
color: "#333",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
series: [
|
|
||||||
{
|
|
||||||
type: "pie",
|
|
||||||
radius: "50%",
|
|
||||||
data: props.data,
|
|
||||||
emphasis: {
|
|
||||||
itemStyle: {
|
|
||||||
shadowBlur: 10,
|
|
||||||
shadowOffsetX: 0,
|
|
||||||
shadowColor: "rgba(0, 0, 0, 0.5)",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
</script>
|
|
@@ -58,6 +58,7 @@ limitations under the License. -->
|
|||||||
:intervalTime="intervalTime"
|
:intervalTime="intervalTime"
|
||||||
:colMetrics="colMetrics"
|
:colMetrics="colMetrics"
|
||||||
:config="config"
|
:config="config"
|
||||||
|
v-if="colMetrics.length"
|
||||||
/>
|
/>
|
||||||
</el-table>
|
</el-table>
|
||||||
</div>
|
</div>
|
||||||
@@ -81,6 +82,7 @@ import type { PropType } from "vue";
|
|||||||
import { ServiceListConfig } from "@/types/dashboard";
|
import { ServiceListConfig } from "@/types/dashboard";
|
||||||
import { useSelectorStore } from "@/store/modules/selectors";
|
import { useSelectorStore } from "@/store/modules/selectors";
|
||||||
import { useDashboardStore } from "@/store/modules/dashboard";
|
import { useDashboardStore } from "@/store/modules/dashboard";
|
||||||
|
import { useAppStoreWithOut } from "@/store/modules/app";
|
||||||
import { Service } from "@/types/selector";
|
import { Service } from "@/types/selector";
|
||||||
import { useQueryPodsMetrics, usePodsSource } from "@/hooks/useProcessor";
|
import { useQueryPodsMetrics, usePodsSource } from "@/hooks/useProcessor";
|
||||||
import { EntityType } from "../data";
|
import { EntityType } from "../data";
|
||||||
@@ -110,6 +112,7 @@ const props = defineProps({
|
|||||||
});
|
});
|
||||||
const selectorStore = useSelectorStore();
|
const selectorStore = useSelectorStore();
|
||||||
const dashboardStore = useDashboardStore();
|
const dashboardStore = useDashboardStore();
|
||||||
|
const appStore = useAppStoreWithOut();
|
||||||
const chartLoading = ref<boolean>(false);
|
const chartLoading = ref<boolean>(false);
|
||||||
const pageSize = 10;
|
const pageSize = 10;
|
||||||
const services = ref<Service[]>([]);
|
const services = ref<Service[]>([]);
|
||||||
@@ -117,7 +120,7 @@ const searchText = ref<string>("");
|
|||||||
const groups = ref<any>({});
|
const groups = ref<any>({});
|
||||||
const sortServices = ref<(Service & { merge: boolean })[]>([]);
|
const sortServices = ref<(Service & { merge: boolean })[]>([]);
|
||||||
const colMetrics = computed(() =>
|
const colMetrics = computed(() =>
|
||||||
props.config.metrics.filter((d: string) => d)
|
(props.config.metrics || []).filter((d: string) => d)
|
||||||
);
|
);
|
||||||
queryServices();
|
queryServices();
|
||||||
|
|
||||||
@@ -178,16 +181,16 @@ function setServices(arr: (Service & { merge: boolean })[]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function clickService(scope: any) {
|
function clickService(scope: any) {
|
||||||
const d = getDashboard({
|
const { dashboard } = getDashboard({
|
||||||
name: props.config.dashboardName,
|
name: props.config.dashboardName,
|
||||||
layer: dashboardStore.layerId,
|
layer: dashboardStore.layerId,
|
||||||
entity: EntityType[0].value,
|
entity: EntityType[0].value,
|
||||||
});
|
});
|
||||||
if (!d) {
|
if (!dashboard) {
|
||||||
ElMessage.error("No this dashboard");
|
ElMessage.error("No this dashboard");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const path = `/dashboard/${d.layer}/${d.entity}/${scope.row.id}/${d.name}`;
|
const path = `/dashboard/${dashboard.layer}/${dashboard.entity}/${scope.row.id}/${dashboard.name}`;
|
||||||
|
|
||||||
router.push(path);
|
router.push(path);
|
||||||
}
|
}
|
||||||
@@ -195,7 +198,8 @@ async function queryServiceMetrics(currentServices: Service[]) {
|
|||||||
if (!currentServices.length) {
|
if (!currentServices.length) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const { metrics, metricTypes } = props.config;
|
const metrics = props.config.metrics || [];
|
||||||
|
const metricTypes = props.config.metricTypes || [];
|
||||||
|
|
||||||
if (metrics.length && metrics[0] && metricTypes.length && metricTypes[0]) {
|
if (metrics.length && metrics[0] && metricTypes.length && metricTypes[0]) {
|
||||||
const params = await useQueryPodsMetrics(
|
const params = await useQueryPodsMetrics(
|
||||||
@@ -271,6 +275,14 @@ watch(
|
|||||||
queryServiceMetrics(services.value);
|
queryServiceMetrics(services.value);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
watch(
|
||||||
|
() => appStore.durationTime,
|
||||||
|
() => {
|
||||||
|
if (dashboardStore.entity === EntityType[1].value) {
|
||||||
|
queryServices();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@import "./style.scss";
|
@import "./style.scss";
|
||||||
|
@@ -21,7 +21,6 @@ import Bar from "./Bar.vue";
|
|||||||
import HeatMap from "./HeatMap.vue";
|
import HeatMap from "./HeatMap.vue";
|
||||||
import TopList from "./TopList.vue";
|
import TopList from "./TopList.vue";
|
||||||
import Table from "./Table.vue";
|
import Table from "./Table.vue";
|
||||||
import Pie from "./Pie.vue";
|
|
||||||
import Card from "./Card.vue";
|
import Card from "./Card.vue";
|
||||||
import InstanceList from "./InstanceList.vue";
|
import InstanceList from "./InstanceList.vue";
|
||||||
import EndpointList from "./EndpointList.vue";
|
import EndpointList from "./EndpointList.vue";
|
||||||
@@ -34,7 +33,6 @@ export default {
|
|||||||
TopList,
|
TopList,
|
||||||
Area,
|
Area,
|
||||||
Table,
|
Table,
|
||||||
Pie,
|
|
||||||
Card,
|
Card,
|
||||||
EndpointList,
|
EndpointList,
|
||||||
InstanceList,
|
InstanceList,
|
||||||
|
32
src/views/dashboard/graphs/topology.ts
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
/**
|
||||||
|
* 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 Area from "./Area.vue";
|
||||||
|
import Line from "./Line.vue";
|
||||||
|
import Bar from "./Bar.vue";
|
||||||
|
import TopList from "./TopList.vue";
|
||||||
|
import Table from "./Table.vue";
|
||||||
|
import Card from "./Card.vue";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
Line,
|
||||||
|
Bar,
|
||||||
|
TopList,
|
||||||
|
Area,
|
||||||
|
Table,
|
||||||
|
Card,
|
||||||
|
};
|
@@ -28,7 +28,7 @@ limitations under the License. -->
|
|||||||
:w="item.w"
|
:w="item.w"
|
||||||
:h="item.h"
|
:h="item.h"
|
||||||
:i="item.i"
|
:i="item.i"
|
||||||
:key="item.i"
|
:key="item.id"
|
||||||
@click="clickGrid(item, $event)"
|
@click="clickGrid(item, $event)"
|
||||||
:class="{ active: dashboardStore.activedGridItem === item.i }"
|
:class="{ active: dashboardStore.activedGridItem === item.i }"
|
||||||
:drag-ignore-from="dragIgnoreFrom"
|
:drag-ignore-from="dragIgnoreFrom"
|
||||||
|
@@ -14,72 +14,98 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License. -->
|
limitations under the License. -->
|
||||||
<template>
|
<template>
|
||||||
<div class="dashboard-tool flex-h">
|
<div class="dashboard-tool flex-h">
|
||||||
<div class="flex-h">
|
<div :class="isRelation ? 'flex-v' : 'flex-h'">
|
||||||
<div class="selectors-item" v-if="key !== 10">
|
<div class="flex-h">
|
||||||
<span class="label">$Service</span>
|
<div class="selectors-item" v-if="key !== 10">
|
||||||
<Selector
|
<span class="label">$Service</span>
|
||||||
v-model="states.currentService"
|
<Selector
|
||||||
:options="selectorStore.services"
|
v-model="states.currentService"
|
||||||
size="small"
|
:options="selectorStore.services"
|
||||||
placeholder="Select a service"
|
size="small"
|
||||||
@change="changeService"
|
placeholder="Select a service"
|
||||||
class="selectors"
|
@change="changeService"
|
||||||
/>
|
class="selectors"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="selectors-item" v-if="key === 3 || key === 4 || key === 5">
|
||||||
|
<span class="label">
|
||||||
|
{{
|
||||||
|
["EndpointRelation", "Endpoint"].includes(dashboardStore.entity)
|
||||||
|
? "$Endpoint"
|
||||||
|
: "$ServiceInstance"
|
||||||
|
}}
|
||||||
|
</span>
|
||||||
|
<Selector
|
||||||
|
v-model="states.currentPod"
|
||||||
|
:options="selectorStore.pods"
|
||||||
|
size="small"
|
||||||
|
placeholder="Select a data"
|
||||||
|
@change="changePods"
|
||||||
|
@query="searchPods"
|
||||||
|
class="selectorPod"
|
||||||
|
:isRemote="
|
||||||
|
['EndpointRelation', 'Endpoint'].includes(dashboardStore.entity)
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="selectors-item" v-if="key === 5">
|
||||||
|
<span class="label"> $Process </span>
|
||||||
|
<Selector
|
||||||
|
v-model="states.currentProcess"
|
||||||
|
:options="selectorStore.processes"
|
||||||
|
size="small"
|
||||||
|
placeholder="Select a data"
|
||||||
|
@change="changeProcess"
|
||||||
|
class="selectors"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="selectors-item" v-if="key === 3 || key === 4">
|
<div class="flex-h" :class="isRelation ? 'relation' : ''">
|
||||||
<span class="label">
|
<div class="selectors-item" v-if="key === 2 || key === 4 || key === 5">
|
||||||
{{
|
<span class="label">$DestinationService</span>
|
||||||
["EndpointRelation", "Endpoint"].includes(dashboardStore.entity)
|
<Selector
|
||||||
? "$Endpoint"
|
v-model="states.currentDestService"
|
||||||
: "$ServiceInstance"
|
:options="selectorStore.destServices"
|
||||||
}}
|
size="small"
|
||||||
</span>
|
placeholder="Select a service"
|
||||||
<Selector
|
@change="changeDestService"
|
||||||
v-model="states.currentPod"
|
class="selectors"
|
||||||
:options="selectorStore.pods"
|
/>
|
||||||
size="small"
|
</div>
|
||||||
placeholder="Select a data"
|
<div class="selectors-item" v-if="key === 4 || key === 5">
|
||||||
@change="changePods"
|
<span class="label">
|
||||||
@query="searchPods"
|
{{
|
||||||
class="selectorPod"
|
dashboardStore.entity === "EndpointRelation"
|
||||||
:isRemote="
|
? "$DestinationEndpoint"
|
||||||
['EndpointRelation', 'Endpoint'].includes(dashboardStore.entity)
|
: "$DestinationServiceInstance"
|
||||||
"
|
}}
|
||||||
/>
|
</span>
|
||||||
</div>
|
<Selector
|
||||||
<div class="selectors-item" v-if="key === 2 || key === 4">
|
v-model="states.currentDestPod"
|
||||||
<span class="label">$DestinationService</span>
|
:options="selectorStore.destPods"
|
||||||
<Selector
|
size="small"
|
||||||
v-model="states.currentDestService"
|
placeholder="Select a data"
|
||||||
:options="selectorStore.destServices"
|
@change="changeDestPods"
|
||||||
size="small"
|
class="selectorPod"
|
||||||
placeholder="Select a service"
|
@query="searchDestPods"
|
||||||
@change="changeDestService"
|
:isRemote="dashboardStore.entity === 'EndpointRelation'"
|
||||||
class="selectors"
|
/>
|
||||||
/>
|
</div>
|
||||||
</div>
|
<div class="selectors-item" v-if="key === 5">
|
||||||
<div class="selectors-item" v-if="key === 4">
|
<span class="label"> $DestinationProcess </span>
|
||||||
<span class="label">
|
<Selector
|
||||||
{{
|
v-model="states.currentDestProcess"
|
||||||
dashboardStore.entity === "EndpointRelation"
|
:options="selectorStore.destProcesses"
|
||||||
? "$DestinationEndpoint"
|
size="small"
|
||||||
: "$DestinationServiceInstance"
|
placeholder="Select a data"
|
||||||
}}
|
@change="changeDestProcess"
|
||||||
</span>
|
class="selectors"
|
||||||
<Selector
|
/>
|
||||||
v-model="states.currentDestPod"
|
</div>
|
||||||
:options="selectorStore.destPods"
|
|
||||||
size="small"
|
|
||||||
placeholder="Select a data"
|
|
||||||
@change="changeDestPods"
|
|
||||||
class="selectorPod"
|
|
||||||
@query="searchDestPods"
|
|
||||||
:isRemote="dashboardStore.entity === 'EndpointRelation'"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex-h tools" v-loading="loading" v-if="!appStore.isMobile">
|
<div class="flex-h tools" v-loading="loading" v-if="!appStore.isMobile">
|
||||||
<div class="tool-icons flex-h" v-if="dashboardStore.editMode">
|
<div class="tool-icons" v-if="dashboardStore.editMode">
|
||||||
<el-dropdown content="Controls" placement="bottom" :persistent="false">
|
<el-dropdown content="Controls" placement="bottom" :persistent="false">
|
||||||
<i>
|
<i>
|
||||||
<Icon class="icon-btn" size="sm" iconName="control" />
|
<Icon class="icon-btn" size="sm" iconName="control" />
|
||||||
@@ -133,6 +159,7 @@ import {
|
|||||||
EndpointRelationTools,
|
EndpointRelationTools,
|
||||||
InstanceRelationTools,
|
InstanceRelationTools,
|
||||||
ServiceRelationTools,
|
ServiceRelationTools,
|
||||||
|
ProcessTools,
|
||||||
} from "../data";
|
} from "../data";
|
||||||
import { useSelectorStore } from "@/store/modules/selectors";
|
import { useSelectorStore } from "@/store/modules/selectors";
|
||||||
import { ElMessage } from "element-plus";
|
import { ElMessage } from "element-plus";
|
||||||
@@ -144,9 +171,8 @@ const dashboardStore = useDashboardStore();
|
|||||||
const selectorStore = useSelectorStore();
|
const selectorStore = useSelectorStore();
|
||||||
const appStore = useAppStoreWithOut();
|
const appStore = useAppStoreWithOut();
|
||||||
const params = useRoute().params;
|
const params = useRoute().params;
|
||||||
const toolIcons = ref<{ name: string; content: string; id: string }[]>(
|
const toolIcons =
|
||||||
EndpointRelationTools
|
ref<{ name: string; content: string; id: string }[]>(AllTools);
|
||||||
);
|
|
||||||
const loading = ref<boolean>(false);
|
const loading = ref<boolean>(false);
|
||||||
const states = reactive<{
|
const states = reactive<{
|
||||||
destService: string;
|
destService: string;
|
||||||
@@ -154,16 +180,20 @@ const states = reactive<{
|
|||||||
key: number;
|
key: number;
|
||||||
currentService: string;
|
currentService: string;
|
||||||
currentPod: string;
|
currentPod: string;
|
||||||
|
currentProcess: string;
|
||||||
currentDestService: string;
|
currentDestService: string;
|
||||||
currentDestPod: string;
|
currentDestPod: string;
|
||||||
|
currentDestProcess: string;
|
||||||
}>({
|
}>({
|
||||||
destService: "",
|
destService: "",
|
||||||
destPod: "",
|
destPod: "",
|
||||||
key: 0,
|
key: 0,
|
||||||
currentService: "",
|
currentService: "",
|
||||||
currentPod: "",
|
currentPod: "",
|
||||||
|
currentProcess: "",
|
||||||
currentDestService: "",
|
currentDestService: "",
|
||||||
currentDestPod: "",
|
currentDestPod: "",
|
||||||
|
currentDestProcess: "",
|
||||||
});
|
});
|
||||||
const key = computed(() => {
|
const key = computed(() => {
|
||||||
const type = EntityType.find(
|
const type = EntityType.find(
|
||||||
@@ -172,6 +202,14 @@ const key = computed(() => {
|
|||||||
return (type && type.key) || 0;
|
return (type && type.key) || 0;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const isRelation = computed(() => {
|
||||||
|
return [
|
||||||
|
EntityType[7].value,
|
||||||
|
EntityType[6].value,
|
||||||
|
EntityType[5].value,
|
||||||
|
].includes(dashboardStore.entity);
|
||||||
|
});
|
||||||
|
|
||||||
setCurrentDashboard();
|
setCurrentDashboard();
|
||||||
appStore.setEventStack([initSelector]);
|
appStore.setEventStack([initSelector]);
|
||||||
initSelector();
|
initSelector();
|
||||||
@@ -199,6 +237,7 @@ async function setSelector() {
|
|||||||
EntityType[3].value,
|
EntityType[3].value,
|
||||||
EntityType[5].value,
|
EntityType[5].value,
|
||||||
EntityType[6].value,
|
EntityType[6].value,
|
||||||
|
EntityType[7].value,
|
||||||
].includes(String(params.entity))
|
].includes(String(params.entity))
|
||||||
) {
|
) {
|
||||||
setSourceSelector();
|
setSourceSelector();
|
||||||
@@ -248,25 +287,7 @@ async function setSourceSelector() {
|
|||||||
await selectorStore.getService(String(params.serviceId));
|
await selectorStore.getService(String(params.serviceId));
|
||||||
states.currentService = selectorStore.currentService.value;
|
states.currentService = selectorStore.currentService.value;
|
||||||
const e = String(params.entity).split("Relation")[0];
|
const e = String(params.entity).split("Relation")[0];
|
||||||
await fetchPods(e, selectorStore.currentService.id, false);
|
await fetchPods(e, selectorStore.currentService.id, true);
|
||||||
if (!(selectorStore.pods.length && selectorStore.pods[0])) {
|
|
||||||
selectorStore.setCurrentPod(null);
|
|
||||||
states.currentPod = "";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const pod = params.podId || selectorStore.pods[0].id;
|
|
||||||
let currentPod;
|
|
||||||
if (states.currentPod) {
|
|
||||||
currentPod = selectorStore.pods.find(
|
|
||||||
(d: { label: string }) => d.label === states.currentPod
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
currentPod = selectorStore.pods.find((d: { id: string }) => d.id === pod);
|
|
||||||
}
|
|
||||||
if (currentPod) {
|
|
||||||
selectorStore.setCurrentPod(currentPod);
|
|
||||||
states.currentPod = currentPod.label;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function setDestSelector() {
|
async function setDestSelector() {
|
||||||
@@ -275,28 +296,8 @@ async function setDestSelector() {
|
|||||||
await fetchPods(
|
await fetchPods(
|
||||||
String(params.entity),
|
String(params.entity),
|
||||||
selectorStore.currentDestService.id,
|
selectorStore.currentDestService.id,
|
||||||
false
|
true
|
||||||
);
|
);
|
||||||
if (!(selectorStore.destPods.length && selectorStore.destPods[0])) {
|
|
||||||
selectorStore.setCurrentDestPod(null);
|
|
||||||
states.currentDestPod = "";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const destPod = params.destPodId || selectorStore.destPods[0].id;
|
|
||||||
let currentDestPod = { label: "" };
|
|
||||||
if (states.currentDestPod) {
|
|
||||||
currentDestPod = selectorStore.pods.find(
|
|
||||||
(d: { label: string }) => d.label === states.currentDestPod
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
currentDestPod = selectorStore.destPods.find(
|
|
||||||
(d: { id: string }) => d.id === destPod
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (currentDestPod) {
|
|
||||||
selectorStore.setCurrentDestPod(currentDestPod);
|
|
||||||
states.currentDestPod = currentDestPod.label;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getServices() {
|
async function getServices() {
|
||||||
@@ -325,16 +326,21 @@ async function getServices() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
selectorStore.setCurrentService(s || null);
|
selectorStore.setCurrentService(s || null);
|
||||||
let d;
|
let d,
|
||||||
|
val = 1;
|
||||||
|
if (key.value === 5) {
|
||||||
|
val = 0;
|
||||||
|
}
|
||||||
if (states.currentService) {
|
if (states.currentService) {
|
||||||
d = (selectorStore.services || []).find(
|
d = (selectorStore.services || []).find(
|
||||||
(d: { label: string }) => d.label === states.currentDestService
|
(d: { label: string }) => d.label === states.currentDestService
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
d = (selectorStore.services || []).find(
|
d = (selectorStore.services || []).find(
|
||||||
(d: unknown, index: number) => index === 1
|
(d: unknown, index: number) => index === val
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
selectorStore.setCurrentDestService(d || null);
|
selectorStore.setCurrentDestService(d || null);
|
||||||
if (!selectorStore.currentService) {
|
if (!selectorStore.currentService) {
|
||||||
return;
|
return;
|
||||||
@@ -347,62 +353,86 @@ async function getServices() {
|
|||||||
EntityType[3].value,
|
EntityType[3].value,
|
||||||
EntityType[5].value,
|
EntityType[5].value,
|
||||||
EntityType[6].value,
|
EntityType[6].value,
|
||||||
|
EntityType[7].value,
|
||||||
].includes(dashboardStore.entity)
|
].includes(dashboardStore.entity)
|
||||||
) {
|
) {
|
||||||
fetchPods(e, selectorStore.currentService.id, true);
|
await fetchPods(e, selectorStore.currentService.id, true);
|
||||||
}
|
}
|
||||||
if (!selectorStore.currentDestService) {
|
if (!selectorStore.currentDestService) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
states.currentDestService = selectorStore.currentDestService.value;
|
states.currentDestService = selectorStore.currentDestService.value;
|
||||||
if (
|
if (
|
||||||
[EntityType[5].value, EntityType[6].value].includes(dashboardStore.entity)
|
[EntityType[5].value, EntityType[6].value, EntityType[7].value].includes(
|
||||||
|
dashboardStore.entity
|
||||||
|
)
|
||||||
) {
|
) {
|
||||||
fetchPods(dashboardStore.entity, selectorStore.currentDestService.id, true);
|
await fetchPods(
|
||||||
|
dashboardStore.entity,
|
||||||
|
selectorStore.currentDestService.id,
|
||||||
|
true
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function changeService(service: any) {
|
async function changeService(service: Option[]) {
|
||||||
if (service[0]) {
|
if (service[0]) {
|
||||||
states.currentService = service[0].value;
|
states.currentService = service[0].value;
|
||||||
selectorStore.setCurrentService(service[0]);
|
selectorStore.setCurrentService(service[0]);
|
||||||
const e = dashboardStore.entity.split("Relation")[0];
|
|
||||||
selectorStore.setCurrentPod(null);
|
selectorStore.setCurrentPod(null);
|
||||||
states.currentPod = "";
|
states.currentPod = "";
|
||||||
fetchPods(e, selectorStore.currentService.id, true);
|
states.currentProcess = "";
|
||||||
|
if (dashboardStore.entity === EntityType[7].value) {
|
||||||
|
fetchPods("Process", selectorStore.currentService.id, true);
|
||||||
|
} else {
|
||||||
|
fetchPods(dashboardStore.entity, selectorStore.currentService.id, true);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
selectorStore.setCurrentService(null);
|
selectorStore.setCurrentService(null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function changeDestService(service: any) {
|
function changeDestService(service: Option[]) {
|
||||||
if (service[0]) {
|
if (service[0]) {
|
||||||
states.currentDestService = service[0].value;
|
states.currentDestService = service[0].value;
|
||||||
selectorStore.setCurrentDestService(service[0]);
|
selectorStore.setCurrentDestService(service[0]);
|
||||||
selectorStore.setCurrentDestPod(null);
|
selectorStore.setCurrentDestPod(null);
|
||||||
states.currentDestPod = "";
|
states.currentDestPod = "";
|
||||||
|
states.currentDestProcess = "";
|
||||||
fetchPods(dashboardStore.entity, selectorStore.currentDestService.id, true);
|
fetchPods(dashboardStore.entity, selectorStore.currentDestService.id, true);
|
||||||
} else {
|
} else {
|
||||||
selectorStore.setCurrentDestService(null);
|
selectorStore.setCurrentDestService(null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function changePods(pod: any) {
|
async function changePods(pod: Option[]) {
|
||||||
if (pod[0]) {
|
selectorStore.setCurrentPod(pod[0] || null);
|
||||||
selectorStore.setCurrentPod(pod[0]);
|
if (dashboardStore.entity === EntityType[7].value) {
|
||||||
} else {
|
selectorStore.setCurrentProcess(null);
|
||||||
selectorStore.setCurrentPod("");
|
states.currentProcess = "";
|
||||||
|
fetchProcess(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function changeDestPods(pod: any) {
|
function changeDestPods(pod: Option[]) {
|
||||||
if (pod[0]) {
|
selectorStore.setCurrentDestPod(pod[0] || null);
|
||||||
selectorStore.setCurrentDestPod(pod[0]);
|
if (dashboardStore.entity === EntityType[7].value) {
|
||||||
} else {
|
selectorStore.setCurrentDestProcess(null);
|
||||||
selectorStore.setCurrentDestPod(null);
|
states.currentDestProcess = "";
|
||||||
|
fetchDestProcess(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function changeDestProcess(pod: Option[]) {
|
||||||
|
selectorStore.setCurrentDestProcess(pod[0] || null);
|
||||||
|
states.currentDestProcess = pod[0].label || "";
|
||||||
|
}
|
||||||
|
|
||||||
|
function changeProcess(pod: Option[]) {
|
||||||
|
selectorStore.setCurrentProcess(pod[0] || null);
|
||||||
|
states.currentProcess = pod[0].label || "";
|
||||||
|
}
|
||||||
|
|
||||||
function changeMode() {
|
function changeMode() {
|
||||||
if (dashboardStore.editMode) {
|
if (dashboardStore.editMode) {
|
||||||
ElMessage.warning(t("editWarning"));
|
ElMessage.warning(t("editWarning"));
|
||||||
@@ -458,6 +488,15 @@ function setTabControls(id: string) {
|
|||||||
case "addDemandLog":
|
case "addDemandLog":
|
||||||
dashboardStore.addTabControls("DemandLog");
|
dashboardStore.addTabControls("DemandLog");
|
||||||
break;
|
break;
|
||||||
|
case "addEvent":
|
||||||
|
dashboardStore.addTabControls("Event");
|
||||||
|
break;
|
||||||
|
case "addNetworkProfiling":
|
||||||
|
dashboardStore.addTabControls("NetworkProfiling");
|
||||||
|
break;
|
||||||
|
case "addTimeRange":
|
||||||
|
dashboardStore.addTabControls("TimeRange");
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
ElMessage.info("Don't support this control");
|
ElMessage.info("Don't support this control");
|
||||||
break;
|
break;
|
||||||
@@ -493,6 +532,15 @@ function setControls(id: string) {
|
|||||||
case "addDemandLog":
|
case "addDemandLog":
|
||||||
dashboardStore.addControl("DemandLog");
|
dashboardStore.addControl("DemandLog");
|
||||||
break;
|
break;
|
||||||
|
case "addEvent":
|
||||||
|
dashboardStore.addControl("Event");
|
||||||
|
break;
|
||||||
|
case "addNetworkProfiling":
|
||||||
|
dashboardStore.addControl("NetworkProfiling");
|
||||||
|
break;
|
||||||
|
case "addTimeRange":
|
||||||
|
dashboardStore.addControl("TimeRange");
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
dashboardStore.addControl("Widget");
|
dashboardStore.addControl("Widget");
|
||||||
}
|
}
|
||||||
@@ -509,35 +557,13 @@ async function fetchPods(
|
|||||||
case EntityType[2].value:
|
case EntityType[2].value:
|
||||||
resp = await selectorStore.getEndpoints({ serviceId, ...param });
|
resp = await selectorStore.getEndpoints({ serviceId, ...param });
|
||||||
if (setPod) {
|
if (setPod) {
|
||||||
let p;
|
updateCurrentPod();
|
||||||
if (states.currentPod) {
|
|
||||||
p = selectorStore.pods.find(
|
|
||||||
(d: { label: unknown }) => d.label === states.currentPod
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
p = selectorStore.pods.find(
|
|
||||||
(d: unknown, index: number) => index === 0
|
|
||||||
);
|
|
||||||
}
|
|
||||||
selectorStore.setCurrentPod(p || null);
|
|
||||||
states.currentPod = selectorStore.currentPod.label;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case EntityType[3].value:
|
case EntityType[3].value:
|
||||||
resp = await selectorStore.getServiceInstances({ serviceId });
|
resp = await selectorStore.getServiceInstances({ serviceId });
|
||||||
if (setPod) {
|
if (setPod) {
|
||||||
let p;
|
updateCurrentPod();
|
||||||
if (states.currentPod) {
|
|
||||||
p = selectorStore.pods.find(
|
|
||||||
(d: { label: string }) => d.label === states.currentPod
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
p = selectorStore.pods.find(
|
|
||||||
(d: { label: string }, index: number) => index === 0
|
|
||||||
);
|
|
||||||
}
|
|
||||||
selectorStore.setCurrentPod(p || null);
|
|
||||||
states.currentPod = selectorStore.currentPod.label;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case EntityType[6].value:
|
case EntityType[6].value:
|
||||||
@@ -547,18 +573,7 @@ async function fetchPods(
|
|||||||
...param,
|
...param,
|
||||||
});
|
});
|
||||||
if (setPod) {
|
if (setPod) {
|
||||||
let p;
|
updateCurrentDestPod();
|
||||||
if (states.currentDestPod) {
|
|
||||||
p = selectorStore.destPods.find(
|
|
||||||
(d: { label: string }) => d.label === states.currentDestPod
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
p = selectorStore.destPods.find(
|
|
||||||
(d: { label: string }, index: number) => index === 0
|
|
||||||
);
|
|
||||||
}
|
|
||||||
selectorStore.setCurrentDestPod(p || null);
|
|
||||||
states.currentDestPod = selectorStore.currentDestPod.label;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case EntityType[5].value:
|
case EntityType[5].value:
|
||||||
@@ -567,20 +582,17 @@ async function fetchPods(
|
|||||||
isRelation: true,
|
isRelation: true,
|
||||||
});
|
});
|
||||||
if (setPod) {
|
if (setPod) {
|
||||||
let p;
|
updateCurrentDestPod();
|
||||||
if (states.currentDestPod) {
|
|
||||||
p = selectorStore.destPods.find(
|
|
||||||
(d: { label: string }) => d.label === states.currentDestPod
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
p = selectorStore.destPods.find(
|
|
||||||
(d: { label: string }, index: number) => index === 0
|
|
||||||
);
|
|
||||||
}
|
|
||||||
selectorStore.setCurrentDestPod(p || null);
|
|
||||||
states.currentDestPod = selectorStore.currentDestPod.label;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case EntityType[7].value:
|
||||||
|
await fetchPods(EntityType[5].value, serviceId, setPod, param);
|
||||||
|
resp = await fetchDestProcess(setPod);
|
||||||
|
break;
|
||||||
|
case "Process":
|
||||||
|
await fetchPods(EntityType[3].value, serviceId, setPod, param);
|
||||||
|
resp = await fetchProcess(setPod);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
resp = {};
|
resp = {};
|
||||||
}
|
}
|
||||||
@@ -588,6 +600,81 @@ async function fetchPods(
|
|||||||
ElMessage.error(resp.errors);
|
ElMessage.error(resp.errors);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function fetchProcess(setPod: boolean) {
|
||||||
|
const resp = await selectorStore.getProcesses({
|
||||||
|
instanceId: selectorStore.currentPod.id,
|
||||||
|
});
|
||||||
|
if (setPod) {
|
||||||
|
const process = params.processId || selectorStore.processes[0].id;
|
||||||
|
const currentProcess = selectorStore.processes.find(
|
||||||
|
(d: { id: string }) => d.id === process
|
||||||
|
);
|
||||||
|
if (currentProcess) {
|
||||||
|
selectorStore.setCurrentProcess(currentProcess);
|
||||||
|
states.currentProcess = currentProcess.label;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return resp;
|
||||||
|
}
|
||||||
|
async function fetchDestProcess(setPod: boolean) {
|
||||||
|
const resp = await selectorStore.getProcesses({
|
||||||
|
instanceId: selectorStore.currentDestPod.id,
|
||||||
|
isRelation: true,
|
||||||
|
});
|
||||||
|
if (setPod) {
|
||||||
|
const destProcess =
|
||||||
|
params.destProcessId || selectorStore.destProcesses[0].id;
|
||||||
|
const currentDestProcess = selectorStore.destProcesses.find(
|
||||||
|
(d: { id: string }) => d.id === destProcess
|
||||||
|
);
|
||||||
|
if (!currentDestProcess) {
|
||||||
|
states.currentDestProcess = "";
|
||||||
|
selectorStore.setCurrentDestProcess(null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
selectorStore.setCurrentDestProcess(currentDestProcess);
|
||||||
|
states.currentDestProcess = currentDestProcess.label;
|
||||||
|
}
|
||||||
|
return resp;
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateCurrentDestPod() {
|
||||||
|
if (!(selectorStore.destPods.length && selectorStore.destPods[0])) {
|
||||||
|
selectorStore.setCurrentDestPod(null);
|
||||||
|
states.currentDestPod = "";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const destPod = params.destPodId || selectorStore.destPods[0].id;
|
||||||
|
const currentDestPod = selectorStore.destPods.find(
|
||||||
|
(d: { id: string }) => d.id === destPod
|
||||||
|
);
|
||||||
|
if (!currentDestPod) {
|
||||||
|
states.currentDestPod = "";
|
||||||
|
selectorStore.setCurrentDestPod(null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
selectorStore.setCurrentDestPod(currentDestPod);
|
||||||
|
states.currentDestPod = currentDestPod.label;
|
||||||
|
}
|
||||||
|
function updateCurrentPod() {
|
||||||
|
if (!(selectorStore.pods.length && selectorStore.pods[0])) {
|
||||||
|
selectorStore.setCurrentPod(null);
|
||||||
|
states.currentPod = "";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const pod = params.podId || selectorStore.pods[0].id;
|
||||||
|
const currentPod = selectorStore.pods.find(
|
||||||
|
(d: { id: string }) => d.id === pod
|
||||||
|
);
|
||||||
|
if (!currentPod) {
|
||||||
|
selectorStore.setCurrentPod(null);
|
||||||
|
states.currentPod = "";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
selectorStore.setCurrentPod(currentPod);
|
||||||
|
states.currentPod = currentPod.label;
|
||||||
|
}
|
||||||
function getTools() {
|
function getTools() {
|
||||||
switch (params.entity) {
|
switch (params.entity) {
|
||||||
case EntityType[1].value:
|
case EntityType[1].value:
|
||||||
@@ -611,8 +698,11 @@ function getTools() {
|
|||||||
case EntityType[6].value:
|
case EntityType[6].value:
|
||||||
toolIcons.value = EndpointRelationTools;
|
toolIcons.value = EndpointRelationTools;
|
||||||
break;
|
break;
|
||||||
|
case EntityType[7].value:
|
||||||
|
toolIcons.value = ProcessTools;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
toolIcons.value = EndpointRelationTools;
|
toolIcons.value = AllTools;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function searchPods(query: string) {
|
function searchPods(query: string) {
|
||||||
@@ -695,4 +785,8 @@ watch(
|
|||||||
.selectorPod {
|
.selectorPod {
|
||||||
width: 300px;
|
width: 300px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.relation {
|
||||||
|
margin-top: 5px;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
81
src/views/dashboard/related/components/TaskDetails.vue
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
<!-- Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
contributor license agreements. See the NOTICE file distributed with
|
||||||
|
this work for additional information regarding copyright ownership.
|
||||||
|
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
(the "License"); you may not use this file except in compliance with
|
||||||
|
the License. You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License. -->
|
||||||
|
<template>
|
||||||
|
<div class="profile-detail flex-v">
|
||||||
|
<div>
|
||||||
|
<h5 class="mb-10">{{ t("task") }}.</h5>
|
||||||
|
<div class="mb-10 clear item">
|
||||||
|
<span class="g-sm-4 grey">{{ t("taskId") }}:</span>
|
||||||
|
<span class="g-sm-8 wba">
|
||||||
|
{{ details.taskId }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="mb-10 clear item">
|
||||||
|
<span class="g-sm-4 grey">{{ t("service") }}:</span>
|
||||||
|
<span class="g-sm-8 wba">
|
||||||
|
{{ details.serviceName }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="mb-10 clear item">
|
||||||
|
<span class="g-sm-4 grey">{{ t("labels") }}:</span>
|
||||||
|
<span class="g-sm-8 wba">
|
||||||
|
{{ details.processLabels.join(";") }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="mb-10 clear item">
|
||||||
|
<span class="g-sm-4 grey">{{ t("monitorTime") }}:</span>
|
||||||
|
<span class="g-sm-8 wba">
|
||||||
|
{{ dateFormat(details.taskStartTime) }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="mb-10 clear item">
|
||||||
|
<span class="g-sm-4 grey">{{ t("monitorDuration") }}:</span>
|
||||||
|
<span class="g-sm-8 wba">
|
||||||
|
{{ details.fixedTriggerDuration / 60 }} min
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="mb-10 clear item">
|
||||||
|
<span class="g-sm-4 grey">{{ t("triggerType") }}:</span>
|
||||||
|
<span class="g-sm-8 wba">{{ details.triggerType }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="mb-10 clear item">
|
||||||
|
<span class="g-sm-4 grey">{{ t("targetType") }}:</span>
|
||||||
|
<span class="g-sm-8 wba">{{ details.targetType }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import type { PropType } from "vue";
|
||||||
|
import dayjs from "dayjs";
|
||||||
|
import { useI18n } from "vue-i18n";
|
||||||
|
import { EBPFTaskList } from "@/types/ebpf";
|
||||||
|
|
||||||
|
/*global defineProps */
|
||||||
|
defineProps({
|
||||||
|
details: {
|
||||||
|
type: Object as PropType<EBPFTaskList>,
|
||||||
|
default: () => ({}),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const { t } = useI18n();
|
||||||
|
const dateFormat = (date: number, pattern = "YYYY-MM-DD HH:mm:ss") =>
|
||||||
|
dayjs(date).format(pattern);
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.item span {
|
||||||
|
height: 21px;
|
||||||
|
}
|
||||||
|
</style>
|