From ccb4d78f6bfb298a4921f0952fec82afedf7cf0f Mon Sep 17 00:00:00 2001 From: Fine0830 Date: Tue, 30 Jan 2024 15:59:16 +0800 Subject: [PATCH] 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', }" > - + {{ item.title }} - + @@ -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; }