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 f1e405f  feat: add switch to control dashboard mode (#31)
f1e405f is described below

commit f1e405fbb4fccef12b8157585da290c8818d7f03
Author: Fine0830 <[email protected]>
AuthorDate: Mon Mar 21 19:34:08 2022 +0800

    feat: add switch to control dashboard mode (#31)
---
 src/components/Icon.vue                            |  2 +-
 src/hooks/useDashboardsSession.ts                  | 32 ++++++++++++
 src/layout/Index.vue                               |  3 +-
 src/layout/components/SideBar.vue                  |  2 +-
 src/locales/lang/en.ts                             |  4 +-
 src/locales/lang/zh.ts                             |  2 +
 src/store/modules/dashboard.ts                     |  5 ++
 src/views/Layer.vue                                | 11 ++--
 src/views/dashboard/Edit.vue                       |  4 +-
 src/views/dashboard/List.vue                       | 25 +++++++--
 src/views/dashboard/controls/Log.vue               |  4 +-
 src/views/dashboard/controls/Profile.vue           |  5 +-
 src/views/dashboard/controls/Tab.vue               |  9 ++--
 src/views/dashboard/controls/Topology.vue          |  4 +-
 src/views/dashboard/controls/Trace.vue             | 11 ++--
 src/views/dashboard/controls/Widget.vue            |  6 +--
 src/views/dashboard/graphs/EndpointList.vue        | 26 +++++++---
 src/views/dashboard/graphs/InstanceList.vue        | 27 +++++++---
 src/views/dashboard/graphs/ServiceList.vue         | 26 +++++++---
 src/views/dashboard/panel/Tool.vue                 | 60 +++++++++++++++++-----
 .../related/topology/components/Graph.vue          | 45 ++++++++++++----
 .../related/topology/components/PodTopology.vue    | 18 ++++++-
 .../related/topology/components/Settings.vue       |  1 +
 23 files changed, 250 insertions(+), 82 deletions(-)

diff --git a/src/components/Icon.vue b/src/components/Icon.vue
index fc6a0ce..e780541 100644
--- a/src/components/Icon.vue
+++ b/src/components/Icon.vue
@@ -37,7 +37,7 @@ defineProps({
   loading: { type: Boolean, default: false },
 });
 </script>
-<style lang="scss" scope>
+<style lang="scss" scoped>
 .icon {
   width: 16px;
   height: 16px;
diff --git a/src/hooks/useDashboardsSession.ts 
b/src/hooks/useDashboardsSession.ts
new file mode 100644
index 0000000..bd3e1a5
--- /dev/null
+++ b/src/hooks/useDashboardsSession.ts
@@ -0,0 +1,32 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+export default function getDashboard(param: {
+  name: string;
+  layer: string;
+  entity: string;
+}) {
+  const list = JSON.parse(sessionStorage.getItem("dashboards") || "[]");
+  const dashboard = list.find(
+    (d: { name: string; layer: string; entity: string }) =>
+      d.name === param.name &&
+      d.entity === param.entity &&
+      d.layer === param.layer
+  );
+
+  return dashboard;
+}
diff --git a/src/layout/Index.vue b/src/layout/Index.vue
index 23b3571..906251c 100644
--- a/src/layout/Index.vue
+++ b/src/layout/Index.vue
@@ -24,10 +24,11 @@ limitations under the License. -->
 <script lang="ts" setup>
 import { AppMain, SideBar, NavBar } from "./components";
 </script>
-<style lang="scss" scope>
+<style lang="scss" scoped>
 .app-wrapper {
   height: 100%;
 }
+
 .main-container {
   flex-grow: 2;
   height: 100%;
diff --git a/src/layout/components/SideBar.vue 
b/src/layout/components/SideBar.vue
index 31da52c..e7afe78 100644
--- a/src/layout/components/SideBar.vue
+++ b/src/layout/components/SideBar.vue
@@ -129,7 +129,7 @@ const filterMenus = (menus: any[]) => {
 };
 </script>
 
-<style lang="scss" scope>
+<style lang="scss" scoped>
 .side-bar {
   position: relative;
   height: 100%;
diff --git a/src/locales/lang/en.ts b/src/locales/lang/en.ts
index a955a01..a1a87f5 100644
--- a/src/locales/lang/en.ts
+++ b/src/locales/lang/en.ts
@@ -115,10 +115,12 @@ const msg = {
   rename: "Rename",
   selfObservability: "Self Observability",
   satellite: "Satellite",
-  skyWalkingServer: "Sky Walking Server",
+  skyWalkingServer: "SkyWalking Server",
   functions: "Functions",
   browser: "Browser",
   linux: "Linux",
+  editWarning: "You are entering edit mode",
+  viewWarning: "You are entering view mode",
   hourTip: "Select Hour",
   minuteTip: "Select Minute",
   secondTip: "Select Second",
diff --git a/src/locales/lang/zh.ts b/src/locales/lang/zh.ts
index 62bc7bf..445c5c5 100644
--- a/src/locales/lang/zh.ts
+++ b/src/locales/lang/zh.ts
@@ -119,6 +119,8 @@ const msg = {
   functions: "Functions",
   linux: "Linux",
   browser: "浏览器",
+  editWarning: "你正在进入编辑模式",
+  viewWarning: "你正在进入预览模式",
   hourTip: "选择小时",
   minuteTip: "选择分钟",
   secondTip: "选择秒数",
diff --git a/src/store/modules/dashboard.ts b/src/store/modules/dashboard.ts
index 4839296..6e7d33a 100644
--- a/src/store/modules/dashboard.ts
+++ b/src/store/modules/dashboard.ts
@@ -41,6 +41,7 @@ interface DashboardState {
   currentTabItems: LayoutConfig[];
   dashboards: DashboardItem[];
   currentDashboard: Nullable<DashboardItem>;
+  editMode: boolean;
 }
 
 export const dashboardStore = defineStore({
@@ -58,11 +59,15 @@ export const dashboardStore = defineStore({
     currentTabItems: [],
     dashboards: [],
     currentDashboard: null,
+    editMode: false,
   }),
   actions: {
     setLayout(data: LayoutConfig[]) {
       this.layout = data;
     },
+    setMode(mode: boolean) {
+      this.editMode = mode;
+    },
     resetDashboards(list: DashboardItem[]) {
       this.dashboards = list;
       sessionStorage.setItem("dashboards", JSON.stringify(list));
diff --git a/src/views/Layer.vue b/src/views/Layer.vue
index ed1f418..b7f3210 100644
--- a/src/views/Layer.vue
+++ b/src/views/Layer.vue
@@ -23,11 +23,13 @@ import { useRoute } from "vue-router";
 import { useI18n } from "vue-i18n";
 import { EntityType } from "./dashboard/data";
 import { useDashboardStore } from "@/store/modules/dashboard";
+import { useAppStoreWithOut } from "@/store/modules/app";
 import Edit from "./dashboard/Edit.vue";
 
 const { t } = useI18n();
 const route = useRoute();
 const dashboardStore = useDashboardStore();
+const appStore = useAppStoreWithOut();
 const routeNames = [
   "GeneralServices",
   "Database",
@@ -44,8 +46,11 @@ const layer = ref<string>("GENERAL");
 getDashboard();
 
 async function getDashboard() {
-  dashboardStore.setCurrentDashboard(null);
   setLayer(String(route.name));
+  dashboardStore.setLayer(layer.value);
+  dashboardStore.setEntity(EntityType[0].value);
+  dashboardStore.setMode(false);
+  dashboardStore.setCurrentDashboard(null);
   await dashboardStore.setDashboards();
   const index = dashboardStore.dashboards.findIndex(
     (d: { name: string; isRoot: boolean; layer: string; entity: string }) =>
@@ -56,6 +61,7 @@ async function getDashboard() {
   }
   const d = dashboardStore.dashboards[index];
   dashboardStore.setCurrentDashboard(d);
+  appStore.setPageTitle(d.name);
 }
 function setLayer(n: string) {
   switch (n) {
@@ -93,9 +99,6 @@ function setLayer(n: string) {
       layer.value = "GENERAL";
       break;
   }
-  dashboardStore.setLayer(layer.value);
-  dashboardStore.setEntity(EntityType[1].value);
-  // appStore.setPageTitle(layer.value);
 }
 watch(
   () => route.name,
diff --git a/src/views/dashboard/Edit.vue b/src/views/dashboard/Edit.vue
index 99a7fae..67d850c 100644
--- a/src/views/dashboard/Edit.vue
+++ b/src/views/dashboard/Edit.vue
@@ -13,11 +13,11 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 
express or implied.
 See the License for the specific language governing permissions and
 limitations under the License. -->
 <template>
-  <Tool v-if="p.entity" />
+  <Tool />
   <div
     class="ds-main"
     @click="handleClick"
-    :style="{ height: p.entity ? 'calc(100% - 45px)' : '100%' }"
+    :style="{ height: dashboardStore.editMode ? 'calc(100% - 45px)' : '100%' }"
   >
     <grid-layout />
     <el-dialog
diff --git a/src/views/dashboard/List.vue b/src/views/dashboard/List.vue
index df462af..f767b2b 100644
--- a/src/views/dashboard/List.vue
+++ b/src/views/dashboard/List.vue
@@ -44,7 +44,11 @@ limitations under the License. -->
         @selection-change="handleSelectionChange"
       >
         <el-table-column type="selection" width="55" />
-        <el-table-column prop="name" label="Name" />
+        <el-table-column prop="name" label="Name">
+          <template #default="scope">
+            <span @click="handleView(scope.row)">{{ scope.row.name }}</span>
+          </template>
+        </el-table-column>
         <el-table-column prop="layer" label="Layer" width="200" />
         <el-table-column prop="entity" label="Entity" width="200" />
         <el-table-column prop="isRoot" label="Root" width="100">
@@ -56,10 +60,10 @@ limitations under the License. -->
         </el-table-column>
         <el-table-column label="Operations">
           <template #default="scope">
-            <el-button size="small" @click="handleView(scope.row)">
+            <el-button size="small" @click="handleEdit(scope.row)">
               {{ t("edit") }}
             </el-button>
-            <el-button size="small" @click="handleEdit(scope.row)">
+            <el-button size="small" @click="handleRename(scope.row)">
               {{ t("rename") }}
             </el-button>
             <el-popconfirm
@@ -196,7 +200,20 @@ function exportTemplates() {
     multipleTableRef.value!.clearSelection();
   }, 2000);
 }
+function handleEdit(row: DashboardItem) {
+  dashboardStore.setMode(true);
+  dashboardStore.setEntity(row.entity);
+  dashboardStore.setLayer(row.layer);
+  dashboardStore.setCurrentDashboard(row);
+  router.push(
+    `/dashboard/${row.layer}/${row.entity}/${row.name.split(" ").join("-")}`
+  );
+}
+
 function handleView(row: DashboardItem) {
+  dashboardStore.setMode(false);
+  dashboardStore.setEntity(row.entity);
+  dashboardStore.setLayer(row.layer);
   dashboardStore.setCurrentDashboard(row);
   router.push(
     `/dashboard/${row.layer}/${row.entity}/${row.name.split(" ").join("-")}`
@@ -267,7 +284,7 @@ async function setRoot(row: DashboardItem) {
   searchDashboards();
   loading.value = false;
 }
-function handleEdit(row: DashboardItem) {
+function handleRename(row: DashboardItem) {
   ElMessageBox.prompt("Please input dashboard name", "Edit", {
     confirmButtonText: "OK",
     cancelButtonText: "Cancel",
diff --git a/src/views/dashboard/controls/Log.vue 
b/src/views/dashboard/controls/Log.vue
index 9f0f9a1..ead077b 100644
--- a/src/views/dashboard/controls/Log.vue
+++ b/src/views/dashboard/controls/Log.vue
@@ -18,7 +18,7 @@ limitations under the License. -->
       placement="bottom"
       trigger="click"
       :width="100"
-      v-if="routeParams.entity"
+      v-if="dashboardStore.editMode"
     >
       <template #reference>
         <span class="delete cp">
@@ -39,7 +39,6 @@ limitations under the License. -->
 </template>
 <script lang="ts" setup>
 import { useI18n } from "vue-i18n";
-import { useRoute } from "vue-router";
 import { useDashboardStore } from "@/store/modules/dashboard";
 import Header from "../related/log/Header.vue";
 import List from "../related/log/List.vue";
@@ -53,7 +52,6 @@ const props = defineProps({
   activeIndex: { type: String, default: "" },
 });
 const { t } = useI18n();
-const routeParams = useRoute().params;
 const dashboardStore = useDashboardStore();
 
 function removeWidget() {
diff --git a/src/views/dashboard/controls/Profile.vue 
b/src/views/dashboard/controls/Profile.vue
index e6bce9e..1faca45 100644
--- a/src/views/dashboard/controls/Profile.vue
+++ b/src/views/dashboard/controls/Profile.vue
@@ -18,7 +18,7 @@ limitations under the License. -->
       placement="bottom"
       trigger="click"
       :width="100"
-      v-if="routeParams.entity"
+      v-if="dashboardStore.editMode"
     >
       <template #reference>
         <span class="delete cp">
@@ -39,7 +39,6 @@ import { useI18n } from "vue-i18n";
 import { useDashboardStore } from "@/store/modules/dashboard";
 import Header from "../related/profile/Header.vue";
 import Content from "../related/profile/Content.vue";
-import { useRoute } from "vue-router";
 
 /*global defineProps */
 const props = defineProps({
@@ -50,8 +49,8 @@ const props = defineProps({
   activeIndex: { type: String, default: "" },
 });
 const { t } = useI18n();
-const routeParams = useRoute().params;
 const dashboardStore = useDashboardStore();
+
 function removeWidget() {
   dashboardStore.removeControls(props.data);
 }
diff --git a/src/views/dashboard/controls/Tab.vue 
b/src/views/dashboard/controls/Tab.vue
index bb77acd..2582f3b 100644
--- a/src/views/dashboard/controls/Tab.vue
+++ b/src/views/dashboard/controls/Tab.vue
@@ -34,10 +34,10 @@ limitations under the License. -->
           size="sm"
           iconName="cancel"
           @click="deleteTabItem($event, idx)"
-          v-if="routeParams.entity"
+          v-if="dashboardStore.editMode"
         />
       </span>
-      <span class="tab-icons" v-if="routeParams.entity">
+      <span class="tab-icons" v-if="dashboardStore.editMode">
         <el-tooltip content="Add tab items" placement="bottom">
           <i @click="addTabItem">
             <Icon size="middle" iconName="add" />
@@ -45,7 +45,7 @@ limitations under the License. -->
         </el-tooltip>
       </span>
     </div>
-    <div class="operations" v-if="routeParams.entity">
+    <div class="operations" v-if="dashboardStore.editMode">
       <el-popover
         placement="bottom"
         trigger="click"
@@ -113,7 +113,6 @@ limitations under the License. -->
 <script lang="ts">
 import { ref, watch, defineComponent, toRefs } from "vue";
 import { useI18n } from "vue-i18n";
-import { useRoute } from "vue-router";
 import type { PropType } from "vue";
 import { LayoutConfig } from "@/types/dashboard";
 import { useDashboardStore } from "@/store/modules/dashboard";
@@ -136,7 +135,6 @@ export default defineComponent({
   props,
   setup(props) {
     const { t } = useI18n();
-    const routeParams = useRoute().params;
     const dashboardStore = useDashboardStore();
     const activeTabIndex = ref<number>(0);
     const activeTabWidget = ref<string>("");
@@ -247,7 +245,6 @@ export default defineComponent({
       needQuery,
       canEditTabName,
       showTools,
-      routeParams,
       t,
     };
   },
diff --git a/src/views/dashboard/controls/Topology.vue 
b/src/views/dashboard/controls/Topology.vue
index 27a7bdd..6fa8a6e 100644
--- a/src/views/dashboard/controls/Topology.vue
+++ b/src/views/dashboard/controls/Topology.vue
@@ -19,7 +19,7 @@ limitations under the License. -->
         placement="bottom"
         trigger="click"
         :width="100"
-        v-if="routeParams.entity"
+        v-if="dashboardStore.editMode"
       >
         <template #reference>
           <span>
@@ -39,7 +39,6 @@ limitations under the License. -->
 </template>
 <script lang="ts" setup>
 import type { PropType } from "vue";
-import { useRoute } from "vue-router";
 import { useI18n } from "vue-i18n";
 import { useDashboardStore } from "@/store/modules/dashboard";
 import Topology from "../related/topology/Index.vue";
@@ -53,7 +52,6 @@ const props = defineProps({
   activeIndex: { type: String, default: "" },
 });
 const { t } = useI18n();
-const routeParams = useRoute().params;
 const dashboardStore = useDashboardStore();
 
 function removeTopo() {
diff --git a/src/views/dashboard/controls/Trace.vue 
b/src/views/dashboard/controls/Trace.vue
index 236c3a5..0682fcf 100644
--- a/src/views/dashboard/controls/Trace.vue
+++ b/src/views/dashboard/controls/Trace.vue
@@ -14,13 +14,18 @@ See the License for the specific language governing 
permissions and
 limitations under the License. -->
 <template>
   <div class="trace-wrapper flex-v">
-    <el-popover placement="bottom" trigger="click" :width="100">
+    <el-popover
+      placement="bottom"
+      trigger="click"
+      :width="100"
+      v-if="dashboardStore.editMode"
+    >
       <template #reference>
         <span class="delete cp">
           <Icon iconName="ellipsis_v" size="middle" class="operation" />
         </span>
       </template>
-      <div class="tools" @click="removeWidget" v-if="routeParams.entity">
+      <div class="tools" @click="removeWidget">
         <span>{{ t("delete") }}</span>
       </div>
     </el-popover>
@@ -35,7 +40,6 @@ limitations under the License. -->
 </template>
 <script lang="ts" setup>
 import type { PropType } from "vue";
-import { useRoute } from "vue-router";
 import Filter from "../related/trace/Filter.vue";
 import TraceList from "../related/trace/TraceList.vue";
 import TraceDetail from "../related/trace/Detail.vue";
@@ -51,7 +55,6 @@ const props = defineProps({
   activeIndex: { type: String, default: "" },
 });
 const { t } = useI18n();
-const routeParams = useRoute().params;
 const dashboardStore = useDashboardStore();
 function removeWidget() {
   dashboardStore.removeControls(props.data);
diff --git a/src/views/dashboard/controls/Widget.vue 
b/src/views/dashboard/controls/Widget.vue
index e183824..f63d34e 100644
--- a/src/views/dashboard/controls/Widget.vue
+++ b/src/views/dashboard/controls/Widget.vue
@@ -38,7 +38,7 @@ limitations under the License. -->
           placement="bottom"
           trigger="click"
           :width="100"
-          v-if="routeParams.entity"
+          v-if="dashboardStore.editMode"
         >
           <template #reference>
             <span>
@@ -74,7 +74,6 @@ limitations under the License. -->
 <script lang="ts">
 import { toRefs, reactive, defineComponent, ref, watch } from "vue";
 import type { PropType } from "vue";
-import { useRoute } from "vue-router";
 import { LayoutConfig } from "@/types/dashboard";
 import { useDashboardStore } from "@/store/modules/dashboard";
 import { useAppStoreWithOut } from "@/store/modules/app";
@@ -98,7 +97,6 @@ export default defineComponent({
   props,
   setup(props) {
     const { t } = useI18n();
-    const routeParams = useRoute().params;
     const loading = ref<boolean>(false);
     const state = reactive<{ source: { [key: string]: unknown } }>({
       source: {},
@@ -196,7 +194,7 @@ export default defineComponent({
       editConfig,
       data,
       loading,
-      routeParams,
+      dashboardStore,
       t,
     };
   },
diff --git a/src/views/dashboard/graphs/EndpointList.vue 
b/src/views/dashboard/graphs/EndpointList.vue
index 27fbd7e..d3b09a0 100644
--- a/src/views/dashboard/graphs/EndpointList.vue
+++ b/src/views/dashboard/graphs/EndpointList.vue
@@ -33,17 +33,13 @@ limitations under the License. -->
       <el-table v-loading="chartLoading" :data="endpoints" style="width: 100%">
         <el-table-column label="Endpoints">
           <template #default="scope">
-            <router-link
+            <span
               class="link"
-              :to="`/dashboard/${dashboardStore.layerId}/${
-                EntityType[2].value
-              }/${selectorStore.currentService.id}/${
-                scope.row.id
-              }/${config.dashboardName.split(' ').join('-')}`"
+              @click="clickEndpoint"
               :style="{ fontSize: `${config.fontSize}px` }"
             >
               {{ scope.row.label }}
-            </router-link>
+            </span>
           </template>
         </el-table-column>
         <el-table-column
@@ -94,6 +90,8 @@ import { useQueryPodsMetrics, usePodsSource } from 
"@/hooks/useProcessor";
 import Line from "./Line.vue";
 import Card from "./Card.vue";
 import { EntityType } from "../data";
+import router from "@/router";
+import getDashboard from "@/hooks/useDashboardsSession";
 
 /*global defineProps */
 const props = defineProps({
@@ -159,6 +157,20 @@ async function queryEndpointMetrics(currentPods: 
Endpoint[]) {
   }
   endpoints.value = currentPods;
 }
+function clickEndpoint(scope: any) {
+  const d = getDashboard({
+    name: props.config.dashboardName,
+    layer: dashboardStore.layerId,
+    entity: EntityType[2].value,
+  });
+  dashboardStore.setEntity(EntityType[2].value);
+  dashboardStore.setCurrentDashboard(d);
+  router.push(
+    `/dashboard/${d.layer}/${d.entity}/${selectorStore.currentService.id}/${
+      scope.row.id
+    }/${d.name.split(" ").join("-")}`
+  );
+}
 function changePage(pageIndex: number) {
   endpoints.value = searchEndpoints.value.splice(pageIndex - 1, pageSize);
 }
diff --git a/src/views/dashboard/graphs/InstanceList.vue 
b/src/views/dashboard/graphs/InstanceList.vue
index 06e7a23..584fc61 100644
--- a/src/views/dashboard/graphs/InstanceList.vue
+++ b/src/views/dashboard/graphs/InstanceList.vue
@@ -33,17 +33,13 @@ limitations under the License. -->
       <el-table v-loading="chartLoading" :data="instances" style="width: 100%">
         <el-table-column label="Service Instances">
           <template #default="scope">
-            <router-link
+            <span
               class="link"
-              :to="`/dashboard/${dashboardStore.layerId}/${
-                EntityType[3].value
-              }/${selectorStore.currentService.id}/${
-                scope.row.id
-              }/${config.dashboardName.split(' ').join('-')}`"
+              @click="clickInstance"
               :style="{ fontSize: `${config.fontSize}px` }"
             >
               {{ scope.row.label }}
-            </router-link>
+            </span>
           </template>
         </el-table-column>
         <el-table-column
@@ -94,6 +90,8 @@ import { InstanceListConfig } from "@/types/dashboard";
 import { Instance } from "@/types/selector";
 import { useQueryPodsMetrics, usePodsSource } from "@/hooks/useProcessor";
 import { EntityType } from "../data";
+import router from "@/router";
+import getDashboard from "@/hooks/useDashboardsSession";
 
 /*global defineProps */
 const props = defineProps({
@@ -164,6 +162,21 @@ async function queryInstanceMetrics(currentInstances: 
Instance[]) {
   instances.value = currentInstances;
 }
 
+function clickInstance(scope: any) {
+  const d = getDashboard({
+    name: props.config.dashboardName,
+    layer: dashboardStore.layerId,
+    entity: EntityType[3].value,
+  });
+  dashboardStore.setCurrentDashboard(d);
+  dashboardStore.setEntity(d.entity);
+  router.push(
+    `/dashboard/${d.layer}/${d.entity}/${selectorStore.currentService.id}/${
+      scope.row.id
+    }/${d.name.split(" ").join("-")}`
+  );
+}
+
 function changePage(pageIndex: number) {
   instances.value = searchInstances.value.splice(pageIndex - 1, pageSize);
 }
diff --git a/src/views/dashboard/graphs/ServiceList.vue 
b/src/views/dashboard/graphs/ServiceList.vue
index f2b7856..81bf5f9 100644
--- a/src/views/dashboard/graphs/ServiceList.vue
+++ b/src/views/dashboard/graphs/ServiceList.vue
@@ -45,16 +45,13 @@ limitations under the License. -->
         </el-table-column>
         <el-table-column label="Service Names">
           <template #default="scope">
-            <router-link
+            <span
               class="link"
-              :to="`/dashboard/${dashboardStore.layerId}/${
-                EntityType[0].value
-              }/${scope.row.id}/${config.dashboardName.split(' ').join('-')}`"
-              :key="1"
               :style="{ fontSize: `${config.fontSize}px` }"
+              @click="clickService(scope)"
             >
               {{ scope.row.label }}
-            </router-link>
+            </span>
           </template>
         </el-table-column>
         <el-table-column
@@ -105,6 +102,8 @@ import { useDashboardStore } from 
"@/store/modules/dashboard";
 import { Service } from "@/types/selector";
 import { useQueryPodsMetrics, usePodsSource } from "@/hooks/useProcessor";
 import { EntityType } from "../data";
+import router from "@/router";
+import getDashboard from "@/hooks/useDashboardsSession";
 
 /*global defineProps */
 const props = defineProps({
@@ -173,6 +172,21 @@ async function queryServices() {
   }
   queryServiceMetrics(services.value);
 }
+
+function clickService(scope: any) {
+  const d = getDashboard({
+    name: props.config.dashboardName,
+    layer: dashboardStore.layerId,
+    entity: EntityType[0].value,
+  });
+  dashboardStore.setCurrentDashboard(d);
+  dashboardStore.setEntity(d.entity);
+  const path = `/dashboard/${d.layer}/${d.entity}/${scope.row.id}/${d.name
+    .split(" ")
+    .join("-")}`;
+
+  router.push(path);
+}
 async function queryServiceMetrics(currentServices: Service[]) {
   const { metrics } = props.config;
 
diff --git a/src/views/dashboard/panel/Tool.vue 
b/src/views/dashboard/panel/Tool.vue
index b1fa821..5285d64 100644
--- a/src/views/dashboard/panel/Tool.vue
+++ b/src/views/dashboard/panel/Tool.vue
@@ -72,15 +72,29 @@ limitations under the License. -->
         />
       </div>
     </div>
-    <div class="tool-icons">
-      <span
-        @click="clickIcons(t)"
-        v-for="(t, index) in toolIcons"
-        :key="index"
-        :title="t.content"
-      >
-        <Icon class="icon-btn" size="sm" :iconName="t.name" />
-      </span>
+    <div class="flex-h tools">
+      <div class="tool-icons flex-h" v-if="dashboardStore.editMode">
+        <span
+          @click="clickIcons(t)"
+          v-for="(t, index) in toolIcons"
+          :key="index"
+          :title="t.content"
+        >
+          <el-tooltip :content="t.content" placement="bottom">
+            <i>
+              <Icon class="icon-btn" size="sm" :iconName="t.name" />
+            </i>
+          </el-tooltip>
+        </span>
+      </div>
+      <div class="switch">
+        <el-switch
+          v-model="dashboardStore.editMode"
+          active-text="Edit"
+          inactive-text="View"
+          @change="changeMode"
+        />
+      </div>
     </div>
   </div>
 </template>
@@ -102,7 +116,9 @@ import {
 import { useSelectorStore } from "@/store/modules/selectors";
 import { ElMessage } from "element-plus";
 import { Option } from "@/types/app";
+import { useI18n } from "vue-i18n";
 
+const { t } = useI18n();
 const dashboardStore = useDashboardStore();
 const selectorStore = useSelectorStore();
 const appStore = useAppStoreWithOut();
@@ -127,9 +143,10 @@ const states = reactive<{
   currentDestService: "",
   currentDestPod: "",
 });
-
-dashboardStore.setLayer(params.layerId);
-dashboardStore.setEntity(params.entity);
+if (params.layerId) {
+  dashboardStore.setLayer(params.layerId);
+  dashboardStore.setEntity(params.entity);
+}
 appStore.setEventStack([initSelector]);
 
 initSelector();
@@ -286,6 +303,14 @@ function changePods(pod: any) {
   }
 }
 
+function changeMode() {
+  if (dashboardStore.editMode) {
+    ElMessage.warning(t("editWarning"));
+    return;
+  }
+  ElMessage.warning(t("viewWarning"));
+}
+
 function clickIcons(t: { id: string; content: string; name: string }) {
   if (
     dashboardStore.selectedGrid &&
@@ -429,12 +454,17 @@ function getTools() {
 <style lang="scss" scoped>
 .dashboard-tool {
   text-align: right;
-  padding: 5px;
+  padding: 3px 5px 5px 5px;
   background: rgb(240, 242, 245);
   border-bottom: 1px solid #dfe4e8;
   justify-content: space-between;
 }
 
+.switch {
+  padding-top: 2px;
+  margin: 0 10px;
+}
+
 .label {
   font-size: 12px;
   display: inline-block;
@@ -445,6 +475,10 @@ function getTools() {
   margin-top: 2px;
 }
 
+.tools {
+  justify-content: space-between;
+}
+
 .icon-btn {
   display: inline-block;
   padding: 3px;
diff --git a/src/views/dashboard/related/topology/components/Graph.vue 
b/src/views/dashboard/related/topology/components/Graph.vue
index f67be5e..3f1baf6 100644
--- a/src/views/dashboard/related/topology/components/Graph.vue
+++ b/src/views/dashboard/related/topology/components/Graph.vue
@@ -85,6 +85,7 @@ import Settings from "./Settings.vue";
 import { Option } from "@/types/app";
 import { Service } from "@/types/selector";
 import { useAppStoreWithOut } from "@/store/modules/app";
+import getDashboard from "@/hooks/useDashboardsSession";
 
 /*global Nullable, defineProps */
 const props = defineProps({
@@ -239,9 +240,15 @@ function handleLinkClick(event: any, d: Call) {
     dashboardStore.entity === EntityType[1].value
       ? EntityType[0].value
       : dashboardStore.entity;
-  const path = `/dashboard/${dashboardStore.layerId}/${e}Relation/${
-    d.source.id
-  }/${d.target.id}/${settings.value.linkDashboard.split(" ").join("-")}`;
+  const p = getDashboard({
+    name: settings.value.linkDashboard,
+    layer: dashboardStore.layerId,
+    entity: `${e}Relation`,
+  });
+  dashboardStore.setEntity(p.entity);
+  const path = `/dashboard/${p.layer}/${e}Relation/${d.source.id}/${
+    d.target.id
+  }/${p.name.split(" ").join("-")}`;
   const routeUrl = router.resolve({ path });
   window.open(routeUrl.href, "_blank");
 }
@@ -373,15 +380,27 @@ async function handleInspect() {
   update();
 }
 function handleGoEndpoint(name: string) {
-  const path = `/dashboard/${dashboardStore.layerId}/Endpoint/${
-    topologyStore.node.id
-  }/${name.split(" ").join("-")}`;
+  const p = getDashboard({
+    name,
+    layer: dashboardStore.layerId,
+    entity: EntityType[2].value,
+  });
+  dashboardStore.setEntity(p.entity);
+  const path = `/dashboard/${p.layer}/Endpoint/${topologyStore.node.id}/${name
+    .split(" ")
+    .join("-")}`;
   const routeUrl = router.resolve({ path });
 
   window.open(routeUrl.href, "_blank");
 }
 function handleGoInstance(name: string) {
-  const path = `/dashboard/${dashboardStore.layerId}/ServiceInstance/${
+  const p = getDashboard({
+    name,
+    layer: dashboardStore.layerId,
+    entity: EntityType[3].value,
+  });
+  dashboardStore.setEntity(p.entity);
+  const path = `/dashboard/${p.layer}/ServiceInstance/${
     topologyStore.node.id
   }/${name.split(" ").join("-")}`;
   const routeUrl = router.resolve({ path });
@@ -389,9 +408,15 @@ function handleGoInstance(name: string) {
   window.open(routeUrl.href, "_blank");
 }
 function handleGoDashboard(name: string) {
-  const path = `/dashboard/${dashboardStore.layerId}/Service/${
-    topologyStore.node.id
-  }/${name.split(" ").join("-")}`;
+  const p = getDashboard({
+    name,
+    layer: dashboardStore.layerId,
+    entity: EntityType[0].value,
+  });
+  dashboardStore.setEntity(p.entity);
+  const path = `/dashboard/${p.layer}/Service/${topologyStore.node.id}/${name
+    .split(" ")
+    .join("-")}`;
   const routeUrl = router.resolve({ path });
 
   window.open(routeUrl.href, "_blank");
diff --git a/src/views/dashboard/related/topology/components/PodTopology.vue 
b/src/views/dashboard/related/topology/components/PodTopology.vue
index 045f17f..83e9fbf 100644
--- a/src/views/dashboard/related/topology/components/PodTopology.vue
+++ b/src/views/dashboard/related/topology/components/PodTopology.vue
@@ -86,6 +86,7 @@ import { ElMessage } from "element-plus";
 import Sankey from "./Sankey.vue";
 import Settings from "./Settings.vue";
 import router from "@/router";
+import getDashboard from "@/hooks/useDashboardsSession";
 
 /*global defineProps */
 const props = defineProps({
@@ -150,7 +151,14 @@ function goDashboard() {
     dashboardStore.entity === EntityType[2].value
       ? EntityType[2].value
       : EntityType[3].value;
-  const path = 
`/dashboard/${dashboardStore.layerId}/${entity}/${topologyStore.node.serviceId}/${topologyStore.node.id}/${settings.value.nodeDashboard}`;
+  const d = getDashboard({
+    name: settings.value.nodeDashboard,
+    layer: dashboardStore.layerId,
+    entity,
+  });
+  dashboardStore.setEntity(entity);
+  dashboardStore.setCurrentDashboard(d);
+  const path = 
`/dashboard/${d.layer}/${entity}/${topologyStore.node.serviceId}/${topologyStore.node.id}/${d.name}`;
   const routeUrl = router.resolve({ path });
   window.open(routeUrl.href, "_blank");
   topologyStore.setNode(null);
@@ -182,7 +190,13 @@ function selectNodeLink(d: any) {
       dashboardStore.entity === EntityType[2].value
         ? EntityType[6].value
         : EntityType[5].value;
-    const path = 
`/dashboard/${dashboardStore.layerId}/${entity}/${sourceObj.serviceId}/${sourceObj.id}/${targetObj.serviceId}/${targetObj.id}/${settings.value.linkDashboard}`;
+    const p = getDashboard({
+      name: settings.value.linkDashboard,
+      layer: dashboardStore.layerId,
+      entity,
+    });
+    dashboardStore.setEntity(entity);
+    const path = 
`/dashboard/${p.layer}/${entity}/${sourceObj.serviceId}/${sourceObj.id}/${targetObj.serviceId}/${targetObj.id}/${p.name}`;
     const routeUrl = router.resolve({ path });
     window.open(routeUrl.href, "_blank");
     return;
diff --git a/src/views/dashboard/related/topology/components/Settings.vue 
b/src/views/dashboard/related/topology/components/Settings.vue
index 3d5e658..55895ab 100644
--- a/src/views/dashboard/related/topology/components/Settings.vue
+++ b/src/views/dashboard/related/topology/components/Settings.vue
@@ -225,6 +225,7 @@ const states = reactive<{
   linkDashboards: [],
   nodeDashboards: [],
 });
+console.log(dashboardStore.selectedGrid);
 const isService = [EntityType[0].value, EntityType[1].value].includes(
   dashboardStore.entity
 );

Reply via email to