This is an automated email from the ASF dual-hosted git repository.

qiuxiafan 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 1377703  feat: Implement adding controls in Tabs (#21)
1377703 is described below

commit 1377703185c83bd3bf530efdc169e5d017905c14
Author: Fine0830 <[email protected]>
AuthorDate: Fri Mar 4 15:35:29 2022 +0800

    feat: Implement adding controls in Tabs (#21)
---
 src/components/Icon.vue                            |  13 +-
 src/locales/lang/en.ts                             |   1 +
 src/locales/lang/zh.ts                             |   1 +
 src/router/index.ts                                |   3 +-
 src/store/modules/dashboard.ts                     | 105 ++++++--
 src/types/dashboard.ts                             |   1 +
 src/views/dashboard/Edit.vue                       |   1 +
 src/views/dashboard/controls/Tab.vue               | 267 +++++++++++++--------
 src/views/dashboard/controls/Widget.vue            |   8 +-
 src/views/dashboard/data.ts                        |   6 +-
 src/views/dashboard/panel/Layout.vue               |   1 +
 src/views/dashboard/panel/Tool.vue                 |  50 +++-
 src/views/dashboard/related/profile/Content.vue    |   9 +-
 .../related/profile/components/SpanTree.vue        |  28 ++-
 .../related/trace/components/Table/TableItem.vue   |   3 +-
 15 files changed, 347 insertions(+), 150 deletions(-)

diff --git a/src/components/Icon.vue b/src/components/Icon.vue
index 10becda..fc6a0ce 100644
--- a/src/components/Icon.vue
+++ b/src/components/Icon.vue
@@ -21,7 +21,7 @@ limitations under the License. -->
       lg: size === 'lg',
       xl: size === 'xl',
       logo: size === 'logo',
-      loading: loading,
+      loading,
     }"
   >
     <use :xlink:href="`#${iconName}`"></use>
@@ -73,4 +73,15 @@ defineProps({
     width: 30px;
   }
 }
+@keyframes loading {
+  0% {
+    -webkit-transform: rotate(0deg);
+    transform: rotate(0deg);
+  }
+
+  to {
+    -webkit-transform: rotate(1turn);
+    transform: rotate(1turn);
+  }
+}
 </style>
diff --git a/src/locales/lang/en.ts b/src/locales/lang/en.ts
index 29feac0..b364919 100644
--- a/src/locales/lang/en.ts
+++ b/src/locales/lang/en.ts
@@ -95,6 +95,7 @@ const msg = {
   topChildren: "Top 5 of children",
   taskList: "Task List",
   sampledTraces: "Sampled Traces",
+  editTab: "Enable editing tab names",
   hourTip: "Select Hour",
   minuteTip: "Select Minute",
   secondTip: "Select Second",
diff --git a/src/locales/lang/zh.ts b/src/locales/lang/zh.ts
index 5764eee..d60322c 100644
--- a/src/locales/lang/zh.ts
+++ b/src/locales/lang/zh.ts
@@ -95,6 +95,7 @@ const msg = {
   showDepth: "展示深度选择器",
   taskList: "任务列表",
   sampledTraces: "采样的追踪",
+  editTab: "开启编辑Tab的名称",
   hourTip: "选择小时",
   minuteTip: "选择分钟",
   secondTip: "选择秒数",
diff --git a/src/router/index.ts b/src/router/index.ts
index 80068c3..4ab9d19 100644
--- a/src/router/index.ts
+++ b/src/router/index.ts
@@ -26,7 +26,6 @@ import { routesEvent } from "./event";
 import { routesAlert } from "./alert";
 import { routesSetting } from "./setting";
 import { routesAlarm } from "./alarm";
-import { useTimeoutFn } from "@/hooks/useTimeout";
 
 const routes: Array<RouteRecordRaw> = [
   ...routesGen,
@@ -52,7 +51,7 @@ router.beforeEach((to, from, next) => {
   // const token = window.localStorage.getItem("skywalking-authority");
   if ((window as any).axiosCancel.length !== 0) {
     for (const func of (window as any).axiosCancel) {
-      useTimeoutFn(func(), 0);
+      setTimeout(func(), 0);
     }
     (window as any).axiosCancel = [];
   }
diff --git a/src/store/modules/dashboard.ts b/src/store/modules/dashboard.ts
index 24a19e3..ad15f25 100644
--- a/src/store/modules/dashboard.ts
+++ b/src/store/modules/dashboard.ts
@@ -43,6 +43,7 @@ interface DashboardState {
   durationTime: Duration;
   selectorStore: any;
   showTopology: boolean;
+  currentTabItems: LayoutConfig[];
 }
 
 export const dashboardStore = defineStore({
@@ -57,6 +58,7 @@ export const dashboardStore = defineStore({
     durationTime: useAppStoreWithOut().durationTime,
     selectorStore: useSelectorStore(),
     showTopology: false,
+    currentTabItems: [],
   }),
   actions: {
     setLayout(data: LayoutConfig[]) {
@@ -71,7 +73,8 @@ export const dashboardStore = defineStore({
         metrics: [""],
       };
       if (type === "Tab") {
-        newItem.h = 24;
+        newItem.h = 36;
+        newItem.activedTabIndex = 0;
         newItem.children = [
           {
             name: "Tab1",
@@ -96,14 +99,15 @@ export const dashboardStore = defineStore({
         };
       }
       if (type === "Trace" || type === "Profile") {
-        newItem.h = 36;
+        newItem.h = 24;
       }
+      this.activedGridItem = newItem.i;
+      this.selectedGrid = newItem;
       this.layout = this.layout.map((d: LayoutConfig) => {
         d.y = d.y + newItem.h;
         return d;
       });
       this.layout.push(newItem);
-      this.activedGridItem = newItem.i;
     },
     addTabItem(item: LayoutConfig) {
       const idx = this.layout.findIndex((d: LayoutConfig) => d.i === item.i);
@@ -117,7 +121,7 @@ export const dashboardStore = defineStore({
       };
       this.layout[idx].children?.push(i);
     },
-    addTabWidget(tabIndex: number) {
+    addTabControls(type: string) {
       const activedGridItem = this.activedGridItem.split("-")[0];
       const idx = this.layout.findIndex(
         (d: LayoutConfig) => d.i === activedGridItem
@@ -125,37 +129,91 @@ export const dashboardStore = defineStore({
       if (idx < 0) {
         return;
       }
+      const tabIndex = this.layout[idx].activedTabIndex;
       const { children } = this.layout[idx].children[tabIndex];
-      const newWidget = {
-        x: 0,
-        y: 0,
-        w: 24,
-        h: 12,
+      const newItem: LayoutConfig = {
+        ...NewControl,
         i: String(children.length),
-        type: "Widget",
-        widget: {
-          title: "Title",
-        },
-        graph: {},
-        standard: {},
+        type,
+        metricTypes: [""],
+        metrics: [""],
       };
+      if (type === "Topology") {
+        newItem.w = 4;
+        newItem.h = 6;
+        newItem.graph = {
+          fontColor: "white",
+          backgroundColor: "green",
+          iconTheme: true,
+          content: "Topology",
+          fontSize: 18,
+          showDepth: true,
+        };
+      }
+      if (type === "Trace" || type === "Profile") {
+        newItem.h = 24;
+      }
       if (this.layout[idx].children) {
         const items = children.map((d: LayoutConfig) => {
-          d.y = d.y + newWidget.h;
+          d.y = d.y + newItem.h;
           return d;
         });
-        items.push(newWidget);
+        items.push(newItem);
         this.layout[idx].children[tabIndex].children = items;
+        this.currentTabItems = items;
       }
     },
     activeGridItem(index: string) {
       this.activedGridItem = index;
     },
+    setActiveTabIndex(index: number) {
+      const idx = this.layout.findIndex(
+        (d: LayoutConfig) => d.i === this.activedGridItem
+      );
+      if (idx < 0) {
+        return;
+      }
+      this.layout[idx].activedTabIndex = index;
+    },
+    setCurrentTabItems(items: LayoutConfig[]) {
+      this.currentTabItems = items;
+    },
+    removeTab(item: LayoutConfig) {
+      if (this.selectedGrid && this.selectedGrid.i === item.i) {
+        this.selectedGrid = null;
+      }
+      this.layout = this.layout.filter((d: LayoutConfig) => d.i !== item.i);
+    },
     removeControls(item: LayoutConfig) {
+      const actived = this.activedGridItem.split("-");
+      const index = this.layout.findIndex(
+        (d: LayoutConfig) => actived[0] === d.i
+      );
+
+      if (this.selectedGrid && this.selectedGrid.i === item.i) {
+        this.selectedGrid = null;
+      }
+      if (actived.length === 3) {
+        const tabIndex = Number(actived[1]);
+        const itemIndex = this.layout[index].children[
+          tabIndex
+        ].children.findIndex((d: LayoutConfig) => actived[2] === d.i);
+
+        this.layout[index].children[tabIndex].children.splice(itemIndex, 1);
+        
this.setCurrentTabItems(this.layout[index].children[tabIndex].children);
+        return;
+      }
       this.layout = this.layout.filter((d: LayoutConfig) => d.i !== item.i);
     },
     removeTabItem(item: LayoutConfig, index: number) {
       const idx = this.layout.findIndex((d: LayoutConfig) => d.i === item.i);
+      if (this.selectedGrid) {
+        for (const item of this.layout[idx].children[index].children) {
+          if (this.selectedGrid.i === item.i) {
+            this.selectedGrid = null;
+          }
+        }
+      }
       if (this.layout[idx].children) {
         this.layout[idx].children?.splice(index, 1);
       }
@@ -204,11 +262,18 @@ export const dashboardStore = defineStore({
       );
 
       if (actived.length === 3) {
-        this.layout[index].children[actived[1]].children[actived[2]] = {
-          ...this.layout[index],
+        const tabIndex = Number(actived[1]);
+        const itemIndex = this.layout[index].children[
+          tabIndex
+        ].children.findIndex((d: LayoutConfig) => actived[2] === d.i);
+
+        this.layout[index].children[tabIndex].children[itemIndex] = {
+          ...this.layout[index].children[tabIndex].children[itemIndex],
           ...param,
         };
-        this.selectedGrid = this.layout[index];
+        this.selectedGrid =
+          this.layout[index].children[tabIndex].children[itemIndex];
+        
this.setCurrentTabItems(this.layout[index].children[tabIndex].children);
         return;
       }
       this.layout[index] = {
diff --git a/src/types/dashboard.ts b/src/types/dashboard.ts
index b8c0544..c0ec3d8 100644
--- a/src/types/dashboard.ts
+++ b/src/types/dashboard.ts
@@ -27,6 +27,7 @@ export interface LayoutConfig {
   type: string;
   metricTypes: string[];
   children?: any;
+  activedTabIndex?: number;
 }
 
 export interface WidgetConfig {
diff --git a/src/views/dashboard/Edit.vue b/src/views/dashboard/Edit.vue
index 075b0ec..d6b3e24 100644
--- a/src/views/dashboard/Edit.vue
+++ b/src/views/dashboard/Edit.vue
@@ -75,6 +75,7 @@ function handleClick(e: any) {
   e.stopPropagation();
   if (e.target.className === "ds-main") {
     dashboardStore.activeGridItem("");
+    dashboardStore.selectWidget(null);
   }
 }
 </script>
diff --git a/src/views/dashboard/controls/Tab.vue 
b/src/views/dashboard/controls/Tab.vue
index 5c31a87..20c106d 100644
--- a/src/views/dashboard/controls/Tab.vue
+++ b/src/views/dashboard/controls/Tab.vue
@@ -33,38 +33,62 @@ limitations under the License. -->
           v-show="activeTabIndex === idx"
           size="sm"
           iconName="cancel"
-          @click="deleteTabItem(idx)"
+          @click="deleteTabItem($event, idx)"
         />
       </span>
       <span class="tab-icons">
-        <el-tooltip effect="dark" content="Add tab items" placement="bottom">
+        <el-tooltip content="Add tab items" placement="bottom">
           <i @click="addTabItem">
             <Icon size="middle" iconName="add" />
           </i>
         </el-tooltip>
-        <el-tooltip effect="dark" content="Add widgets" placement="bottom">
-          <i @click="addTabWidget">
-            <Icon size="middle" iconName="playlist_add" />
-          </i>
-        </el-tooltip>
       </span>
     </div>
     <div class="operations">
-      <Icon size="sm" iconName="clearclose" @click="removeTab" />
+      <el-popover
+        placement="bottom"
+        trigger="click"
+        :width="200"
+        v-model:visible="showTools"
+      >
+        <template #reference>
+          <span>
+            <Icon
+              iconName="ellipsis_v"
+              size="middle"
+              class="operation"
+              @click="showTools = true"
+            />
+          </span>
+        </template>
+        <div
+          class="tools"
+          @click="
+            canEditTabName = true;
+            showTools = false;
+          "
+        >
+          <span class="edit-tab">{{ t("editTab") }}</span>
+        </div>
+        <div class="tools" @click="removeTab">
+          <span>{{ t("delete") }}</span>
+        </div>
+      </el-popover>
     </div>
   </div>
-  <div class="tab-layout">
+  <div class="tab-layout" @click="handleClick">
     <grid-layout
-      v-if="state.layout.length"
-      v-model:layout="state.layout"
+      v-if="dashboardStore.currentTabItems.length"
+      v-model:layout="dashboardStore.currentTabItems"
       :col-num="24"
       :row-height="10"
       :is-draggable="true"
       :is-resizable="true"
+      :responsive="true"
       @layout-updated="layoutUpdatedEvent"
     >
       <grid-item
-        v-for="item in state.layout"
+        v-for="item in dashboardStore.currentTabItems"
         :x="item.x"
         :y="item.y"
         :w="item.w"
@@ -74,103 +98,147 @@ limitations under the License. -->
         @click="clickTabGrid($event, item)"
         :class="{ active: activeTabWidget === item.i }"
       >
-        <Widget
+        <component
+          :is="item.type"
           :data="item"
           :activeIndex="`${data.i}-${activeTabIndex}-${item.i}`"
+          :needQuery="needQuery"
         />
       </grid-item>
     </grid-layout>
     <div class="no-data-tips" v-else>Please add widgets.</div>
   </div>
 </template>
-<script lang="ts" setup>
-import { ref, watch, reactive } from "vue";
+<script lang="ts">
+import { ref, watch, defineComponent, toRefs } from "vue";
+import { useI18n } from "vue-i18n";
 import type { PropType } from "vue";
-import Widget from "./Widget.vue";
 import { LayoutConfig } from "@/types/dashboard";
 import { useDashboardStore } from "@/store/modules/dashboard";
-/*global defineProps */
-const props = defineProps({
+import Topology from "./Topology.vue";
+import Widget from "./Widget.vue";
+import Trace from "./Trace.vue";
+import Profile from "./Profile.vue";
+
+const props = {
   data: {
     type: Object as PropType<LayoutConfig>,
     default: () => ({ children: [] }),
   },
   active: { type: Boolean, default: false },
-});
-const dashboardStore = useDashboardStore();
-const activeTabIndex = ref<number>(0);
-const activeTabWidget = ref<string>("0");
-const editTabIndex = ref<number>(NaN); // edit tab item name
-const state = reactive<{
-  layout: LayoutConfig[];
-}>({
-  layout:
-    
dashboardStore.layout[props.data.i].children[activeTabIndex.value].children,
-});
-
-function layoutUpdatedEvent(newLayout: LayoutConfig[]) {
-  state.layout = newLayout;
-}
-function clickTabs(e: Event, idx: number) {
-  e.stopPropagation();
-  activeTabIndex.value = idx;
-}
-function removeTab() {
-  dashboardStore.removeControls(props.data);
-}
-function deleteTabItem(idx: number) {
-  dashboardStore.removeTabItem(props.data, idx);
-}
-function addTabItem() {
-  dashboardStore.addTabItem(props.data);
-}
-function editTabName(el: Event, index: number) {
-  el.stopPropagation();
-  editTabIndex.value = index;
-}
-function handleClick(el: any) {
-  if (el.target.className === "tab-name") {
-    return;
-  }
-  editTabIndex.value = NaN;
-}
-function addTabWidget(e: Event) {
-  e.stopPropagation();
-  activeTabWidget.value = String(state.layout.length);
-  dashboardStore.addTabWidget(activeTabIndex.value);
-  dashboardStore.activeGridItem(
-    `${props.data.i}-${activeTabIndex.value}-${activeTabWidget.value}`
-  );
-}
-function clickTabGrid(e: Event, item: LayoutConfig) {
-  e.stopPropagation();
-  activeTabWidget.value = item.i;
-  dashboardStore.activeGridItem(
-    `${props.data.i}-${activeTabIndex.value}-${item.i}`
-  );
-}
-document.body.addEventListener("click", handleClick, false);
+};
+export default defineComponent({
+  name: "Tab",
+  components: { Topology, Widget, Trace, Profile },
+  props,
+  setup(props) {
+    const { t } = useI18n();
+    const dashboardStore = useDashboardStore();
+    const activeTabIndex = ref<number>(0);
+    const activeTabWidget = ref<string>("");
+    const editTabIndex = ref<number>(NaN); // edit tab item name
+    const canEditTabName = ref<boolean>(false);
+    const needQuery = ref<boolean>(false);
+    const showTools = ref<boolean>(false);
+    const l = dashboardStore.layout.findIndex(
+      (d: LayoutConfig) => d.i === props.data.i
+    );
+    dashboardStore.setCurrentTabItems(
+      dashboardStore.layout[l].children[activeTabIndex.value].children
+    );
 
-const children = ref(
-  dashboardStore.layout[props.data.i].children[activeTabIndex.value].children
-);
-watch(
-  () => children.value,
-  (data) => {
-    state.layout = data;
-  }
-);
-watch(
-  () => dashboardStore.activedGridItem,
-  (data) => {
-    const i = data.split("-");
-    if (i[0] === props.data.i && activeTabIndex.value === Number(i[1])) {
-      activeTabWidget.value = i[2];
-    } else {
-      activeTabWidget.value = "";
+    function clickTabs(e: Event, idx: number) {
+      e.stopPropagation();
+      activeTabIndex.value = idx;
+      dashboardStore.activeGridItem(props.data.i);
+      dashboardStore.selectWidget(props.data);
+      dashboardStore.setActiveTabIndex(idx);
+      const l = dashboardStore.layout.findIndex(
+        (d: LayoutConfig) => d.i === props.data.i
+      );
+      dashboardStore.setCurrentTabItems(
+        dashboardStore.layout[l].children[activeTabIndex.value].children
+      );
+      needQuery.value = true;
     }
-  }
-);
+    function removeTab(e: Event) {
+      e.stopPropagation();
+      dashboardStore.removeTab(props.data);
+    }
+    function deleteTabItem(e: Event, idx: number) {
+      e.stopPropagation();
+      dashboardStore.removeTabItem(props.data, idx);
+    }
+    function addTabItem() {
+      dashboardStore.addTabItem(props.data);
+    }
+    function editTabName(el: Event, index: number) {
+      if (!canEditTabName.value) {
+        editTabIndex.value = NaN;
+        return;
+      }
+      editTabIndex.value = index;
+    }
+    function handleClick(el: any) {
+      if (["tab-name", "edit-tab"].includes(el.target.className)) {
+        return;
+      }
+      canEditTabName.value = false;
+      editTabIndex.value = NaN;
+    }
+    function clickTabGrid(e: Event, item: LayoutConfig) {
+      e.stopPropagation();
+      activeTabWidget.value = item.i;
+      dashboardStore.activeGridItem(
+        `${props.data.i}-${activeTabIndex.value}-${item.i}`
+      );
+      handleClick(e);
+    }
+    function layoutUpdatedEvent() {
+      const l = dashboardStore.layout.findIndex(
+        (d: LayoutConfig) => d.i === props.data.i
+      );
+      dashboardStore.setCurrentTabItems(
+        dashboardStore.layout[l].children[activeTabIndex.value].children
+      );
+    }
+    document.body.addEventListener("click", handleClick, false);
+    watch(
+      () => dashboardStore.activedGridItem,
+      (data) => {
+        if (!data) {
+          activeTabWidget.value = "";
+          return;
+        }
+        const i = data.split("-");
+        if (i[0] === props.data.i && activeTabIndex.value === Number(i[1])) {
+          activeTabWidget.value = i[2];
+        } else {
+          activeTabWidget.value = "";
+        }
+      }
+    );
+    return {
+      handleClick,
+      layoutUpdatedEvent,
+      clickTabGrid,
+      editTabName,
+      addTabItem,
+      deleteTabItem,
+      removeTab,
+      clickTabs,
+      ...toRefs(props),
+      activeTabWidget,
+      dashboardStore,
+      activeTabIndex,
+      editTabIndex,
+      needQuery,
+      canEditTabName,
+      showTools,
+      t,
+    };
+  },
+});
 </script>
 <style lang="scss" scoped>
 .tabs {
@@ -218,10 +286,6 @@ watch(
   }
 }
 
-.el-input__inner {
-  border: none !important;
-}
-
 .operations {
   color: #aaa;
   cursor: pointer;
@@ -263,4 +327,17 @@ watch(
   padding-top: 30px;
   color: #888;
 }
+
+.tools {
+  padding: 5px 0;
+  color: #999;
+  cursor: pointer;
+  position: relative;
+  text-align: center;
+
+  &:hover {
+    color: #409eff;
+    background-color: #eee;
+  }
+}
 </style>
diff --git a/src/views/dashboard/controls/Widget.vue 
b/src/views/dashboard/controls/Widget.vue
index 74ca377..56de472 100644
--- a/src/views/dashboard/controls/Widget.vue
+++ b/src/views/dashboard/controls/Widget.vue
@@ -77,6 +77,7 @@ const props = {
     default: () => ({ widget: {} }),
   },
   activeIndex: { type: String, default: "" },
+  needQuery: { type: Boolean, default: false },
 };
 export default defineComponent({
   name: "Widget",
@@ -93,7 +94,7 @@ export default defineComponent({
     const dashboardStore = useDashboardStore();
     const selectorStore = useSelectorStore();
 
-    if (dashboardStore.entity === EntityType[1].value) {
+    if (dashboardStore.entity === EntityType[1].value || props.needQuery) {
       queryMetrics();
     }
 
@@ -128,7 +129,10 @@ export default defineComponent({
     watch(
       () => [props.data.metricTypes, props.data.metrics],
       () => {
-        if (props.data.i !== dashboardStore.selectedGrid.i) {
+        if (
+          dashboardStore.selectedGrid &&
+          props.data.i !== dashboardStore.selectedGrid.i
+        ) {
           return;
         }
         if (TableChartTypes.includes(dashboardStore.selectedGrid.graph.type)) {
diff --git a/src/views/dashboard/data.ts b/src/views/dashboard/data.ts
index 17a186f..396de2c 100644
--- a/src/views/dashboard/data.ts
+++ b/src/views/dashboard/data.ts
@@ -165,9 +165,9 @@ export const SortOrder = [
 export const ToolIcons = [
   { name: "playlist_add", content: "Add Widget", id: "addWidget" },
   { name: "all_inbox", content: "Add Tab", id: "addTab" },
-  { name: "device_hub", content: "Add Topology", id: "topology" },
-  { name: "merge", content: "Add Trace", id: "trace" },
-  { name: "timeline", content: "Add Profile", id: "profile" },
+  { name: "device_hub", content: "Add Topology", id: "addTopology" },
+  { name: "merge", content: "Add Trace", id: "addTrace" },
+  { name: "timeline", content: "Add Profile", id: "addProfile" },
   // { name: "save_alt", content: "Export", id: "export" },
   // { name: "folder_open", content: "Import", id: "import" },
   // { name: "settings", content: "Settings", id: "settings" },
diff --git a/src/views/dashboard/panel/Layout.vue 
b/src/views/dashboard/panel/Layout.vue
index 72c9588..bc3938f 100644
--- a/src/views/dashboard/panel/Layout.vue
+++ b/src/views/dashboard/panel/Layout.vue
@@ -53,6 +53,7 @@ export default defineComponent({
     }
     function clickGrid(item: LayoutConfig) {
       dashboardStore.activeGridItem(item.i);
+      dashboardStore.selectWidget(item);
     }
     return {
       dashboardStore,
diff --git a/src/views/dashboard/panel/Tool.vue 
b/src/views/dashboard/panel/Tool.vue
index 7e5774a..b052257 100644
--- a/src/views/dashboard/panel/Tool.vue
+++ b/src/views/dashboard/panel/Tool.vue
@@ -107,7 +107,6 @@ import { EntityType, ToolIcons, hasTopology, TraceEntitys } 
from "../data";
 import { useSelectorStore } from "@/store/modules/selectors";
 import { ElMessage } from "element-plus";
 import { Option } from "@/types/app";
-import { Service } from "@/types/selector";
 
 const dashboardStore = useDashboardStore();
 const selectorStore = useSelectorStore();
@@ -260,7 +259,7 @@ async function getServices() {
   }
 }
 
-async function changeService(service: Service[]) {
+async function changeService(service: any) {
   if (service[0]) {
     states.currentService = service[0].value;
     selectorStore.setCurrentService(service[0]);
@@ -270,7 +269,7 @@ async function changeService(service: Service[]) {
   }
 }
 
-function changeDestService(service: Service[]) {
+function changeDestService(service: any) {
   if (service[0]) {
     states.currentDestService = service[0].value;
     selectorStore.setCurrentDestService(service[0]);
@@ -279,7 +278,7 @@ function changeDestService(service: Service[]) {
   }
 }
 
-function changePods(pod: Option[]) {
+function changePods(pod: any) {
   if (pod[0]) {
     selectorStore.setCurrentPod(pod[0]);
   } else {
@@ -288,20 +287,55 @@ function changePods(pod: Option[]) {
 }
 
 function clickIcons(t: { id: string; content: string; name: string }) {
-  switch (t.id) {
+  if (
+    dashboardStore.selectedGrid &&
+    dashboardStore.selectedGrid.type === "Tab"
+  ) {
+    setTabControls(t.id);
+    return;
+  }
+  if (dashboardStore.activedGridItem.split("-").length === 3) {
+    setTabControls(t.id);
+    return;
+  }
+  setControls(t.id);
+}
+
+function setTabControls(id: string) {
+  switch (id) {
+    case "addWidget":
+      dashboardStore.addTabControls("Widget");
+      break;
+    case "addTrace":
+      dashboardStore.addTabControls("Trace");
+      break;
+    case "addProfile":
+      dashboardStore.addTabControls("Profile");
+      break;
+    case "addTopology":
+      dashboardStore.addTabControls("Topology");
+      break;
+    default:
+      ElMessage.info("Don't support this control");
+      break;
+  }
+}
+
+function setControls(id: string) {
+  switch (id) {
     case "addWidget":
       dashboardStore.addControl("Widget");
       break;
     case "addTab":
       dashboardStore.addControl("Tab");
       break;
-    case "trace":
+    case "addTrace":
       dashboardStore.addControl("Trace");
       break;
-    case "profile":
+    case "addProfile":
       dashboardStore.addControl("Profile");
       break;
-    case "topology":
+    case "addTopology":
       dashboardStore.addControl("Topology");
       break;
     case "settings":
diff --git a/src/views/dashboard/related/profile/Content.vue 
b/src/views/dashboard/related/profile/Content.vue
index 4679ba6..18bd265 100644
--- a/src/views/dashboard/related/profile/Content.vue
+++ b/src/views/dashboard/related/profile/Content.vue
@@ -65,19 +65,16 @@ function loadTrees(l: boolean) {
 }
 
 .thread-stack {
-  padding: 5px 12px;
-  height: calc(50% - 50px);
+  padding: 5px;
+  height: calc(50% - 20px);
   overflow: auto;
   width: 100%;
 }
 
 .t-loading {
   text-align: center;
-  position: absolute;
   width: 100%;
-  height: 70px;
-  margin-top: 40px;
-  line-height: 88px;
   overflow: hidden;
+  height: calc(50% - 20px);
 }
 </style>
diff --git a/src/views/dashboard/related/profile/components/SpanTree.vue 
b/src/views/dashboard/related/profile/components/SpanTree.vue
index 63df51d..0913b7d 100644
--- a/src/views/dashboard/related/profile/components/SpanTree.vue
+++ b/src/views/dashboard/related/profile/components/SpanTree.vue
@@ -35,16 +35,18 @@ limitations under the License. -->
         {{ t("analyze") }}
       </el-button>
     </div>
-    <Table
-      :data="profileStore.segmentSpans"
-      :traceId="
-        profileStore.currentSegment.traceIds &&
-        profileStore.currentSegment.traceIds[0]
-      "
-      :showBtnDetail="true"
-      headerType="profile"
-      @select="selectSpan"
-    />
+    <div class="profile-table">
+      <Table
+        :data="profileStore.segmentSpans"
+        :traceId="
+          profileStore.currentSegment.traceIds &&
+          profileStore.currentSegment.traceIds[0]
+        "
+        :showBtnDetail="true"
+        headerType="profile"
+        @select="selectSpan"
+      />
+    </div>
   </div>
 </template>
 <script lang="ts" setup>
@@ -158,10 +160,14 @@ function updateTimeRange() {
   padding: 5px;
   flex-shrink: 0;
   height: 50%;
-  overflow: auto;
   width: 100%;
 }
 
+.profile-table {
+  height: calc(100% - 30px);
+  overflow: auto;
+}
+
 .profile-trace-detail-wrapper {
   padding: 5px 0;
   border-bottom: 1px solid rgba(0, 0, 0, 0.1);
diff --git a/src/views/dashboard/related/trace/components/Table/TableItem.vue 
b/src/views/dashboard/related/trace/components/Table/TableItem.vue
index 86c8f5d..7f032fd 100644
--- a/src/views/dashboard/related/trace/components/Table/TableItem.vue
+++ b/src/views/dashboard/related/trace/components/Table/TableItem.vue
@@ -136,7 +136,7 @@ limitations under the License. -->
 <script lang="ts">
 import dayjs from "dayjs";
 import { useI18n } from "vue-i18n";
-import { ref, watch, computed, defineComponent } from "vue";
+import { ref, computed, defineComponent } from "vue";
 import type { PropType } from "vue";
 import SpanDetail from "../D3Graph/SpanDetail.vue";
 
@@ -152,7 +152,6 @@ export default defineComponent({
   emits: ["select"],
   components: { SpanDetail },
   setup(props, { emit }) {
-    /* global Nullable */
     const displayChildren = ref<boolean>(true);
     const showDetail = ref<boolean>(false);
     const { t } = useI18n();

Reply via email to