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 <fanxue0...@gmail.com>
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;
     }

Reply via email to