This is an automated email from the ASF dual-hosted git repository.
wusheng pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/skywalking-booster-ui.git
The following commit(s) were added to refs/heads/main by this push:
new ccb4d78f feat: add the `layers` filed and associate layers dashboards
for the service topology nodes (#370)
ccb4d78f is described below
commit ccb4d78f6bfb298a4921f0952fec82afedf7cf0f
Author: Fine0830 <[email protected]>
AuthorDate: Tue Jan 30 15:59:16 2024 +0800
feat: add the `layers` filed and associate layers dashboards for the
service topology nodes (#370)
---
src/graphql/fragments/topology.ts | 1 +
src/store/modules/topology.ts | 15 ++--
src/types/topology.d.ts | 3 +-
.../related/topology/service/ServiceMap.vue | 94 ++++++++++++++++++----
4 files changed, 89 insertions(+), 24 deletions(-)
diff --git a/src/graphql/fragments/topology.ts
b/src/graphql/fragments/topology.ts
index 327c1408..bdbf9158 100644
--- a/src/graphql/fragments/topology.ts
+++ b/src/graphql/fragments/topology.ts
@@ -23,6 +23,7 @@ export const ServicesTopology = {
name
type
isReal
+ layers
}
calls {
id
diff --git a/src/store/modules/topology.ts b/src/store/modules/topology.ts
index b14e09fd..dee037ae 100644
--- a/src/store/modules/topology.ts
+++ b/src/store/modules/topology.ts
@@ -16,7 +16,6 @@
*/
import { defineStore } from "pinia";
import { store } from "@/store";
-import type { Service } from "@/types/selector";
import type { Node, Call, HierarchyNode, ServiceHierarchy, InstanceHierarchy }
from "@/types/topology";
import graphql from "@/graphql";
import { useSelectorStore } from "@/store/modules/selectors";
@@ -88,12 +87,9 @@ export const topologyStore = defineStore({
},
setTopology(data: { nodes: Node[]; calls: Call[] }) {
const obj = {} as Recordable;
- const services = useSelectorStore().services;
const nodes = (data.nodes || []).reduce((prev: Node[], next: Node) => {
if (!obj[next.id]) {
obj[next.id] = true;
- const s = services.filter((d: Service) => d.id === next.id)[0] || {};
- next.layer = s.layers ? s.layers[0] : null;
prev.push(next);
}
return prev;
@@ -603,7 +599,12 @@ export const topologyStore = defineStore({
const dashboardStore = useDashboardStore();
const { currentService } = useSelectorStore();
const id = this.node ? this.node.id : (currentService || {}).id;
- const layer = this.node ? this.node.layer : dashboardStore.layerId;
+ let layer = dashboardStore.layerId;
+ if (this.node) {
+ layer = this.node.layers.includes(dashboardStore.layerId)
+ ? dashboardStore.layerId
+ : this.node.layers.filter((d: string) => d !==
dashboardStore.layerId)[0];
+ }
if (!(id && layer)) {
return new Promise((resolve) => resolve({}));
}
@@ -659,7 +660,7 @@ export const topologyStore = defineStore({
return metrics;
},
async queryHierarchyNodeExpressions(expressions: string[], layer: string) {
- const nodes = this.hierarchyServiceNodes.filter((n: Node) => n.layer ===
layer);
+ const nodes = this.hierarchyServiceNodes.filter((n: HierarchyNode) =>
n.layer === layer);
if (!nodes.length) {
this.setHierarchyNodeMetricValue({}, layer);
return;
@@ -672,7 +673,7 @@ export const topologyStore = defineStore({
this.setHierarchyNodeMetricValue(metrics, layer);
},
async queryHierarchyInstanceNodeExpressions(expressions: string[], layer:
string) {
- const nodes = this.hierarchyInstanceNodes.filter((n: Node) => n.layer
=== layer);
+ const nodes = this.hierarchyInstanceNodes.filter((n: HierarchyNode) =>
n.layer === layer);
if (!expressions.length) {
this.setHierarchyInstanceNodeMetricValue({}, layer);
diff --git a/src/types/topology.d.ts b/src/types/topology.d.ts
index d2e4c4e3..ec7feb11 100644
--- a/src/types/topology.d.ts
+++ b/src/types/topology.d.ts
@@ -43,7 +43,7 @@ export interface Node {
name: string;
type: string;
isReal: boolean;
- layer?: string;
+ layers: string[];
serviceName?: string;
height?: number;
width?: number;
@@ -52,6 +52,7 @@ export interface Node {
level?: number;
l?: number;
key?: string;
+ layer?: string;
}
export interface ServiceHierarchy {
diff --git a/src/views/dashboard/related/topology/service/ServiceMap.vue
b/src/views/dashboard/related/topology/service/ServiceMap.vue
index b4eb5f83..111f2380 100644
--- a/src/views/dashboard/related/topology/service/ServiceMap.vue
+++ b/src/views/dashboard/related/topology/service/ServiceMap.vue
@@ -124,11 +124,17 @@ limitations under the License. -->
left: operationsPos.x + 5 + 'px',
}"
>
- <span v-for="(item, index) of items" :key="index"
@click="item.func(item.dashboard)">
+ <span v-for="(item, index) of items" :key="index"
@click="item.func(item)">
{{ item.title }}
</span>
</div>
- <el-dialog v-model="hierarchyRelated" :destroy-on-close="true"
@closed="hierarchyRelated = false" width="640px">
+ <el-dialog
+ v-model="hierarchyRelated"
+ :title="getHierarchyTitle()"
+ :destroy-on-close="true"
+ @closed="hierarchyRelated = false"
+ width="640px"
+ >
<div class="hierarchy-related">
<hierarchy-map :config="config" />
</div>
@@ -160,6 +166,7 @@ limitations under the License. -->
import { layout, computeLevels, changeNode } from
"../components/utils/layout";
import zoom from "@/views/dashboard/related/components/utils/zoom";
import { useQueryTopologyExpressionsProcessor } from
"@/hooks/useExpressionsProcessor";
+ import { ConfigFieldTypes } from "@/views/dashboard/data";
/*global Nullable, defineProps */
const props = defineProps({
config: {
@@ -268,6 +275,20 @@ limitations under the License. -->
currentNode.value = null;
}
+ function getHierarchyTitle() {
+ if (!currentNode.value) {
+ return;
+ }
+ if (currentNode.value.layers.includes(dashboardStore.layerId)) {
+ return `${dashboardStore.layerId} --> ${currentNode.value.name}`;
+ }
+ const layer = currentNode.value.layers.filter((d: string) => d !==
dashboardStore.layerId);
+ if (layer.length) {
+ return `${layer[0]} --> ${currentNode.value.name}`;
+ }
+ return "";
+ }
+
async function initLegendMetrics() {
if (!topologyStore.nodes.length) {
return;
@@ -410,19 +431,15 @@ limitations under the License. -->
topologyStore.setLink(null);
operationsPos.x = event.offsetX;
operationsPos.y = event.offsetY;
- if (d.layer === String(dashboardStore.layerId)) {
+ if (d.layers.includes(dashboardStore.layerId)) {
setNodeTools(settings.value.nodeDashboard);
return;
}
- items.value = [
- { id: "hierarchyServices", title: "Hierarchy Services", func:
handleHierarchyRelatedServices },
- { id: "inspect", title: "Inspect", func: handleInspect },
- { id: "alerting", title: "Alerting", func: handleGoAlerting },
- ];
+ initNodeMenus();
}
function handleLinkClick(event: MouseEvent, d: Call) {
event.stopPropagation();
- if (d.sourceObj.layer !== dashboardStore.layerId || d.targetObj.layer !==
dashboardStore.layerId) {
+ if (!d.sourceObj.layers.includes(dashboardStore.layerId) ||
!d.targetObj.layers.includes(dashboardStore.layerId)) {
return;
}
topologyStore.setNode(null);
@@ -462,25 +479,34 @@ limitations under the License. -->
topologyStore.setNode(null);
topologyStore.setLink(null);
}
- function handleGoEndpoint(name: string) {
+ function handleGoEndpoint(params: { dashboard: string }) {
+ if (!params.dashboard) {
+ return;
+ }
const origin = dashboardStore.entity;
- const path =
`/dashboard/${dashboardStore.layerId}/${EntityType[2].value}/${topologyStore.node.id}/${name}`;
+ const path =
`/dashboard/${dashboardStore.layerId}/${EntityType[2].value}/${topologyStore.node.id}/${params.dashboard}`;
const routeUrl = router.resolve({ path });
window.open(routeUrl.href, "_blank");
dashboardStore.setEntity(origin);
}
- function handleGoInstance(name: string) {
+ function handleGoInstance(params: { dashboard: string }) {
+ if (!params.dashboard) {
+ return;
+ }
const origin = dashboardStore.entity;
- const path =
`/dashboard/${dashboardStore.layerId}/${EntityType[3].value}/${topologyStore.node.id}/${name}`;
+ const path =
`/dashboard/${dashboardStore.layerId}/${EntityType[3].value}/${topologyStore.node.id}/${params.dashboard}`;
const routeUrl = router.resolve({ path });
window.open(routeUrl.href, "_blank");
dashboardStore.setEntity(origin);
}
- function handleGoDashboard(name: string) {
+ function handleGoDashboard(params: { dashboard: string }) {
+ if (!params.dashboard) {
+ return;
+ }
const origin = dashboardStore.entity;
- const path =
`/dashboard/${dashboardStore.layerId}/${EntityType[0].value}/${topologyStore.node.id}/${name}`;
+ const path =
`/dashboard/${dashboardStore.layerId}/${EntityType[0].value}/${topologyStore.node.id}/${params.dashboard}`;
const routeUrl = router.resolve({ path });
window.open(routeUrl.href, "_blank");
@@ -492,6 +518,28 @@ limitations under the License. -->
window.open(routeUrl.href, "_blank");
}
+ function handleGoLayerDashboard(param: { id: string }) {
+ if (!(param.id && currentNode.value)) {
+ return;
+ }
+ const origin = dashboardStore.entity;
+ const { dashboard } = getDashboard(
+ {
+ layer: param.id,
+ entity: EntityType[0].value,
+ },
+ ConfigFieldTypes.ISDEFAULT,
+ );
+ if (!dashboard) {
+ return ElMessage.info("No Dashboard");
+ }
+
+ const path =
`/dashboard/${param.id}/${EntityType[0].value}/${currentNode.value.id}/${dashboard.name}`;
+ const routeUrl = router.resolve({ path });
+
+ window.open(routeUrl.href, "_blank");
+ dashboardStore.setEntity(origin);
+ }
async function backToTopology() {
loading.value = true;
await freshNodes();
@@ -520,12 +568,26 @@ limitations under the License. -->
settings.value = config;
setNodeTools(config.nodeDashboard);
}
- function setNodeTools(nodeDashboard: any) {
+ function initNodeMenus() {
items.value = [
{ id: "hierarchyServices", title: "Hierarchy Services", func:
handleHierarchyRelatedServices },
{ id: "inspect", title: "Inspect", func: handleInspect },
{ id: "alerting", title: "Alerting", func: handleGoAlerting },
];
+ if (!currentNode.value) {
+ return;
+ }
+ const diffLayers = currentNode.value.layers.filter((l: string) => l !==
dashboardStore.layerId);
+ for (const l of diffLayers) {
+ items.value.push({
+ id: l,
+ title: `${l} Dashboard`,
+ func: handleGoLayerDashboard,
+ });
+ }
+ }
+ function setNodeTools(nodeDashboard: any) {
+ initNodeMenus();
if (!(nodeDashboard && nodeDashboard.length)) {
return;
}