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 860af150 fix: enhance VNode logic and support multiple Trace IDs in 
span's ref (#369)
860af150 is described below

commit 860af150f71f8dd0a2cbf555c8f7bd97954c5e53
Author: Fine0830 <[email protected]>
AuthorDate: Mon Jan 29 23:09:00 2024 +0800

    fix: enhance VNode logic and support multiple Trace IDs in span's ref (#369)
---
 src/hooks/useDashboardsSession.ts                  |  5 +-
 src/store/modules/dashboard.ts                     |  1 -
 src/views/dashboard/related/trace/Filter.vue       | 10 ++-
 src/views/dashboard/related/trace/TraceList.vue    |  3 +-
 .../related/trace/components/D3Graph/Index.vue     | 87 ++++++++++++----------
 .../trace/components/D3Graph/SpanDetail.vue        | 37 ++++++++-
 6 files changed, 95 insertions(+), 48 deletions(-)

diff --git a/src/hooks/useDashboardsSession.ts 
b/src/hooks/useDashboardsSession.ts
index a97d7c33..3fc9d1af 100644
--- a/src/hooks/useDashboardsSession.ts
+++ b/src/hooks/useDashboardsSession.ts
@@ -24,7 +24,7 @@ export default function getDashboard(param?: { name?: string; 
layer: string; ent
   const dashboardStore = useDashboardStore();
   const opt = param || dashboardStore.currentDashboard;
   const list = JSON.parse(sessionStorage.getItem("dashboards") || "[]");
-  let dashboard;
+  let dashboard: Recordable;
   if (type === ConfigFieldTypes.NAME) {
     dashboard = list.find(
       (d: { name: string; layer: string; entity: string }) =>
@@ -62,6 +62,9 @@ export default function getDashboard(param?: { name?: string; 
layer: string; ent
       filters,
     };
     dashboardStore.setWidget(item);
+    if (widget.id === sourceId) {
+      return;
+    }
     const targetTabIndex = (widget.id || "").split("-");
     const sourceTabindex = (sourceId || "").split("-") || [];
     let container: Nullable<Element>;
diff --git a/src/store/modules/dashboard.ts b/src/store/modules/dashboard.ts
index c784acee..46f6cac3 100644
--- a/src/store/modules/dashboard.ts
+++ b/src/store/modules/dashboard.ts
@@ -24,7 +24,6 @@ import { useSelectorStore } from "@/store/modules/selectors";
 import { NewControl, TextConfig, TimeRangeConfig, ControlsTypes } from 
"../data";
 import type { AxiosResponse } from "axios";
 import { ElMessage } from "element-plus";
-import { useI18n } from "vue-i18n";
 import { EntityType, MetricModes, WidgetType } from "@/views/dashboard/data";
 interface DashboardState {
   showConfig: boolean;
diff --git a/src/views/dashboard/related/trace/Filter.vue 
b/src/views/dashboard/related/trace/Filter.vue
index b9eeb38f..0ca285a1 100644
--- a/src/views/dashboard/related/trace/Filter.vue
+++ b/src/views/dashboard/related/trace/Filter.vue
@@ -150,7 +150,13 @@ limitations under the License. -->
       ElMessage.error(resp.errors);
       return;
     }
-    state.service = getCurrentNode(traceStore.services) || 
traceStore.services[0];
+    if (props.data.filters && props.data.filters.id === "0") {
+      state.service = { value: "", label: "" };
+      return;
+    } else {
+      state.service = getCurrentNode(traceStore.services) || 
traceStore.services[0];
+    }
+
     emits("get", state.service.id);
 
     getEndpoints(state.service.id);
@@ -198,7 +204,7 @@ limitations under the License. -->
     if (props.data.filters && props.data.filters.id) {
       param = {
         ...param,
-        serviceId: props.data.filters.id || undefined,
+        serviceId: props.data.filters.id && props.data.filters.id !== "0" ? 
props.data.filters.id : undefined,
         endpointId: state.endpoint.id || undefined,
         serviceInstanceId: state.instance.id || undefined,
       };
diff --git a/src/views/dashboard/related/trace/TraceList.vue 
b/src/views/dashboard/related/trace/TraceList.vue
index 6b2ca76a..ba2991a8 100644
--- a/src/views/dashboard/related/trace/TraceList.vue
+++ b/src/views/dashboard/related/trace/TraceList.vue
@@ -227,7 +227,8 @@ limitations under the License. -->
 
   .no-data {
     padding-top: 50px;
-    width: 100%;
+    width: 280px;
     text-align: center;
+    height: 100px;
   }
 </style>
diff --git a/src/views/dashboard/related/trace/components/D3Graph/Index.vue 
b/src/views/dashboard/related/trace/components/D3Graph/Index.vue
index c96c04b7..ff4705e7 100644
--- a/src/views/dashboard/related/trace/components/D3Graph/Index.vue
+++ b/src/views/dashboard/related/trace/components/D3Graph/Index.vue
@@ -139,28 +139,61 @@ limitations under the License. -->
     }
     segmentHeaders.forEach((span: Span) => {
       if (span.refs.length) {
+        let exit = 0;
         span.refs.forEach((ref) => {
-          const index = props.data.findIndex(
+          const i = props.data.findIndex(
             (i: Recordable) => ref.parentSegmentId === i.segmentId && 
ref.parentSpanId === i.spanId,
           );
-          if (index === -1) {
-            // create a known broken node.
-            const i = ref.parentSpanId;
-            const fixSpanKeyContent = {
+          if (i > -1) {
+            exit = 1;
+          }
+        });
+
+        if (!exit) {
+          const ref = span.refs[0];
+          // create a known broken node.
+          const i = ref.parentSpanId;
+          const fixSpanKeyContent = {
+            traceId: ref.traceId,
+            segmentId: ref.parentSegmentId,
+            spanId: i,
+            parentSpanId: i > -1 ? 0 : -1,
+          };
+          if (!_.find(fixSpans, fixSpanKeyContent)) {
+            fixSpans.push({
+              ...fixSpanKeyContent,
+              refs: [],
+              endpointName: `VNode: ${ref.parentSegmentId}`,
+              serviceCode: "VirtualNode",
+              type: `[Broken] ${ref.type}`,
+              peer: "",
+              component: `VirtualNode: #${i}`,
+              isError: true,
+              isBroken: true,
+              layer: "Broken",
+              tags: [],
+              logs: [],
+              startTime: 0,
+              endTime: 0,
+            });
+          }
+          // if root broken node is not exist, create a root broken node.
+          if (fixSpanKeyContent.parentSpanId > -1) {
+            const fixRootSpanKeyContent = {
               traceId: ref.traceId,
               segmentId: ref.parentSegmentId,
-              spanId: i,
-              parentSpanId: i > -1 ? 0 : -1,
+              spanId: 0,
+              parentSpanId: -1,
             };
-            if (!_.find(fixSpans, fixSpanKeyContent)) {
+            if (!_.find(fixSpans, fixRootSpanKeyContent)) {
               fixSpans.push({
-                ...fixSpanKeyContent,
+                ...fixRootSpanKeyContent,
                 refs: [],
                 endpointName: `VNode: ${ref.parentSegmentId}`,
                 serviceCode: "VirtualNode",
                 type: `[Broken] ${ref.type}`,
                 peer: "",
-                component: `VirtualNode: #${i}`,
+                component: `VirtualNode: #0`,
                 isError: true,
                 isBroken: true,
                 layer: "Broken",
@@ -170,44 +203,16 @@ limitations under the License. -->
                 endTime: 0,
               });
             }
-            // if root broken node is not exist, create a root broken node.
-            if (fixSpanKeyContent.parentSpanId > -1) {
-              const fixRootSpanKeyContent = {
-                traceId: ref.traceId,
-                segmentId: ref.parentSegmentId,
-                spanId: 0,
-                parentSpanId: -1,
-              };
-              if (!_.find(fixSpans, fixRootSpanKeyContent)) {
-                fixSpans.push({
-                  ...fixRootSpanKeyContent,
-                  refs: [],
-                  endpointName: `VNode: ${ref.parentSegmentId}`,
-                  serviceCode: "VirtualNode",
-                  type: `[Broken] ${ref.type}`,
-                  peer: "",
-                  component: `VirtualNode: #0`,
-                  isError: true,
-                  isBroken: true,
-                  layer: "Broken",
-                  tags: [],
-                  logs: [],
-                  startTime: 0,
-                  endTime: 0,
-                });
-              }
-            }
           }
-        });
+        }
       }
     });
     [...fixSpans, ...props.data].forEach((i) => {
       i.label = i.endpointName || "no operation name";
       i.children = [];
-      if (segmentGroup[i.segmentId] === undefined) {
+      if (!segmentGroup[i.segmentId]) {
         segmentIdGroup.push(i.segmentId);
-        segmentGroup[i.segmentId] = [];
-        segmentGroup[i.segmentId].push(i);
+        segmentGroup[i.segmentId] = [i];
       } else {
         segmentGroup[i.segmentId].push(i);
       }
diff --git 
a/src/views/dashboard/related/trace/components/D3Graph/SpanDetail.vue 
b/src/views/dashboard/related/trace/components/D3Graph/SpanDetail.vue
index a9d54711..eebdd416 100644
--- a/src/views/dashboard/related/trace/components/D3Graph/SpanDetail.vue
+++ b/src/views/dashboard/related/trace/components/D3Graph/SpanDetail.vue
@@ -42,6 +42,12 @@ limitations under the License. -->
       <span class="g-sm-4 grey">{{ t("isError") }}:</span>
       <span class="g-sm-8 wba">{{ currentSpan.isError }}</span>
     </div>
+    <h5 class="mb-10" v-if="diffRefs.length"> {{ t("traceID") }}. </h5>
+    <div class="mb-10 clear item" v-for="item in diffRefs" :key="item.traceId">
+      <span class="g-sm-12 wba cp link" @click="viewRelateTrace(item)">
+        {{ item.traceId }}
+      </span>
+    </div>
     <h5 class="mb-10" v-if="currentSpan.tags && currentSpan.tags.length"> {{ 
t("tags") }}. </h5>
     <div class="mb-10 clear item" v-for="i in currentSpan.tags" :key="i.key">
       <span class="g-sm-4 grey">{{ i.key }}:</span>
@@ -127,7 +133,7 @@ limitations under the License. -->
   </el-dialog>
 </template>
 <script lang="ts" setup>
-  import { ref, computed, onMounted } from "vue";
+  import { ref, computed, onMounted, inject } from "vue";
   import { useI18n } from "vue-i18n";
   import type { PropType } from "vue";
   import dayjs from "dayjs";
@@ -138,14 +144,20 @@ limitations under the License. -->
   import { useTraceStore } from "@/store/modules/trace";
   import LogTable from "@/views/dashboard/related/log/LogTable/Index.vue";
   import type { SpanAttachedEvent } from "@/types/trace";
+  import getDashboard from "@/hooks/useDashboardsSession";
+  import { useDashboardStore } from "@/store/modules/dashboard";
+  import { WidgetType } from "@/views/dashboard/data";
+  import type { LayoutConfig } from "@/types/dashboard";
 
   /*global defineProps, Nullable, Recordable */
   const props = defineProps({
     currentSpan: { type: Object as PropType<Recordable>, default: () => ({}) },
     traceId: { type: String, default: "" },
   });
+  const options: Recordable<LayoutConfig> = inject("options") || {};
   const { t } = useI18n();
   const traceStore = useTraceStore();
+  const dashboardStore = useDashboardStore();
   const pageNum = ref<number>(1);
   const showRelatedLogs = ref<boolean>(false);
   const showEventDetail = ref<boolean>(false);
@@ -154,6 +166,9 @@ limitations under the License. -->
   const total = computed(() =>
     traceStore.traceList.length === pageSize ? pageSize * pageNum.value + 1 : 
pageSize * pageNum.value,
   );
+  const diffRefs = computed(() =>
+    props.currentSpan.refs.filter((d: Recordable) => d.traceId !== 
props.currentSpan.traceId),
+  );
   const tree = ref<any>(null);
   const eventGraph = ref<Nullable<HTMLDivElement>>(null);
   const visDate = (date: number, pattern = "YYYY-MM-DD HH:mm:ss:SSS") => 
dayjs(date).format(pattern);
@@ -217,6 +232,19 @@ limitations under the License. -->
     tree.value.draw();
   }
 
+  function viewRelateTrace(item: Recordable) {
+    const { associationWidget } = 
getDashboard(dashboardStore.currentDashboard);
+    associationWidget(
+      (options.id as any) || "",
+      {
+        sourceId: options.id || "",
+        traceId: item.traceId || "",
+        id: "0",
+      },
+      WidgetType.Trace,
+    );
+  }
+
   function selectEvent(i: any) {
     currentEvent.value = i.data;
     showEventDetail.value = true;
@@ -259,7 +287,12 @@ limitations under the License. -->
     cursor: pointer;
   }
 
+  .link,
   .link-hover:hover {
-    color: #448dfe;
+    color: var(--el-color-primary);
+  }
+
+  .link {
+    text-decoration: underline;
   }
 </style>

Reply via email to