You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@skywalking.apache.org by ke...@apache.org on 2021/06/02 12:26:52 UTC

[skywalking-rocketbot-ui] branch master updated: Feat: Implement metrics templates in the topology (#495)

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

kezhenxu94 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/skywalking-rocketbot-ui.git


The following commit(s) were added to refs/heads/master by this push:
     new 8ab2da2  Feat: Implement metrics templates in the topology (#495)
8ab2da2 is described below

commit 8ab2da2bf10719df857bf07809034d9fe522c23e
Author: Qiuxia Fan <fi...@outlook.com>
AuthorDate: Wed Jun 2 20:26:46 2021 +0800

    Feat: Implement metrics templates in the topology (#495)
---
 src/assets/lang/en.ts                              |   2 +
 src/assets/lang/zh.ts                              |   2 +
 src/assets/styles/lib.scss                         |   3 +
 src/assets/styles/reset.scss                       |   4 +-
 src/assets/styles/style.scss                       |  16 -
 src/components/rk-select.vue                       |  49 +-
 src/constants/constant.ts                          |  13 +-
 src/graph/fragments/topology.ts                    | 254 --------
 src/graph/query/topology.ts                        |  25 +-
 .../modules/dashboard/dashboard-data-query.ts      | 120 +++-
 src/store/modules/dashboard/mutation-types.ts      |   3 +
 src/store/modules/global/selectors.ts              |  37 +-
 src/store/modules/topology/index.ts                | 697 +++++++++++++--------
 src/store/modules/trace/index.ts                   |   4 +-
 src/store/mutation-types.ts                        |  28 +-
 src/types/topo.d.ts                                |  94 +--
 .../components/dashboard/charts/chart-bar.vue      |   4 +
 .../components/dashboard/charts/chart-edit.vue     | 127 ++--
 .../components/dashboard/charts/chart-heap.vue     |   4 +
 .../components/dashboard/charts/chart-line.vue     |   4 +
 .../components/dashboard/charts/chart-num.vue      |   7 +-
 .../components/dashboard/charts/chart-table.vue    |  14 +-
 src/views/components/dashboard/charts/constant.ts  |   3 +
 src/views/components/dashboard/dashboard-item.vue  | 131 +++-
 .../dashboard/tool-bar/tool-bar-btns.vue           |   2 +-
 .../components/dashboard/tool-bar/tool-bar.vue     |   4 +
 src/views/components/topology/chart-line.vue       |  98 ---
 .../topology/{ => chart}/dependency-sankey.vue     |   5 -
 .../components/topology/{ => chart}/radial.vue     |   0
 src/views/components/topology/chart/topo.vue       |  10 +-
 .../dependency/topo-endpoint-dependency.vue        | 314 ++++++++++
 .../dependency/topo-instance-dependency.vue        | 342 ++++++++++
 .../dependency/topo-service-dependency.vue         | 143 +++++
 .../components/topology/styles/common.scss}        |  37 +-
 src/views/components/topology/topo-aside.vue       |  83 +--
 src/views/components/topology/topo-chart.vue       |  94 ---
 .../components/topology/topo-detect-point.vue      | 343 +++++++---
 .../topology/topo-endpoint-dependency.vue          | 126 ----
 .../topology/topo-instance-dependency.vue          | 148 -----
 .../components/topology/topo-service-metrics.vue   | 129 ++++
 src/views/containers/dashboard.vue                 |  20 +-
 .../topology/endpoint-dependency/index.vue         |   6 +-
 .../topology/endpoint/endpoints-survey.vue         |  92 ++-
 src/views/containers/topology/endpoint/index.vue   | 119 +++-
 src/views/containers/topology/instance/index.vue   | 121 +++-
 .../topology/instance/instances-survey.vue         |  90 ++-
 src/views/containers/topology/topology.vue         | 165 +++--
 47 files changed, 2598 insertions(+), 1538 deletions(-)

diff --git a/src/assets/lang/en.ts b/src/assets/lang/en.ts
index 33a931a..4f6c801 100644
--- a/src/assets/lang/en.ts
+++ b/src/assets/lang/en.ts
@@ -226,6 +226,8 @@ const m = {
   tooltipsContent: 'Tooltip Content',
   alarmDetail: 'Alarm Detail',
   scope: 'Scope',
+  destService: 'Destination Service',
+  destServiceInstance: 'Destination Service Instance',
 };
 
 export default m;
diff --git a/src/assets/lang/zh.ts b/src/assets/lang/zh.ts
index 972d197..5ed9f6d 100644
--- a/src/assets/lang/zh.ts
+++ b/src/assets/lang/zh.ts
@@ -224,6 +224,8 @@ const m = {
   tooltipsContent: '提示内容',
   alarmDetail: '警告详情',
   scope: '范围',
+  destService: '终点服务',
+  destServiceInstance: '终点实例',
 };
 
 export default m;
diff --git a/src/assets/styles/lib.scss b/src/assets/styles/lib.scss
index f18b456..94232c9 100644
--- a/src/assets/styles/lib.scss
+++ b/src/assets/styles/lib.scss
@@ -175,6 +175,9 @@
 .pt-5 {
   padding-top: 5px;
 }
+.pl-10 {
+  padding-left: 10px;
+}
 .pt-10 {
   padding-top: 10px;
 }
diff --git a/src/assets/styles/reset.scss b/src/assets/styles/reset.scss
index 44b7d50..754c350 100644
--- a/src/assets/styles/reset.scss
+++ b/src/assets/styles/reset.scss
@@ -165,7 +165,7 @@ pre {
   overflow: auto;
 }
 .scroll_bar_style::-webkit-scrollbar {
-  width: 10px;
+  width: 9px;
   height: 6px;
 }
 .scroll_bar_style::-webkit-scrollbar-track {
@@ -173,5 +173,5 @@ pre {
 }
 .scroll_bar_style::-webkit-scrollbar-thumb {
   border-radius: 5px;
-  background: #777;
+  background: rgba(196, 200, 225, .2);
 }
diff --git a/src/assets/styles/style.scss b/src/assets/styles/style.scss
index 2cb9595..a805edd 100644
--- a/src/assets/styles/style.scss
+++ b/src/assets/styles/style.scss
@@ -68,19 +68,3 @@
 .oa:hover {
   overflow: auto;
 }
-
-.dashboard-container {
-  overflow: auto;
-  padding: 20px 15px;
-  height: 100%;
-  flex-grow: 1;
-  .rk-add-dashboard-item {
-    height: 342px;
-    text-align: center;
-    line-height: 250px;
-    border: 1px dashed rgba(196, 200, 225, 0.5);
-    cursor: pointer;
-    display: inline-block;
-    font-size: 16px;
-  }
-}
diff --git a/src/components/rk-select.vue b/src/components/rk-select.vue
index 528c05a..7e20251 100644
--- a/src/components/rk-select.vue
+++ b/src/components/rk-select.vue
@@ -21,15 +21,15 @@ limitations under the License. -->
         search = '';
       }
     "
-    :class="{ active: visible }"
+    :class="{ active: visible, dark: theme === 'dark' }"
   >
-    <div class="rk-bar-i flex-h" @click="visible = !visible">
+    <div class="rk-bar-i flex-h" @click="visible = !visible" :class="{ dark: theme === 'dark' }">
       <div class="mr-15 rk-bar-i-text">
-        <div v-if="Array.isArray(current)">
-          <span class="selected" v-for="item in current" :key="item.key">
+        <div v-if="Array.isArray(current)" class="flex-h">
+          <div class="selected" v-for="item in current" :key="item.key">
             <span>{{ item.label }}</span>
             <span class="remove-icon" v-if="current.length !== 1" @click="removeSelected(item)">×</span>
-          </span>
+          </div>
         </div>
         <div class="ell" v-else v-tooltip:right.ellipsis="current.label || ''">
           {{ current.label }}
@@ -39,9 +39,9 @@ limitations under the License. -->
         <use xlink:href="#arrow-down"></use>
       </svg>
     </div>
-    <div class="rk-sel" v-show="visible">
+    <div class="rk-sel" v-show="visible" :class="{ dark: theme === 'dark' }">
       <div>
-        <input type="text" class="rk-sel-search" v-model="search" />
+        <input type="text" class="rk-sel-search" v-model="search" :class="{ dark: theme === 'dark' }" />
         <svg class="icon sm close" @click="search = ''" v-if="search">
           <use xlink:href="#clear"></use>
         </svg>
@@ -50,7 +50,7 @@ limitations under the License. -->
         <div
           class="rk-opt ell"
           @click="handleSelect(i)"
-          :class="{ 'select-disabled': selectedOpt.includes(i.key) }"
+          :class="{ 'select-disabled': selectedOpt.includes(i.key), dark: theme === 'dark' }"
           v-for="i in filterData"
           :key="i.key"
         >
@@ -69,6 +69,8 @@ limitations under the License. -->
     @Prop() private mode: any;
     @Prop() private data!: any;
     @Prop() private current!: any;
+    @Prop({ default: 'light' }) private theme!: string;
+
     private search: string = '';
     private visible: boolean = false;
 
@@ -116,18 +118,17 @@ limitations under the License. -->
       flex-shrink: 0;
     }
     .selected {
-      display: inline-block;
-      padding: 5px;
+      padding: 0 3px;
       border-radius: 3px;
       margin: 3px;
-      overflow: hidden;
       color: rgba(0, 0, 0, 0.65);
       background-color: #fafafa;
       border: 1px solid #e8e8e8;
+      text-align: center;
     }
     .remove-icon {
       display: inline-block;
-      margin-left: 5px;
+      padding: 0 6px;
       cursor: pointer;
     }
   }
@@ -137,7 +138,7 @@ limitations under the License. -->
   .rk-bar-i {
     height: 100%;
     width: 100%;
-    padding: 5px 10px;
+    padding: 2px 10px;
     overflow: auto;
   }
   .rk-sel {
@@ -185,4 +186,26 @@ limitations under the License. -->
     max-height: 200px;
     padding-bottom: 2px;
   }
+  .rk-sel-search.dark {
+    border-bottom: 1px solid #333;
+    border-top: 1px solid #333;
+  }
+  .dark {
+    border: none;
+    background: #3d444f;
+    color: #eee;
+    &:hover {
+      background-color: #333;
+    }
+    &.select-disabled {
+      color: #eee;
+      cursor: not-allowed;
+    }
+  }
+  .selected-ell {
+    display: table-cell;
+    vertical-align: middle;
+    text-align: center;
+    height: 100%;
+  }
 </style>
diff --git a/src/constants/constant.ts b/src/constants/constant.ts
index f67961e..f1c77cd 100644
--- a/src/constants/constant.ts
+++ b/src/constants/constant.ts
@@ -18,12 +18,10 @@
 export enum TopologyType {
   TOPOLOGY_ENDPOINT = 'TOPOLOGY_ENDPOINT',
   TOPOLOGY_INSTANCE = 'TOPOLOGY_INSTANCE',
-}
-
-export enum ObjectsType {
-  UPDATE_INSTANCES = 'UPDATE_INSTANCES',
-  UPDATE_ENDPOINTS = 'UPDATE_ENDPOINTS',
-  UPDATE_DASHBOARD = 'UPDATE_DASHBOARD',
+  TOPOLOGY_SERVICE = 'TOPOLOGY_SERVICE',
+  TOPOLOGY_SERVICE_DEPENDENCY = 'TOPOLOGY_SERVICE_RELATION',
+  TOPOLOGY_SERVICE_INSTANCE_DEPENDENCY = 'TOPOLOGY_SERVICE_INSTANCE_RELATION',
+  TOPOLOGY_ENDPOINT_DEPENDENCY = 'TOPOLOGY_ENDPOINT_RELATION',
 }
 
 export enum TimeType {
@@ -36,8 +34,11 @@ export enum PageEventsType {
   DASHBOARD_EVENTS = 'dashboardEvents',
   TOPO_ENDPOINT_EVENTS = 'topoEndpointEvents',
   TOPO_INSTANCE_EVENTS = 'topoInstanceEvents',
+  TOPO_SERVICE_EVENTS = 'topoInstanceEvents',
 }
 export enum PageTypes {
   DASHBOARD = 'Dashboard',
   LOG = 'Log',
+  TOPOLOGY = 'Topology',
 }
+export const DEFAULT = 'default';
diff --git a/src/graph/fragments/topology.ts b/src/graph/fragments/topology.ts
index 18288f9..c540d9b 100644
--- a/src/graph/fragments/topology.ts
+++ b/src/graph/fragments/topology.ts
@@ -15,142 +15,6 @@
  * limitations under the License.
  */
 
-export const TopoServiceInfo = {
-  variable: '$duration: Duration!, $id: ID!',
-  query: `
-    getResponseTimeTrend: getLinearIntValues(metric: {
-      name: "service_relation_server_resp_time"
-      id: $id
-    }, duration: $duration) {
-      values {
-        value
-      }
-    }
-    getThroughputTrend: getLinearIntValues(metric: {
-      name: "service_relation_server_cpm"
-      id: $id
-    }, duration: $duration) {
-      values {
-        value
-      }
-    }
-    getSLATrend: getLinearIntValues(metric: {
-      name: "service_relation_server_call_sla"
-      id: $id
-    }, duration: $duration) {
-      values {
-        value
-      }
-    }
-    getPercentile: getMultipleLinearIntValues(metric: {
-      name: "service_relation_server_percentile",
-      id: $id
-    }, numOfLinear: 5, duration: $duration) { values { value } }
-`,
-};
-
-export const TopoClientInfo = {
-  variable: '$duration: Duration!, $id: ID!',
-  query: `
-    getResponseTimeTrend: getLinearIntValues(metric: {
-      name: "service_relation_client_resp_time"
-      id: $id
-    }, duration: $duration) {
-      values {
-        value
-      }
-    }
-    getThroughputTrend: getLinearIntValues(metric: {
-      name: "service_relation_client_cpm"
-      id: $id
-    }, duration: $duration) {
-      values {
-        value
-      }
-    }
-    getSLATrend: getLinearIntValues(metric: {
-      name: "service_relation_client_call_sla"
-      id: $id
-    }, duration: $duration) {
-      values {
-        value
-      }
-    }
-    getPercentile: getMultipleLinearIntValues(metric: {
-      name: "service_relation_client_percentile",
-      id: $id
-    }, numOfLinear: 5, duration: $duration) { values { value } }
-`,
-};
-
-export const TopoInstanceClientInfo = {
-  variable: '$duration: Duration!, $id: ID!',
-  query: `
-    getResponseTimeTrend: getLinearIntValues(metric: {
-      name: "service_instance_relation_client_resp_time"
-      id: $id
-    }, duration: $duration) {
-      values {
-        value
-      }
-    }
-    getThroughputTrend: getLinearIntValues(metric: {
-      name: "service_instance_relation_client_cpm"
-      id: $id
-    }, duration: $duration) {
-      values {
-        value
-      }
-    }
-    getSLATrend: getLinearIntValues(metric: {
-      name: "service_instance_relation_client_call_sla"
-      id: $id
-    }, duration: $duration) {
-      values {
-        value
-      }
-    }
-    getPercentile: getMultipleLinearIntValues(metric: {
-      name: "service_instance_relation_client_percentile",
-      id: $id
-    }, numOfLinear: 5, duration: $duration) { values { value } }
-`,
-};
-
-export const TopoInstanceServerInfo = {
-  variable: '$duration: Duration!, $id: ID!',
-  query: `
-    getResponseTimeTrend: getLinearIntValues(metric: {
-      name: "service_instance_relation_server_resp_time"
-      id: $id
-    }, duration: $duration) {
-      values {
-        value
-      }
-    }
-    getThroughputTrend: getLinearIntValues(metric: {
-      name: "service_instance_relation_server_cpm"
-      id: $id
-    }, duration: $duration) {
-      values {
-        value
-      }
-    }
-    getSLATrend: getLinearIntValues(metric: {
-      name: "service_instance_relation_server_call_sla"
-      id: $id
-    }, duration: $duration) {
-      values {
-        value
-      }
-    }
-    getPercentile: getMultipleLinearIntValues(metric: {
-      name: "service_instance_relation_client_percentile",
-      id: $id
-    }, numOfLinear: 5, duration: $duration) { values { value } }
-`,
-};
-
 export const TopoInstanceDependency = {
   variable: '$clientServiceId: ID!, $serverServiceId: ID!, $duration: Duration!',
   query: `
@@ -352,121 +216,3 @@ export const DependencyInstanceClientMetric = {
     }
   }`,
 };
-export const TopoServiceDetail = {
-  variable: ['$serviceId: ID!', '$duration: Duration!'],
-  query: `
-    servicePercentile: getMultipleLinearIntValues(metric: {
-      name: "service_percentile"
-      id: $serviceId
-    }, numOfLinear: 5, duration: $duration) {
-      values { value }
-    }
-    serviceSLA: getLinearIntValues(metric: {
-      name: "service_sla"
-      id: $serviceId
-    }, duration: $duration) {
-      values {
-        value
-      }
-    }
-    serviceThroughput: getLinearIntValues(metric: {
-      name: "service_cpm"
-      id: $serviceId
-    }, duration: $duration) {
-      values {
-        value
-      }
-    }
-    serviceResponseTime: getLinearIntValues(metric: {
-      name: "service_resp_time"
-      id: $serviceId
-    }, duration: $duration) {
-      values {value}
-    }
-    serviceApdexScore: getLinearIntValues(metric: {
-      name: "service_apdex"
-      id: $serviceId
-    }, duration: $duration) {
-      values {value}
-    }
-`,
-};
-export const TopoEndpointDependencyMetrics = {
-  variable: [
-    '$serviceName: String',
-    '$endpointName: String',
-    '$destServiceName: String',
-    '$destEndpointName: String',
-    '$duration: Duration!',
-  ],
-  query: `
-    endpointRelationPercentile: readLabeledMetricsValues(condition: {
-      name: "endpoint_relation_percentile"
-      entity: {
-        scope: EndpointRelation
-        serviceName: $serviceName
-        normal: true
-        endpointName: $endpointName
-        destNormal: true
-        destServiceName:  $destServiceName
-        destEndpointName: $destEndpointName
-      }
-    }, labels: ["0", "1", "2", "3", "4"], duration: $duration) {
-      label
-      values {
-        values {value}
-      }
-    }
-    endpointRelationCpm: readMetricsValues(condition: {
-      name: "endpoint_relation_cpm"
-      entity: {
-        scope: EndpointRelation
-        serviceName: $serviceName
-        normal: true
-        endpointName: $endpointName
-        destNormal: true
-        destServiceName:  $destServiceName
-        destEndpointName: $destEndpointName
-      }
-    }, duration: $duration) {
-      label
-      values {
-        values {value}
-      }
-    }
-    endpointRelationRespTime: readMetricsValues(condition: {
-      name: "endpoint_relation_resp_time"
-      entity: {
-        scope: EndpointRelation
-        serviceName: $serviceName
-        normal: true
-        endpointName: $endpointName
-        destNormal: true
-        destServiceName:  $destServiceName
-        destEndpointName: $destEndpointName
-      }
-    }, duration: $duration) {
-      label
-      values {
-        values {value}
-      }
-    }
-    endpointRelationSla: readMetricsValues(condition: {
-      name: "endpoint_relation_sla"
-      entity: {
-        scope: EndpointRelation
-        serviceName: $serviceName
-        normal: true
-        endpointName: $endpointName
-        destNormal: true
-        destServiceName:  $destServiceName
-        destEndpointName: $destEndpointName
-      }
-    }, duration: $duration) {
-      label
-      values {
-        values {value}
-      }
-    }
-`,
-};
diff --git a/src/graph/query/topology.ts b/src/graph/query/topology.ts
index e4d8ec3..8b8a4ac 100644
--- a/src/graph/query/topology.ts
+++ b/src/graph/query/topology.ts
@@ -21,17 +21,11 @@ import {
   ServicesTopo,
   TopoMetric,
   TopoInstanceDependency,
-  TopoInstanceClientInfo,
-  TopoInstanceServerInfo,
   TopoServiceMetric,
   TopoClientMetric,
-  TopoServiceInfo,
-  TopoClientInfo,
   DependencyInstanceServerMetric,
   DependencyInstanceClientMetric,
-  TopoServiceDetail,
   endpointTopology,
-  TopoEndpointDependencyMetrics,
 } from '../fragments/topology';
 
 export const queryTopo = `query queryTopo(${Topo.variable}) {${Topo.query}}`;
@@ -51,32 +45,17 @@ export const queryTopoInfo = `query queryTopoInfo(
         ${TopoClientMetric.query}
       }`;
 
-export const queryTopoServiceInfo = `query queryTopoServiceInfo(
-  ${TopoServiceInfo.variable}) {${TopoServiceInfo.query}}`;
-
-export const queryTopoClientInfo = `query queryTopoClientInfo(
-  ${TopoClientInfo.variable}) {${TopoClientInfo.query}}`;
-
 export const queryTopoInstanceDependency = `query queryTopoInstanceDependency(
   ${TopoInstanceDependency.variable}) {${TopoInstanceDependency.query}}`;
 
-export const queryTopoInstanceServerInfo = `query queryTopoInstanceServerInfo(
-  ${TopoInstanceServerInfo.variable}) {${TopoInstanceServerInfo.query}}`;
-
-export const queryTopoInstanceClientInfo = `query queryTopoInstanceClientInfo(
-  ${TopoInstanceClientInfo.variable}) {${TopoInstanceClientInfo.query}}`;
-
 export const queryDependencyInstanceServerMetric = `query queryDependencyInstanceServerMetric(
   ${DependencyInstanceServerMetric.variable}) {${DependencyInstanceServerMetric.query}}`;
 
 export const queryDependencyInstanceClientMetric = `query queryDependencyInstanceClientMetric(
   ${DependencyInstanceClientMetric.variable}) {${DependencyInstanceClientMetric.query}}`;
 
-export const queryTopoServiceDetail = `query queryTopoServiceDetail(
-  ${TopoServiceDetail.variable}) {${TopoServiceDetail.query}}`;
+// export const queryTopoServiceDetail = `query queryTopoServiceDetail(
+//   ${TopoServiceDetail.variable}) {${TopoServiceDetail.query}}`;
 
 export const queryEndpointTopology = `query queryEndpointTopology(${endpointTopology.variable}) {
   ${endpointTopology.query}}`;
-
-export const queryTopoEndpointDependencyMetrics = `query queryTopoEndpointDependencyMetrics(
-  ${TopoEndpointDependencyMetrics.variable}) {${TopoEndpointDependencyMetrics.query}}`;
diff --git a/src/store/modules/dashboard/dashboard-data-query.ts b/src/store/modules/dashboard/dashboard-data-query.ts
index 5394335..7318cce 100644
--- a/src/store/modules/dashboard/dashboard-data-query.ts
+++ b/src/store/modules/dashboard/dashboard-data-query.ts
@@ -19,11 +19,7 @@ import { Commit, ActionTree, Dispatch } from 'vuex';
 import { AxiosResponse } from 'axios';
 import { State } from './dashboard-data';
 import graph from '@/graph';
-
-export enum TopologyType {
-  TOPOLOGY_ENDPOINT = 'TOPOLOGY_ENDPOINT',
-  TOPOLOGY_INSTANCE = 'TOPOLOGY_INSTANCE',
-}
+import { TopologyType } from '@/constants/constant';
 
 // actions
 const actions: ActionTree<State, any> = {
@@ -34,31 +30,104 @@ const actions: ActionTree<State, any> = {
       duration: any;
       type: string;
       rocketOption: any;
+      templateType: string;
+      templateMode: string;
     },
   ) {
-    const { currentDatabase, currentEndpoint, currentInstance, currentService } = params.rocketOption;
+    const {
+      currentDatabase,
+      currentEndpoint,
+      currentInstance,
+      currentService,
+      destService,
+      destInstance,
+      destEndpoint,
+    } = params.rocketOption;
     const dashboard: string = `${window.localStorage.getItem('dashboard')}`;
     const tree = dashboard ? JSON.parse(dashboard) : context.state.tree;
     const normal = params.type ? true : tree[context.state.group].type === 'database' ? false : true;
-    let config = {} as any;
+    let config = null as any;
     const names = ['readSampledRecords', 'sortMetrics'];
 
     if (params.type === TopologyType.TOPOLOGY_ENDPOINT) {
-      const endpointComps: string = `${window.localStorage.getItem('topologyEndpoints')}`;
-      const topoEndpoint = endpointComps ? JSON.parse(endpointComps) : [];
-      config = topoEndpoint[params.index];
+      const endpointCompStr: string = `${window.localStorage.getItem('topologyEndpoints')}`;
+      const topoEndpoint = endpointCompStr ? JSON.parse(endpointCompStr) : {};
+      let endpointComps: any = [];
+      for (const type of params.templateType) {
+        const t: any = type;
+
+        endpointComps = [...endpointComps, ...topoEndpoint[t]];
+      }
+      config = endpointComps[params.index];
+      if (!config) {
+        return new Promise((resolve) => resolve({}));
+      }
     } else if (params.type === TopologyType.TOPOLOGY_INSTANCE) {
-      const instanceComps: string = `${window.localStorage.getItem('topologyInstances')}`;
-      const topoInstance = instanceComps ? JSON.parse(instanceComps) : [];
-      config = topoInstance[params.index];
+      const instanceCompStr: string = `${localStorage.getItem('topologyInstances')}`;
+      const topoInstance = instanceCompStr ? JSON.parse(instanceCompStr) : {};
+      let instanceComps: any[] = [];
+      for (const type of params.templateType) {
+        const t: any = type;
+
+        instanceComps = [...instanceComps, ...topoInstance[t]];
+      }
+      config = instanceComps[params.index];
+      if (!config) {
+        return new Promise((resolve) => resolve({}));
+      }
+    } else if (params.type === TopologyType.TOPOLOGY_SERVICE) {
+      const serviceCompsStr: string = `${window.localStorage.getItem('topologyServices')}`;
+      const topoService = serviceCompsStr ? JSON.parse(serviceCompsStr) : {};
+      let serviceComps: any[] = [];
+
+      for (const type of params.templateType) {
+        serviceComps = [...serviceComps, ...topoService[type]];
+      }
+      config = serviceComps[params.index];
+      if (!config) {
+        return new Promise((resolve) => resolve({}));
+      }
+    } else if (params.type === TopologyType.TOPOLOGY_SERVICE_DEPENDENCY) {
+      const serviceDependencyCompStr: string = `${window.localStorage.getItem('topologyServicesDependency')}`;
+      const topoServiceDependency = serviceDependencyCompStr ? JSON.parse(serviceDependencyCompStr) : {};
+      let serviceDependencyComps: any[] = [];
+
+      for (const type of params.templateType) {
+        serviceDependencyComps = [...serviceDependencyComps, ...topoServiceDependency[type][params.templateMode]];
+      }
+      config = serviceDependencyComps[params.index];
+    } else if (params.type === TopologyType.TOPOLOGY_SERVICE_INSTANCE_DEPENDENCY) {
+      const serviceInstanceDependencyComps: string = `${localStorage.getItem('topologyServicesInstanceDependency')}`;
+      const topoServiceInstanceDependency = serviceInstanceDependencyComps
+        ? JSON.parse(serviceInstanceDependencyComps)
+        : {};
+      let instanceDependencyComps: any[] = [];
+
+      for (const type of params.templateType) {
+        instanceDependencyComps = [
+          ...instanceDependencyComps,
+          ...topoServiceInstanceDependency[type][params.templateMode],
+        ];
+      }
+      config = instanceDependencyComps[params.index];
+    } else if (params.type === TopologyType.TOPOLOGY_ENDPOINT_DEPENDENCY) {
+      const endpointDependencyCompStr: string = `${localStorage.getItem('topologyEndpointDependency')}`;
+      const topoEndpointDependency = JSON.parse(endpointDependencyCompStr || JSON.stringify({}));
+      let endpointDependencyComps: any[] = [];
+
+      for (const type of params.templateType) {
+        endpointDependencyComps = [...endpointDependencyComps, ...topoEndpointDependency[type]];
+      }
+      config = endpointDependencyComps[params.index];
     } else {
       config = tree[context.state.group].children[context.state.current].children[params.index];
     }
+
     if (!config) {
-      return;
+      return new Promise((resolve) => resolve([]));
     }
     if (!config.metricName) {
-      return;
+      return new Promise((resolve) => resolve([{ config }]));
     }
     // remove the space at the beginning and end of the string
     const metricNames = config.metricName.split(',').map((item: string) => item.replace(/^\s*|\s*$/g, ''));
@@ -68,6 +137,7 @@ const actions: ActionTree<State, any> = {
     const currentEndpointId = config.independentSelector ? config.currentEndpoint : currentEndpoint.label;
     const currentDatabaseId = config.independentSelector ? config.currentDatabase : currentDatabase.label;
     const labels = config.metricType === 'LABELED_VALUE' ? labelsIndex : undefined;
+    const isRelation = ['ServiceRelation', 'ServiceInstanceRelation', 'EndpointRelation'].includes(config.entityType);
     const variablesList = metricNames.map((name: string) => {
       let variables = {} as any;
 
@@ -131,13 +201,21 @@ const actions: ActionTree<State, any> = {
               entity: {
                 scope: normal ? config.entityType : 'Service',
                 serviceName,
-                serviceInstanceName: config.entityType === 'ServiceInstance' ? currentInstanceId : undefined,
-                endpointName: config.entityType === 'Endpoint' ? currentEndpointId : undefined,
+                serviceInstanceName: config.entityType.includes('ServiceInstance') ? currentInstanceId : undefined,
+                endpointName: config.entityType.includes('Endpoint') ? currentEndpointId : undefined,
                 normal,
-                // destNormal: normal,
-                // destServiceName: '',
-                // destServiceInstanceName: '',
-                // destEndpointName: '',
+                destNormal: isRelation ? normal : undefined,
+                destServiceName: isRelation ? destService.label : undefined,
+                destServiceInstanceName: isRelation
+                  ? config.entityType === 'ServiceInstanceRelation'
+                    ? destInstance.label
+                    : undefined
+                  : undefined,
+                destEndpointName: isRelation
+                  ? config.entityType === 'EndpointRelation'
+                    ? destEndpoint.label
+                    : undefined
+                  : undefined,
               },
             },
             labels,
diff --git a/src/store/modules/dashboard/mutation-types.ts b/src/store/modules/dashboard/mutation-types.ts
index eef9b1c..a526130 100644
--- a/src/store/modules/dashboard/mutation-types.ts
+++ b/src/store/modules/dashboard/mutation-types.ts
@@ -42,6 +42,9 @@ export const SET_ALL_INSTANCE_EVENTS = 'SET_ALL_INSTANCE_EVENTS';
 export const SET_EVENTS_PAGE_TYPE = 'SET_EVENTS_PAGE_TYPE';
 export const SET_CURRENT_SERIES_TYPE = 'SET_CURRENT_SERIES_TYPE';
 export const SET_CLEAR_SELECTED_EVENTS = 'SET_CLEAR_SELECTED_EVENTS';
+export const SET_SERVICE_DEPENDENCY = 'SET_SERVICE_DEPENDENCY';
+export const SET_SERVICE_INSTANCE_DEPENDENCY = 'SET_SERVICE_INSTANCE_DEPENDENCY';
+export const SET_ENDPOINT_DEPENDENCY = 'SET_ENDPOINT_DEPENDENCY';
 
 // comp
 export const SET_CURRENT_GROUP = 'SET_CURRENT_GROUP';
diff --git a/src/store/modules/global/selectors.ts b/src/store/modules/global/selectors.ts
index 72832f2..605317f 100644
--- a/src/store/modules/global/selectors.ts
+++ b/src/store/modules/global/selectors.ts
@@ -20,7 +20,7 @@ import * as types from '../dashboard/mutation-types';
 import { AxiosResponse } from 'axios';
 import graph from '@/graph';
 import { Duration, DurationTime, Option } from '@/types/global';
-import { PageTypes } from '@/constants/constant';
+import { PageTypes, TopologyType } from '@/constants/constant';
 
 const EntityType = ['Service', 'ServiceInstance', 'Endpoint'];
 export interface State {
@@ -34,10 +34,11 @@ export interface State {
   currentInstance: Option;
   updateDashboard: { key: string; label?: string | undefined };
   pageType: string;
+  destService: Option;
+  destInstance: Option;
+  destEndpoint: Option;
 }
 
-const LOG = 'Log';
-
 const initState: State = {
   services: [],
   currentService: { key: '', label: '' },
@@ -49,17 +50,20 @@ const initState: State = {
   currentDatabase: { key: '', label: '' },
   updateDashboard: { key: '' },
   pageType: '',
+  destService: { key: '', label: '' },
+  destInstance: { key: '', label: '' },
+  destEndpoint: { key: '', label: '' },
 };
 
 // mutations
 const mutations: MutationTree<State> = {
   [types.SET_SERVICES](state: State, data: Option[]) {
-    state.services = state.pageType === LOG ? [{ label: 'All', key: '' }, ...data] : data;
+    state.services = state.pageType === PageTypes.LOG ? [{ label: 'All', key: '' }, ...data] : data;
     state.currentService = state.services[0] || {};
   },
   [types.SET_CURRENT_SERVICE](state: State, service: Option) {
     state.currentService = service;
-    if (state.pageType !== PageTypes.DASHBOARD) {
+    if (state.pageType === PageTypes.LOG) {
       state.updateDashboard = service;
     }
   },
@@ -69,7 +73,7 @@ const mutations: MutationTree<State> = {
   },
 
   [types.SET_ENDPOINTS](state: State, data: Option[]) {
-    state.endpoints = state.pageType === LOG ? [{ label: 'All', key: '' }, ...data] : data;
+    state.endpoints = state.pageType === PageTypes.LOG ? [{ label: 'All', key: '' }, ...data] : data;
     if (!state.endpoints.length) {
       state.currentEndpoint = { key: '', label: '' };
       return;
@@ -81,7 +85,7 @@ const mutations: MutationTree<State> = {
     state.updateDashboard = endpoint;
   },
   [types.SET_INSTANCES](state: State, data: Option[]) {
-    state.instances = state.pageType === LOG ? [{ label: 'All', key: '' }, ...data] : data;
+    state.instances = state.pageType === PageTypes.LOG ? [{ label: 'All', key: '' }, ...data] : data;
     if (!state.instances.length) {
       state.currentInstance = { key: '', label: '' };
       return;
@@ -107,6 +111,25 @@ const mutations: MutationTree<State> = {
   [types.SET_PAGE_TYPE](state: State, type: string) {
     state.pageType = type;
   },
+  [types.SET_SERVICE_DEPENDENCY](state: State, call: any) {
+    state.currentService = { key: call.source.id, label: call.source.name };
+    state.destService = { key: call.target.id, label: call.target.name };
+    state.updateDashboard = { key: TopologyType.TOPOLOGY_SERVICE_DEPENDENCY + call.id };
+  },
+  [types.SET_SERVICE_INSTANCE_DEPENDENCY](state: State, call: any) {
+    state.currentService = { key: call.sourceObj.serviceId, label: call.sourceObj.serviceName };
+    state.currentInstance = { key: call.sourceObj.id, label: call.sourceObj.name };
+    state.destService = { key: call.targetObj.serviceId, label: call.targetObj.serviceName };
+    state.destInstance = { key: call.targetObj.id, label: call.targetObj.name };
+    state.updateDashboard = { key: TopologyType.TOPOLOGY_SERVICE_INSTANCE_DEPENDENCY + call.id };
+  },
+  [types.SET_ENDPOINT_DEPENDENCY](state: State, call: any) {
+    state.currentService = { key: call.serviceId, label: call.serviceName };
+    state.currentEndpoint = { key: call.endpointId, label: call.endpointName };
+    state.destService = { key: call.destServiceId, label: call.destServiceName };
+    state.destEndpoint = { key: call.destEndpointId, label: call.destEndpointName };
+    state.updateDashboard = { key: TopologyType.TOPOLOGY_ENDPOINT_DEPENDENCY + call.id };
+  },
 };
 
 // actions
diff --git a/src/store/modules/topology/index.ts b/src/store/modules/topology/index.ts
index 5de64af..2288f39 100644
--- a/src/store/modules/topology/index.ts
+++ b/src/store/modules/topology/index.ts
@@ -20,47 +20,10 @@ import graph from '@/graph';
 import * as types from '../../mutation-types';
 import axios, { AxiosPromise, AxiosResponse } from 'axios';
 import { cancelToken } from '@/utils/cancelToken';
-
-interface Option {
-  key: string;
-  label: string;
-}
-export interface Duration {
-  start: string;
-  end: string;
-  step: string;
-}
-export interface Call {
-  avgResponseTime: number;
-  cpm: number;
-  isAlert: boolean;
-  source: string | any;
-  target: string | any;
-  id: string;
-  detectPoints: string[];
-}
-interface Node {
-  apdex: number;
-  avgResponseTime: number;
-  cpm: number;
-  id: string;
-  isAlarm: boolean;
-  name: string;
-  numOfServer: number;
-  numOfServerAlarm: number;
-  numOfServiceAlarm: number;
-  sla: number;
-  type: string;
-}
-
-export interface EndpointDependencyConidition {
-  serviceName: string;
-  endpointName: string;
-  destServiceName: string;
-  destEndpointName: string;
-  duration: Duration;
-}
-
+import { Call, Node, EndpointDependencyConidition } from '@/types/topo';
+import { Duration, Option } from '@/types/global';
+import { DEFAULT, TopologyType } from '@/constants/constant';
+import { uuid } from '@/utils/uuid';
 export interface State {
   callback: any;
   calls: Call[];
@@ -71,10 +34,6 @@ export interface State {
   currentLink: any;
   current: Option;
   mode: boolean;
-  getResponseTimeTrend: number[];
-  getSLATrend: number[];
-  getThroughputTrend: number[];
-  responsePercentile: { [key: string]: number[] };
   instanceDependency: {
     calls: Call[];
     nodes: Node[];
@@ -84,20 +43,26 @@ export interface State {
     nodes: Node[];
   };
   selectedInstanceCall: Call | null;
-  instanceDependencyMetrics: { [key: string]: any };
+  selectedEndpointCall: Call | null;
   endpointDependencyMetrics: { [key: string]: any };
   currentEndpointDepth: { key: number; label: string };
-  queryInstanceMetricsType: string;
-  serviceThroughput: { Throughput: number[] };
-  serviceSLA: { SLA: number[] };
-  serviceResponseTime: { ResponseTime: number[] };
-  servicePercentile: { [key: string]: number[] };
-  serviceApdexScore: { ApdexScore: number[] };
-  topoEndpoints: any[];
-  topoInstances: any[];
+  topoEndpoints: { [key: string]: any[] };
+  topoInstances: { [key: string]: any[] };
+  topoServices: { [key: string]: any[] };
+  topoServicesDependency: { [key: string]: any[] };
+  topoServicesInstanceDependency: { [key: string]: any[] };
+  topoEndpointDependency: { [key: string]: any[] };
+  instanceDependencyMode: string;
+  editDependencyMetrics: boolean;
+  topoTemplatesType: { [key: string]: any };
 }
 
-const PercentileItem: string[] = ['p50', 'p75', 'p90', 'p95', 'p99'];
+const DefaultConfig = {
+  width: 12,
+  title: 'Title',
+  height: 250,
+  metricType: 'UNKNOWN',
+};
 
 const initState: State = {
   callback: '',
@@ -112,10 +77,6 @@ const initState: State = {
     key: 'default',
     label: 'default',
   },
-  getResponseTimeTrend: [],
-  getSLATrend: [],
-  getThroughputTrend: [],
-  responsePercentile: {},
   instanceDependency: {
     calls: [],
     nodes: [],
@@ -125,23 +86,18 @@ const initState: State = {
     nodes: [],
   },
   selectedInstanceCall: null,
-  instanceDependencyMetrics: {},
+  selectedEndpointCall: null,
   endpointDependencyMetrics: {},
   currentEndpointDepth: { key: 2, label: '2' },
-  queryInstanceMetricsType: '',
-  serviceThroughput: { Throughput: [] },
-  serviceSLA: { SLA: [] },
-  serviceResponseTime: { ResponseTime: [] },
-  servicePercentile: {
-    p50: [],
-    p75: [],
-    p90: [],
-    p95: [],
-    p99: [],
-  },
-  serviceApdexScore: { ApdexScore: [] },
-  topoEndpoints: [],
-  topoInstances: [],
+  topoEndpoints: {},
+  topoInstances: {},
+  topoServices: {},
+  topoServicesDependency: {},
+  topoServicesInstanceDependency: {},
+  instanceDependencyMode: '',
+  editDependencyMetrics: false,
+  topoEndpointDependency: {},
+  topoTemplatesType: JSON.parse(localStorage.getItem('topoTemplateTypes') || JSON.stringify({})),
 };
 
 // getters
@@ -149,9 +105,6 @@ const getters = {};
 
 // mutations
 const mutations = {
-  [types.SET_CALLBACK](state: State, data: any) {
-    state.callback = data;
-  },
   [types.SET_MODE](state: State, data: string[]) {
     state.detectPoints = data;
     const temp = state.mode ? 'SERVER' : 'CLIENT';
@@ -162,151 +115,443 @@ const mutations = {
   [types.SET_MODE_STATUS](state: State, data: boolean) {
     state.mode = data;
   },
-  [types.SET_NODE](state: State, data: any) {
+  [types.SET_INSTANCE_DEPENDENCY_MODE_STATUS](state: State, data: string) {
+    state.instanceDependencyMode = data;
+  },
+  [types.SET_NODE](state: State, data: Node) {
     state.currentNode = data;
   },
-  [types.SET_LINK](state: State, data: any) {
+  [types.SET_LINK](state: State, data: Call) {
     state.currentLink = data;
   },
-  [types.SET_TOPO](state: State, data: any) {
+  [types.SET_TOPO](state: State, data: { nodes: Node[]; calls: Call[] }) {
     state.calls = data.calls;
     state.nodes = data.nodes;
   },
   [types.SET_SELECTED_CALL](state: State, data: any) {
     state.selectedServiceCall = data;
   },
-  [types.SET_TOPO_RELATION](state: State, data: any) {
-    state.getResponseTimeTrend = data.getResponseTimeTrend
-      ? data.getResponseTimeTrend.values.map((i: any) => i.value)
-      : [];
-    state.getSLATrend = data.getSLATrend ? data.getSLATrend.values.map((i: any) => i.value) : [];
-    state.getThroughputTrend = data.getThroughputTrend ? data.getThroughputTrend.values.map((i: any) => i.value) : [];
-
-    if (!data.getPercentile) {
-      state.responsePercentile = {};
-      return;
-    }
-    data.getPercentile.forEach((item: any, index: number) => {
-      state.responsePercentile[PercentileItem[index]] = item.values.map((i: any) => i.value);
-    });
-  },
   [types.SET_INSTANCE_DEPENDENCY](state: State, data: any) {
     state.instanceDependency = data;
   },
   [types.SET_SELECTED_INSTANCE_CALL](state: State, data: Call) {
     state.selectedInstanceCall = data;
   },
-  [types.SET_INSTANCE_DEPEDENCE_METRICS](state: State, data: any) {
-    state.instanceDependencyMetrics.getResponseTimeTrend = data.getResponseTimeTrend
-      ? data.getResponseTimeTrend.values.map((i: any) => i.value)
-      : [];
-    state.instanceDependencyMetrics.getSLATrend = data.getSLATrend
-      ? data.getSLATrend.values.map((i: any) => i.value)
-      : [];
-    state.instanceDependencyMetrics.getThroughputTrend = data.getThroughputTrend
-      ? data.getThroughputTrend.values.map((i: any) => i.value)
-      : [];
-    state.instanceDependencyMetrics.percentResponse = {};
-    if (!data.getPercentile) {
-      return;
+  [types.SET_SELECTED_ENDPOINT_CALL](state: State, data: Call) {
+    state.selectedEndpointCall = data;
+  },
+  [types.SET_TOPO_ENDPOINT](state: State, data: { [key: string]: unknown[] }) {
+    state.topoEndpoints = data;
+    window.localStorage.setItem('topologyEndpoints', JSON.stringify(data));
+  },
+  [types.SET_TOPO_INSTANCE](state: State, data: { [key: string]: unknown[] }) {
+    state.topoInstances = data;
+    window.localStorage.setItem('topologyInstances', JSON.stringify(data));
+  },
+  [types.SET_TOPO_SERVICE_DEPENDENCY](state: State, data: any) {
+    state.topoServicesDependency = data;
+    localStorage.setItem('topologyServicesDependency', JSON.stringify(data));
+  },
+  [types.SET_TOPO_SERVICE_INSTANCE_DEPENDENCY](state: State, data: any) {
+    state.topoServicesInstanceDependency = data;
+    localStorage.setItem('topologyServicesInstanceDependency', JSON.stringify(data));
+  },
+  [types.SET_TOPO_ENDPOINT_DEPENDENCY](state: State, data: any) {
+    state.topoEndpointDependency = data;
+    localStorage.setItem('topologyEndpointDependency', JSON.stringify(data));
+  },
+  [types.DELETE_TOPO_ENDPOINT](state: State, id: string) {
+    const serviceTemplateType = state.topoTemplatesType[TopologyType.TOPOLOGY_ENDPOINT] || {};
+    const temps = serviceTemplateType[state.currentNode.type || DEFAULT] || [{ key: DEFAULT, label: DEFAULT }];
+    let index = -1;
+
+    for (const type of temps) {
+      index = state.topoEndpoints[type.key].findIndex((d) => d.uuid === id);
+      if (index > -1) {
+        state.topoEndpoints[type.key].splice(index, 1);
+        localStorage.setItem('topologyEndpoints', JSON.stringify(state.topoEndpoints));
+      }
+    }
+  },
+  [types.DELETE_TOPO_INSTANCE](state: State, id: string) {
+    const instanceTemplateType = state.topoTemplatesType[TopologyType.TOPOLOGY_INSTANCE] || {};
+    const temps = instanceTemplateType[state.currentNode.type || DEFAULT] || [{ key: DEFAULT, label: DEFAULT }];
+    let index = -1;
+
+    for (const type of temps) {
+      index = state.topoInstances[type.key].findIndex((d) => d.uuid === id);
+      if (index > -1) {
+        state.topoInstances[type.key].splice(index, 1);
+        window.localStorage.setItem('topologyInstances', JSON.stringify(state.topoInstances));
+      }
     }
-    data.getPercentile.forEach((item: any, index: number) => {
-      state.instanceDependencyMetrics.percentResponse[PercentileItem[index]] = item.values.map((i: any) => i.value);
-    });
   },
-  [types.SET_ENDPOINT_DEPENDENCY_METRICS](state: State, data: { [key: string]: any }) {
-    state.endpointDependencyMetrics.cpm = data.endpointRelationCpm
-      ? data.endpointRelationCpm.values.values.map((i: any) => i.value)
-      : [];
-    state.endpointDependencyMetrics.respTime = data.endpointRelationRespTime
-      ? data.endpointRelationRespTime.values.values.map((i: any) => i.value)
-      : [];
-    state.endpointDependencyMetrics.sla = data.endpointRelationSla
-      ? data.endpointRelationSla.values.values.map((i: any) => i.value)
-      : [];
-    state.endpointDependencyMetrics.percentile = {};
-    if (!data.endpointRelationPercentile) {
+  [types.DELETE_TOPO_SERVICE](state: State, id: string) {
+    const serviceTemplateType = state.topoTemplatesType[TopologyType.TOPOLOGY_SERVICE] || {};
+    const temps = serviceTemplateType[state.currentNode.type || DEFAULT] || [{ key: DEFAULT }];
+    let index = -1;
+
+    for (const type of temps) {
+      index = state.topoServices[type.key].findIndex((d) => d.uuid === id);
+      if (index > -1) {
+        state.topoServices[type.key].splice(index, 1);
+        localStorage.setItem('topologyServices', JSON.stringify(state.topoServices));
+      }
+    }
+  },
+  [types.DELETE_TOPO_SERVICE_DEPENDENCY](state: State, id: string) {
+    if (!state.selectedServiceCall) {
       return;
     }
-    for (const item of data.endpointRelationPercentile) {
-      state.endpointDependencyMetrics.percentile[PercentileItem[Number(item.label)]] = item.values.values.map(
-        (i: any) => i.value,
-      );
+    const typeCall = state.selectedServiceCall.source.type || DEFAULT;
+    const serviceDependencyTemplateType = state.topoTemplatesType[TopologyType.TOPOLOGY_SERVICE_DEPENDENCY] || {};
+    const temps =
+      serviceDependencyTemplateType[typeCall] ||
+      serviceDependencyTemplateType[DEFAULT] || [{ key: DEFAULT, label: DEFAULT }] ||
+      [];
+    const mode: any = state.mode ? 'server' : 'client';
+    let index = -1;
+
+    for (const type of temps) {
+      index = state.topoServicesDependency[type.key][mode].findIndex((d: any) => d.uuid === id);
+      if (index > -1) {
+        state.topoServicesDependency[type.key][mode].splice(index, 1);
+        localStorage.setItem('topologyServicesDependency', JSON.stringify(state.topoServicesDependency));
+      }
     }
   },
-  [types.SET_INSTANCE_DEPEDENCE_TYPE](state: State, data: string) {
-    state.queryInstanceMetricsType = data;
-  },
-  [types.SET_SERVICE_DETAIL](state: State, data: any) {
-    state.serviceApdexScore = data.serviceApdexScore
-      ? data.serviceApdexScore.values.map((i: any) => Number((i.value / 10000).toFixed(2)))
-      : [];
-    state.serviceResponseTime = data.serviceResponseTime
-      ? data.serviceResponseTime.values.map((i: any) => i.value)
-      : [];
-    state.serviceThroughput = data.serviceThroughput ? data.serviceThroughput.values.map((i: any) => i.value) : [];
-    state.serviceSLA = data.serviceSLA ? data.serviceSLA.values.map((i: any) => i.value / 100) : [];
-    if (!data.servicePercentile) {
+  [types.DELETE_TOPO_ENDPOINT_DEPENDENCY](state: State, id: string) {
+    if (!state.selectedEndpointCall) {
       return;
     }
-    data.servicePercentile.forEach((item: any, index: number) => {
-      state.servicePercentile[PercentileItem[index]] = item.values.map((i: any) => i.value);
-    });
+    const typeCall = state.selectedEndpointCall.type || DEFAULT;
+    const serviceDependencyTemplateType = state.topoTemplatesType[TopologyType.TOPOLOGY_ENDPOINT_DEPENDENCY] || {};
+    const temps = serviceDependencyTemplateType[typeCall] || [{ key: DEFAULT, label: DEFAULT }];
+    let index = -1;
+
+    for (const type of temps) {
+      index = state.topoEndpointDependency[type.key].findIndex((d) => d.uuid === id);
+      if (index > -1) {
+        state.topoEndpointDependency[type.key].splice(index, 1);
+        localStorage.setItem('topologyEndpointDependency', JSON.stringify(state.topoEndpointDependency));
+      }
+    }
   },
-  [types.SET_TOPO_ENDPOINT](state: State, data: any[]) {
-    state.topoEndpoints = data;
-    window.localStorage.setItem('topologyEndpoints', JSON.stringify(data));
+  [types.DELETE_TOPO_INSTANCE_DEPENDENCY](state: State, id: string) {
+    const { sourceObj } = state.selectedInstanceCall || ({} as any);
+    const typeCall = sourceObj.type || DEFAULT;
+    const mode: any = state.instanceDependencyMode;
+    const serviceDependencyTemplateType =
+      state.topoTemplatesType[TopologyType.TOPOLOGY_SERVICE_INSTANCE_DEPENDENCY] || {};
+    const temps = serviceDependencyTemplateType[typeCall] || [{ key: DEFAULT, label: DEFAULT }];
+    let index = -1;
+
+    for (const type of temps) {
+      index = state.topoServicesInstanceDependency[type.key][mode].findIndex((d: any) => d.uuid === id);
+      if (index > -1) {
+        state.topoServicesInstanceDependency[type.key][mode].splice(index, 1);
+        localStorage.setItem(
+          'topologyServicesInstanceDependency',
+          JSON.stringify(state.topoServicesInstanceDependency),
+        );
+      }
+    }
   },
-  [types.SET_TOPO_INSTANCE](state: State, data: any[]) {
-    state.topoInstances = data;
-    window.localStorage.setItem('topologyInstances', JSON.stringify(data));
+  [types.EDIT_TOPO_INSTANCE_CONFIG](state: State, params: { values: any; index: number; uuid: string }) {
+    const templateType = state.topoTemplatesType[TopologyType.TOPOLOGY_INSTANCE] || {};
+    const temps = templateType[state.currentNode.type] || [{ key: DEFAULT, label: DEFAULT }];
+    let index = -1;
+
+    for (const type of temps) {
+      index = state.topoInstances[type.key].findIndex((d) => d.uuid === params.uuid);
+      if (index > -1) {
+        state.topoInstances[type.key][params.index] = {
+          ...state.topoInstances[type.key][params.index],
+          ...params.values,
+        };
+        localStorage.setItem('topologyInstances', JSON.stringify(state.topoInstances));
+      }
+    }
   },
-  [types.EDIT_TOPO_INSTANCE_CONFIG](state: State, params: { values: any; index: number }) {
-    state.topoInstances[params.index] = { ...state.topoInstances[params.index], ...params.values };
-    window.localStorage.setItem('topologyInstances', JSON.stringify(state.topoInstances));
+  [types.EDIT_TOPO_ENDPOINT_CONFIG](state: State, params: { values: any; index: number; uuid: string }) {
+    const templateType = state.topoTemplatesType[TopologyType.TOPOLOGY_INSTANCE] || {};
+    const temps = templateType[state.currentNode.type] || [{ key: DEFAULT, label: DEFAULT }];
+    let index = -1;
+
+    for (const type of temps) {
+      index = state.topoEndpoints[type.key].findIndex((d) => d.uuid === params.uuid);
+      if (index > -1) {
+        state.topoEndpoints[type.key][params.index] = {
+          ...state.topoEndpoints[type.key][params.index],
+          ...params.values,
+        };
+        localStorage.setItem('topologyEndpoints', JSON.stringify(state.topoEndpoints));
+      }
+    }
   },
-  [types.EDIT_TOPO_ENDPOINT_CONFIG](state: State, params: { values: any; index: number }) {
-    state.topoEndpoints[params.index] = { ...state.topoEndpoints[params.index], ...params.values };
-    window.localStorage.setItem('topologyEndpoints', JSON.stringify(state.topoEndpoints));
+  [types.EDIT_TOPO_SERVICE_CONFIG](state: State, params: { values: any; index: number; uuid: string }) {
+    const serviceTemplateType = state.topoTemplatesType[TopologyType.TOPOLOGY_SERVICE] || {};
+    const temps = serviceTemplateType[state.currentNode.type] || [{ key: DEFAULT }];
+    let index = -1;
+
+    for (const type of temps) {
+      index = state.topoServices[type.key].findIndex((d) => d.uuid === params.uuid);
+      if (index > -1) {
+        state.topoServices[type.key][params.index] = {
+          ...state.topoServices[type.key][params.index],
+          ...params.values,
+        };
+        window.localStorage.setItem('topologyServices', JSON.stringify(state.topoServices));
+      }
+    }
   },
-  [types.DELETE_TOPO_ENDPOINT](state: State, index: number) {
-    state.topoEndpoints.splice(index, 1);
-    window.localStorage.setItem('topologyEndpoints', JSON.stringify(state.topoEndpoints));
+  [types.EDIT_ENDPOINT_DEPENDENCY_CONFIG](state: State, params: { values: any; index: number; uuid: string }) {
+    if (!state.selectedEndpointCall) {
+      return;
+    }
+    const endpointTemplateType = state.topoTemplatesType[TopologyType.TOPOLOGY_ENDPOINT_DEPENDENCY] || {};
+    const temps = endpointTemplateType[state.selectedEndpointCall.type || DEFAULT] || [
+      { key: DEFAULT, label: DEFAULT },
+    ];
+    let index = -1;
+
+    for (const type of temps) {
+      index = state.topoEndpointDependency[type.key].findIndex((d) => d.uuid === params.uuid);
+      if (index > -1) {
+        state.topoEndpointDependency[type.key][index] = {
+          ...state.topoEndpointDependency[type.key][index],
+          ...params.values,
+        };
+        localStorage.setItem('topologyEndpointDependency', JSON.stringify(state.topoEndpointDependency));
+      }
+    }
   },
-  [types.DELETE_TOPO_INSTANCE](state: State, index: number) {
-    state.topoInstances.splice(index, 1);
-    window.localStorage.setItem('topologyInstances', JSON.stringify(state.topoInstances));
+  [types.EDIT_TOPO_SERVICE_DEPENDENCY_CONFIG](state: State, params: { values: any; index: number; uuid: string }) {
+    const { source } = state.currentLink;
+    const mode: any = state.mode ? 'server' : 'client';
+    const serviceEndpointTemplateType = state.topoTemplatesType[TopologyType.TOPOLOGY_SERVICE_DEPENDENCY] || {};
+    const temps = serviceEndpointTemplateType[source.type || DEFAULT] || [{ key: DEFAULT, label: DEFAULT }];
+    let index = -1;
+
+    for (const type of temps) {
+      index = state.topoServicesDependency[type.key][mode].findIndex((d: any) => d.uuid === params.uuid);
+      if (index > -1) {
+        state.topoServicesDependency[type.key][mode][params.index] = {
+          ...state.topoServicesDependency[type.key][mode][params.index],
+          ...params.values,
+        };
+        localStorage.setItem('topologyServicesDependency', JSON.stringify(state.topoServicesDependency));
+      }
+    }
+  },
+  [types.EDIT_TOPO_INSTANCE_DEPENDENCY_CONFIG](state: State, params: { values: any; index: number; uuid: string }) {
+    const { sourceObj } = state.selectedInstanceCall || ({} as any);
+    const typeCall = sourceObj.type || DEFAULT;
+    const mode: any = state.instanceDependencyMode;
+
+    if (!(state.topoServicesInstanceDependency[typeCall] && state.topoServicesInstanceDependency[typeCall][mode])) {
+      return;
+    }
+    const endpointTemplateType = state.topoTemplatesType[TopologyType.TOPOLOGY_SERVICE_INSTANCE_DEPENDENCY] || {};
+    const temps = endpointTemplateType[typeCall] || [{ key: DEFAULT, label: DEFAULT }];
+    let index = -1;
+
+    for (const type of temps) {
+      index = state.topoServicesInstanceDependency[type.key][mode].findIndex((d: any) => d.uuid === params.uuid);
+      if (index > -1) {
+        state.topoServicesInstanceDependency[type.key][mode][params.index] = {
+          ...state.topoServicesInstanceDependency[type.key][mode][params.index],
+          ...params.values,
+        };
+        localStorage.setItem(
+          'topologyServicesInstanceDependency',
+          JSON.stringify(state.topoServicesInstanceDependency),
+        );
+      }
+    }
   },
   [types.ADD_TOPO_INSTANCE_COMP](state: State) {
+    const serviceTemplateType = state.topoTemplatesType[TopologyType.TOPOLOGY_SERVICE] || {};
+    const temps = serviceTemplateType[state.currentNode.type] || [{ key: DEFAULT }];
+    const type = temps[temps.length - 1 || 0].key;
     const comp = {
+      ...DefaultConfig,
       width: 3,
-      title: 'Title',
-      height: 350,
+      uuid: uuid(),
       entityType: 'ServiceInstance',
-      independentSelector: false,
-      metricType: 'UNKNOWN',
     };
-    state.topoInstances.push(comp);
+
+    state.topoInstances[type].push(comp);
     window.localStorage.setItem('topologyInstances', JSON.stringify(state.topoInstances));
   },
   [types.ADD_TOPO_ENDPOINT_COMP](state: State) {
+    const serviceTemplateType = state.topoTemplatesType[TopologyType.TOPOLOGY_SERVICE] || {};
+    const temps = serviceTemplateType[state.currentNode.type] || [{ key: DEFAULT }];
+    const type = temps[temps.length - 1 || 0].key;
     const comp = {
+      ...DefaultConfig,
       width: 3,
-      title: 'Title',
-      height: 350,
+      uuid: uuid(),
       entityType: 'Endpoint',
-      independentSelector: false,
-      metricType: 'UNKNOWN',
     };
-    state.topoEndpoints.push(comp);
+
+    state.topoEndpoints[type].push(comp);
     window.localStorage.setItem('topologyEndpoints', JSON.stringify(state.topoEndpoints));
   },
+  [types.ADD_TOPO_SERVICE_COMP](state: State) {
+    const serviceTemplateType = state.topoTemplatesType[TopologyType.TOPOLOGY_SERVICE] || {};
+    const temps = serviceTemplateType[state.currentNode.type] || [{ key: DEFAULT }];
+    const type = temps[temps.length - 1 || 0].key;
+    const comp = {
+      ...DefaultConfig,
+      entityType: 'Service',
+      uuid: uuid(),
+    };
+    state.topoServices[type].push(comp);
+    window.localStorage.setItem('topologyServices', JSON.stringify(state.topoServices));
+  },
+  [types.ADD_TOPO_ENDPOINT_DEPENDENCY_COMP](state: State) {
+    if (!state.selectedEndpointCall) {
+      return;
+    }
+    const callType = state.selectedEndpointCall.type || DEFAULT;
+    const endpointDependencyTemplateType = state.topoTemplatesType[TopologyType.TOPOLOGY_ENDPOINT_DEPENDENCY] || {};
+    const temps = endpointDependencyTemplateType[callType] || [{ key: DEFAULT, label: DEFAULT }];
+    const type = temps[temps.length - 1 || 0].key;
+    const comp = {
+      ...DefaultConfig,
+      height: 200,
+      width: 3,
+      uuid: uuid(),
+      entityType: 'EndpointRelation',
+    };
+
+    state.topoEndpointDependency[type].push(comp);
+    localStorage.setItem('topologyEndpointDependency', JSON.stringify(state.topoEndpointDependency));
+  },
+  [types.ADD_TOPO_SERVICE_DEPENDENCY_COMP](state: State) {
+    if (!state.selectedServiceCall) {
+      return;
+    }
+    const sourceType = state.selectedServiceCall.source.type || DEFAULT;
+    const serviceDependencyTemplateType = state.topoTemplatesType[TopologyType.TOPOLOGY_SERVICE_DEPENDENCY] || {};
+    const temps = serviceDependencyTemplateType[sourceType] || serviceDependencyTemplateType[DEFAULT] || [];
+    const type = temps[temps.length - 1 || 0] ? temps[temps.length - 1 || 0].key : [DEFAULT];
+    const mode: any = state.mode ? 'server' : 'client';
+
+    if (!(state.topoServicesDependency[type] && state.topoServicesDependency[type][mode])) {
+      return;
+    }
+    const comp = {
+      ...DefaultConfig,
+      uuid: uuid(),
+      entityType: 'ServiceRelation',
+    };
+    state.topoServicesDependency[type][mode].push(comp);
+    window.localStorage.setItem('topologyServicesDependency', JSON.stringify(state.topoServicesDependency));
+  },
+  [types.ADD_TOPO_INSTANCE_DEPENDENCY_COMP](state: State) {
+    if (!state.selectedInstanceCall) {
+      return;
+    }
+    const sourceType = state.selectedInstanceCall.sourceObj.type || DEFAULT;
+    const serviceDependencyTemplateType =
+      state.topoTemplatesType[TopologyType.TOPOLOGY_SERVICE_INSTANCE_DEPENDENCY] || {};
+    const temps = serviceDependencyTemplateType[sourceType] || [{ key: DEFAULT, label: DEFAULT }];
+    const type = temps[temps.length - 1 || 0].key;
+    const mode: any = state.instanceDependencyMode;
+
+    if (!(state.topoServicesInstanceDependency[type] && state.topoServicesInstanceDependency[type][mode])) {
+      return;
+    }
+    const comp = {
+      ...DefaultConfig,
+      uuid: uuid(),
+      entityType: 'ServiceInstanceRelation',
+    };
+    state.topoServicesInstanceDependency[type][mode].push(comp);
+    localStorage.setItem('topologyServicesInstanceDependency', JSON.stringify(state.topoServicesInstanceDependency));
+  },
   [types.SET_ENDPOINT_DEPENDENCY](state: State, data: { calls: Call[]; nodes: Node[] }) {
     state.endpointDependency = data;
+    state.selectedEndpointCall = null;
   },
   [types.SET_ENDPOINT_DEPTH](state: State, data: { key: number; label: string }) {
     state.currentEndpointDepth = data;
   },
+  [types.SET_TOPO_SERVICE](state: State, data: any) {
+    state.topoServices = data;
+    localStorage.setItem('topologyServices', JSON.stringify(data));
+  },
+  [types.EDIT_DEPENDENCY_METRICS](state: State, isEdit: boolean) {
+    state.editDependencyMetrics = isEdit;
+  },
+  [types.IMPORT_TREE_SERVICE](state: State, data: any) {
+    const keys = Object.keys(data);
+
+    for (const key of keys) {
+      if (state.topoServices[key]) {
+        state.topoServices[key].push(...data[key]);
+      } else {
+        state.topoServices[key] = data[key];
+      }
+    }
+    localStorage.setItem('topologyServices', JSON.stringify(state.topoServices));
+  },
+  [types.IMPORT_TREE_SERVICE_DEPENDENCY](state: State, data: any) {
+    const keys = Object.keys(data);
+    const modes: any = ['server', 'client'];
+
+    for (const key of keys) {
+      if (state.topoServicesDependency[key]) {
+        for (const mode of modes) {
+          if (state.topoServicesDependency[key][mode]) {
+            state.topoServicesDependency[key][mode].push(...data[key][mode]);
+          } else {
+            state.topoServicesDependency[key][mode] = data[key][mode];
+          }
+        }
+      } else {
+        state.topoServicesDependency[key] = data[key];
+      }
+    }
+    localStorage.setItem('topologyServicesDependency', JSON.stringify(state.topoServicesDependency));
+  },
+  [types.IMPORT_TREE_ENDPOINT_DEPENDENCY](state: State, data: any) {
+    const keys = Object.keys(data);
+
+    for (const key of keys) {
+      if (state.topoEndpointDependency[key]) {
+        state.topoEndpointDependency[key].push(...data[key]);
+      } else {
+        state.topoEndpointDependency[key] = data[key];
+      }
+    }
+    localStorage.setItem('topologyEndpointDependency', JSON.stringify(state.topoEndpointDependency));
+  },
+  [types.IMPORT_TREE_INSTANCE_DEPENDENCY](state: State, data: any) {
+    const keys = Object.keys(data);
+    const modes: any = ['server', 'client'];
+
+    for (const key of keys) {
+      if (state.topoServicesInstanceDependency[key]) {
+        for (const mode of modes) {
+          if (state.topoServicesInstanceDependency[key][mode]) {
+            state.topoServicesInstanceDependency[key][mode].push(...data[key][mode]);
+          } else {
+            state.topoServicesInstanceDependency[key][mode] = data[key][mode];
+          }
+        }
+      } else {
+        state.topoServicesInstanceDependency[key] = data[key];
+      }
+    }
+    localStorage.setItem('topologyServicesInstanceDependency', JSON.stringify(state.topoServicesInstanceDependency));
+  },
+  [types.UPDATE_TOPO_TEMPLATE_TYPES](state: State, data: any) {
+    state.topoTemplatesType = data;
+    localStorage.setItem('topoTemplateTypes', JSON.stringify(data));
+  },
 };
 
 // actions
@@ -340,69 +585,8 @@ const actions: ActionTree<State, any> = {
     context.commit(types.SET_TOPO, { calls: [], nodes: [] });
   },
   CLEAR_TOPO_INFO(context: { commit: Commit; state: State }) {
-    context.commit(types.SET_TOPO_RELATION, {});
     context.commit(types.SET_SELECTED_CALL, null);
   },
-  GET_INSTANCE_DEPENDENCY_METRICS(
-    context: { commit: Commit; state: State; dispatch: Dispatch; getters: any },
-    params: any,
-  ) {
-    if (params.mode === 'SERVER') {
-      params.queryType = 'queryTopoInstanceServerInfo';
-      context.dispatch('INSTANCE_RELATION_INFO', params);
-    }
-    if (params.mode === 'CLIENT') {
-      params.queryType = 'queryTopoInstanceClientInfo';
-      context.dispatch('INSTANCE_RELATION_INFO', params);
-    }
-  },
-  GET_TOPO_SERVICE_INFO(context: { commit: Commit; state: State }, params: { id: string; duration: Duration }) {
-    if (!params.id) {
-      return;
-    }
-    return graph
-      .query('queryTopoServiceInfo')
-      .params({
-        id: params.id,
-        duration: params.duration,
-      })
-      .then((res: AxiosResponse) => {
-        if (!res.data.data) {
-          return;
-        }
-        context.commit('SET_TOPO_RELATION', res.data.data);
-        context.commit(types.SET_SELECTED_CALL, params);
-      });
-  },
-  GET_TOPO_CLIENT_INFO(context: { commit: Commit; state: State }, params: any) {
-    return graph
-      .query('queryTopoClientInfo')
-      .params(params)
-      .then((res: AxiosResponse) => {
-        if (!res.data.data) {
-          return;
-        }
-        context.commit('SET_TOPO_RELATION', res.data.data);
-        context.commit(types.SET_SELECTED_CALL, params);
-      });
-  },
-  GET_TOPO_SERVICE_DETAIL(
-    context: { commit: Commit; state: State },
-    params: { serviceId: string; duration: Duration },
-  ) {
-    return graph
-      .query('queryTopoServiceDetail')
-      .params({
-        serviceId: params.serviceId,
-        duration: params.duration,
-      })
-      .then((res: AxiosResponse) => {
-        if (!res.data.data) {
-          return;
-        }
-        context.commit('SET_SERVICE_DETAIL', res.data.data);
-      });
-  },
   GET_TOPO(context: { commit: Commit; state: State }, params: any) {
     let query = 'queryTopo';
     if (params.serviceId) {
@@ -422,8 +606,8 @@ const actions: ActionTree<State, any> = {
         const calls = res.data.data.topo.calls;
         const nodes = res.data.data.topo.nodes;
         const ids = nodes.map((i: any) => i.id);
-        const idsC = calls.filter((i: any) => i.detectPoints.indexOf('CLIENT') !== -1).map((b: any) => b.id);
-        const idsS = calls.filter((i: any) => i.detectPoints.indexOf('CLIENT') === -1).map((b: any) => b.id);
+        const idsC = calls.filter((i: any) => i.detectPoints.includes('CLIENT')).map((b: any) => b.id);
+        const idsS = calls.filter((i: any) => i.detectPoints.includes('CLIENT')).map((b: any) => b.id);
         return graph
           .query('queryTopoInfo')
           .params({ ...params, ids, idsC, idsS })
@@ -580,11 +764,16 @@ const actions: ActionTree<State, any> = {
                 source = node;
                 call.serviceName = node.serviceName;
                 call.endpointName = node.name;
+                call.serviceId = node.serviceId;
+                call.endpointId = node.id;
+                call.type = node.type;
               }
               if (node.id === call.target) {
                 target = node;
                 call.destServiceName = node.serviceName;
+                call.destServiceId = node.serviceId;
                 call.destEndpointName = node.name;
+                call.destEndpointId = node.id;
               }
             }
             return `cpm_${index}: readMetricsValue(condition: {
@@ -702,40 +891,20 @@ const actions: ActionTree<State, any> = {
             nodes: res.data.data.topo.nodes,
             calls: [...values[0], ...values[1]],
           };
+          for (const call of instanceDependency.calls) {
+            for (const node of instanceDependency.nodes) {
+              if (call.source === node.id) {
+                call.sourceObj = node;
+              }
+              if (call.target === node.id) {
+                call.targetObj = node;
+              }
+            }
+          }
           context.commit(types.SET_INSTANCE_DEPENDENCY, instanceDependency);
         });
       });
   },
-  INSTANCE_RELATION_INFO(
-    context: { commit: Commit; state: State },
-    params: Call & { mode: string; queryType: string; durationTime: Duration },
-  ) {
-    graph
-      .query(params.queryType)
-      .params({
-        id: params.id,
-        duration: params.durationTime,
-      })
-      .then((res: AxiosResponse) => {
-        if (!(res.data && res.data.data)) {
-          return;
-        }
-        context.commit(types.SET_SELECTED_INSTANCE_CALL, params);
-        context.commit(types.SET_INSTANCE_DEPEDENCE_TYPE, params.mode);
-        context.commit(types.SET_INSTANCE_DEPEDENCE_METRICS, res.data.data);
-      });
-  },
-  GET_ENDPOINT_DEPENDENCY_METRICS(context: { commit: Commit; state: State }, params: EndpointDependencyConidition) {
-    return graph
-      .query('queryTopoEndpointDependencyMetrics')
-      .params(params)
-      .then((res: AxiosResponse) => {
-        if (!(res.data && res.data.data)) {
-          return;
-        }
-        context.commit(types.SET_ENDPOINT_DEPENDENCY_METRICS, res.data.data);
-      });
-  },
 };
 
 export default {
diff --git a/src/store/modules/trace/index.ts b/src/store/modules/trace/index.ts
index 4e9a009..2fbdd3d 100644
--- a/src/store/modules/trace/index.ts
+++ b/src/store/modules/trace/index.ts
@@ -18,7 +18,7 @@
 import graph from '@/graph';
 import * as types from '@/store/mutation-types';
 import { Option } from '@/types/global';
-import { Span, Trace } from '@/types/topo';
+import { Span, Trace } from '@/types/trace';
 import { AxiosResponse } from 'axios';
 import { ActionTree, Commit, Dispatch, MutationTree } from 'vuex';
 
@@ -100,7 +100,7 @@ const mutations: MutationTree<State> = {
   [types.SET_TRACE_SPANS](state: State, data: Span[]): void {
     state.traceSpans = data;
   },
-  [types.SET_CURRENT_TRACE](state: State, data: Span): void {
+  [types.SET_CURRENT_TRACE](state: State, data: any): void {
     state.currentTrace = data;
   },
   [types.SET_DEFAULT_EMPTY_TRACE](state: State): void {
diff --git a/src/store/mutation-types.ts b/src/store/mutation-types.ts
index d94ad6d..c23f013 100644
--- a/src/store/mutation-types.ts
+++ b/src/store/mutation-types.ts
@@ -78,7 +78,6 @@ export const SET_TOPO = 'SET_TOPO';
 export const SET_NODE = 'SET_NODE';
 export const SET_MODE = 'SET_MODE';
 export const SET_TOPO_RELATION = 'SET_TOPO_RELATION';
-export const SET_CALLBACK = 'SET_CALLBACK';
 export const SET_MODE_STATUS = 'SET_MODE_STATUS';
 export const SET_HONEYCOMB_NODE = 'SET_HONEYCOMB_NODE';
 export const SET_SHOW_DIALOG = 'SET_SHOW_DIALOG';
@@ -87,8 +86,6 @@ export const SET_LINK = 'SET_LINK';
 export const SET_SERVICE_DETAIL = 'SET_SERVICE_DETAIL';
 export const SET_SERVICE_TOPOLOGY = 'GET_SERVICE_TOPOLOGY';
 export const SET_SELECTED_INSTANCE_CALL = 'SET_SELECTED_INSTANCE_CALL';
-export const SET_INSTANCE_DEPEDENCE_METRICS = 'SET_INSTANCE_DEPEDENCE_METRICS';
-export const SET_INSTANCE_DEPEDENCE_TYPE = 'SET_INSTANCE_DEPEDENCE_TYPE';
 export const SET_SELECTED_CALL = 'SET_SELECTED_CALL';
 export const SET_TOPO_ENDPOINT = 'SET_TOPO_ENDPOINT';
 export const SET_TOPO_INSTANCE = 'SET_TOPO_INSTANCE';
@@ -99,8 +96,31 @@ export const DELETE_TOPO_ENDPOINT = 'DELETE_TOPO_ENDPOINT';
 export const ADD_TOPO_INSTANCE_COMP = 'ADD_TOPO_INSTANCE_COMP';
 export const ADD_TOPO_ENDPOINT_COMP = 'ADD_TOPO_ENDPOINT_COMP';
 export const SET_ENDPOINT_DEPENDENCY = 'SET_ENDPOINT_DEPENDENCY';
-export const SET_ENDPOINT_DEPENDENCY_METRICS = 'SET_ENDPOINT_DEPENDENCY_METRICS';
 export const SET_ENDPOINT_DEPTH = 'SET_ENDPOINT_DEPTH';
+export const SET_TOPO_SERVICE = 'SET_TOPO_SERVICE';
+export const ADD_TOPO_SERVICE_COMP = 'ADD_TOPO_SERVICE_COMP';
+export const DELETE_TOPO_SERVICE = 'DELETE_TOPO_SERVICE';
+export const EDIT_TOPO_SERVICE_CONFIG = 'EDIT_TOPO_SERVICE_CONFIG';
+export const IMPORT_TREE_SERVICE = 'IMPORT_TREE_SERVICE';
+export const SET_TOPO_SERVICE_DEPENDENCY = 'SET_TOPO_SERVICE_DEPENDENCY';
+export const EDIT_TOPO_SERVICE_DEPENDENCY_CONFIG = 'EDIT_TOPO_SERVICE_DEPENDENCY_CONFIG';
+export const DELETE_TOPO_SERVICE_DEPENDENCY = 'DELETE_TOPO_SERVICE_DEPENDENCY';
+export const ADD_TOPO_SERVICE_DEPENDENCY_COMP = 'ADD_TOPO_SERVICE_DEPENDENCY_COMP';
+export const IMPORT_TREE_SERVICE_DEPENDENCY = 'IMPORT_TREE_SERVICE_DEPENDENCY';
+export const SET_TOPO_SERVICE_INSTANCE_DEPENDENCY = 'SET_TOPO_SERVICE_INSTANCE_DEPENDENCY';
+export const SET_INSTANCE_DEPENDENCY_MODE_STATUS = 'SET_INSTANCE_DEPENDENCY_MODE_STATUS';
+export const EDIT_DEPENDENCY_METRICS = 'EDIT_DEPENDENCY_METRICS';
+export const EDIT_TOPO_INSTANCE_DEPENDENCY_CONFIG = 'EDIT_TOPO_INSTANCE_DEPENDENCY_CONFIG';
+export const ADD_TOPO_INSTANCE_DEPENDENCY_COMP = 'ADD_TOPO_INSTANCE_DEPENDENCY_COMP';
+export const DELETE_TOPO_INSTANCE_DEPENDENCY = 'DELETE_TOPO_INSTANCE_DEPENDENCY';
+export const IMPORT_TREE_INSTANCE_DEPENDENCY = 'IMPORT_TREE_INSTANCE_DEPENDENCY';
+export const SET_TOPO_ENDPOINT_DEPENDENCY = 'SET_TOPO_ENDPOINT_DEPENDENCY';
+export const SET_SELECTED_ENDPOINT_CALL = 'SET_SELECTED_ENDPOINT_CALL';
+export const IMPORT_TREE_ENDPOINT_DEPENDENCY = 'IMPORT_TREE_ENDPOINT_DEPENDENCY';
+export const ADD_TOPO_ENDPOINT_DEPENDENCY_COMP = 'ADD_TOPO_ENDPOINT_DEPENDENCY_COMP';
+export const EDIT_ENDPOINT_DEPENDENCY_CONFIG = 'EDIT_ENDPOINT_DEPENDENCY_CONFIG';
+export const DELETE_TOPO_ENDPOINT_DEPENDENCY = 'DELETE_TOPO_ENDPOINT_DEPENDENCY';
+export const UPDATE_TOPO_TEMPLATE_TYPES = 'UPDATE_TOPO_TEMPLATE_TYPES';
 
 // profile
 export const SET_TASK_OPTIONS = 'SET_TASK_OPTIONS';
diff --git a/src/types/topo.d.ts b/src/types/topo.d.ts
index 2932ef5..863455c 100644
--- a/src/types/topo.d.ts
+++ b/src/types/topo.d.ts
@@ -14,72 +14,40 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
-export interface CompsContainer {
-  service: CompsItem[];
-  database: CompsItem[];
-  proxy: CompsItem[];
-}
-
-export interface CompsItem {
-  o: string;
-  comp: string;
-  n: string;
-  t: string;
+import { Duration } from './global';
+export interface Call {
+  avgResponseTime: number;
+  cpm: number;
+  isAlert: boolean;
+  source: string | any;
+  target: string | any;
+  id: string;
+  detectPoints: string[];
   type?: string;
-  w: number;
-}
-
-export interface CompsGroup {
+  sourceObj?: any;
+}
+export interface Node {
+  apdex: number;
+  avgResponseTime: number;
+  cpm: number;
+  id: string;
+  isAlarm: boolean;
   name: string;
-  children: CompsItem[];
-}
-
-export interface CompQuery {
-  service: Option;
-  database: Option;
-  endpoint: Option;
-  instance: Option;
-}
-
-export interface CompsTree {
-  name?: string;
+  numOfServer: number;
+  numOfServerAlarm: number;
+  numOfServiceAlarm: number;
+  sla: number;
   type: string;
-  query: CompQuery;
-  children: CompsGroup[];
-}
-
-export interface Option {
-  key: string;
-  label: string;
-}
-
-export interface Duration {
-  start: Date;
-  end: Date;
-  step: string;
-}
-
-export interface DurationTime {
-  start: string;
-  end: string;
-  step: string;
-}
-
-export interface Trace {
-  duration: number;
-  isError: boolean;
-  key: string;
-  operationNames: string[];
-  start: string;
-  traceIds: string[];
 }
 
-export interface Span {
-  duration: number;
-  isError: boolean;
-  key: string;
-  operationNames: string[];
-  start: string;
-  traceIds: string[];
+export interface EndpointDependencyConidition {
+  serviceName: string;
+  serviceId: string;
+  endpointName: string;
+  endpointId: string;
+  destServiceName: string;
+  destEndpointName: string;
+  destServiceId: string;
+  destEndpointId: string;
+  duration: Duration;
 }
diff --git a/src/views/components/dashboard/charts/chart-bar.vue b/src/views/components/dashboard/charts/chart-bar.vue
index 16dbb49..826b591 100644
--- a/src/views/components/dashboard/charts/chart-bar.vue
+++ b/src/views/components/dashboard/charts/chart-bar.vue
@@ -24,6 +24,7 @@ limitations under the License. -->
   export default class ChartBar extends Vue {
     @Prop() private data!: any;
     @Prop() private intervalTime!: any;
+    @Prop() private theme!: string;
     @Prop() private itemEvents!: Event[];
     public resize() {
       const chart: any = this.$refs.chart;
@@ -131,6 +132,9 @@ limitations under the License. -->
           top: 0,
           left: 0,
           itemWidth: 12,
+          textStyle: {
+            color: this.theme === 'dark' ? '#fff' : '#333',
+          },
         },
         grid: {
           top: keys.length === 1 ? 15 : 40,
diff --git a/src/views/components/dashboard/charts/chart-edit.vue b/src/views/components/dashboard/charts/chart-edit.vue
index f900c8e..2515b3f 100755
--- a/src/views/components/dashboard/charts/chart-edit.vue
+++ b/src/views/components/dashboard/charts/chart-edit.vue
@@ -43,7 +43,7 @@ limitations under the License. -->
           </option>
         </select>
       </div>
-      <div class="flex-h mb-5" v-show="isChartType">
+      <div class="flex-h mb-5" v-show="hasChartType">
         <div class="title grey sm">{{ $t('chartType') }}:</div>
         <select
           class="long"
@@ -73,7 +73,7 @@ limitations under the License. -->
           @change="setItemConfig({ type: 'labelsIndex', value: $event.target.value })"
         />
       </div>
-      <div class="flex-h mb-5" v-show="!isDatabase && !pageTypes.includes(type)">
+      <div class="flex-h mb-5" v-show="!noEntity">
         <div class="title grey sm">{{ $t('entityType') }}:</div>
         <select
           class="long"
@@ -164,7 +164,7 @@ limitations under the License. -->
           </option>
         </select>
       </div>
-      <div class="flex-h mb-5" v-show="!isIndependentSelector && !isBrowser">
+      <div class="flex-h mb-5" v-show="hasIndependentSelector">
         <div class="title grey sm">{{ $t('independentSelector') }}:</div>
         <select
           class="long"
@@ -319,6 +319,10 @@ limitations under the License. -->
     @Mutation('EDIT_COMP_CONFIG') private EDIT_COMP_CONFIG: any;
     @Mutation('rocketTopo/EDIT_TOPO_INSTANCE_CONFIG') private EDIT_TOPO_INSTANCE_CONFIG: any;
     @Mutation('rocketTopo/EDIT_TOPO_ENDPOINT_CONFIG') private EDIT_TOPO_ENDPOINT_CONFIG: any;
+    @Mutation('rocketTopo/EDIT_TOPO_SERVICE_CONFIG') private EDIT_TOPO_SERVICE_CONFIG: any;
+    @Mutation('rocketTopo/EDIT_TOPO_SERVICE_DEPENDENCY_CONFIG') private EDIT_TOPO_SERVICE_DEPENDENCY_CONFIG: any;
+    @Mutation('rocketTopo/EDIT_TOPO_INSTANCE_DEPENDENCY_CONFIG') private EDIT_TOPO_INSTANCE_DEPENDENCY_CONFIG: any;
+    @Mutation('rocketTopo/EDIT_ENDPOINT_DEPENDENCY_CONFIG') private EDIT_ENDPOINT_DEPENDENCY_CONFIG: any;
     @Action('GET_ITEM_SERVICES') private GET_ITEM_SERVICES: any;
     @Action('GET_ITEM_ENDPOINTS') private GET_ITEM_ENDPOINTS: any;
     @Action('GET_ITEM_INSTANCES') private GET_ITEM_INSTANCES: any;
@@ -340,35 +344,37 @@ limitations under the License. -->
     private isDatabase = false;
     private isBrowser = false;
     private isLabel = false;
-    private isIndependentSelector = false;
+    private hasIndependentSelector = false;
     private isChartSlow = false;
-    private pageTypes = [TopologyType.TOPOLOGY_ENDPOINT, TopologyType.TOPOLOGY_INSTANCE] as string[];
     private isChartType = false;
     private ChartTable = 'ChartTable';
+    private noEntity = false;
 
-    private created() {
+    private beforeMount() {
       this.itemConfig = this.item;
       this.initConfig();
-      if (!this.itemConfig.independentSelector || this.pageTypes.includes(this.type)) {
-        return;
+      if (this.itemConfig.independentSelector) {
+        this.setItemServices();
       }
-      this.setItemServices();
     }
 
     private initConfig() {
-      this.isDatabase = this.pageTypes.includes(this.type)
-        ? false
-        : this.rocketComps.tree[this.rocketComps.group].type === DASHBOARDTYPE.DATABASE
-        ? true
-        : false;
-      this.isBrowser = this.rocketComps.tree[this.rocketComps.group].type === DASHBOARDTYPE.BROWSER;
+      const dashboardComps = this.rocketComps.tree[this.rocketComps.group] || {};
+      const topoPageTypes = [
+        TopologyType.TOPOLOGY_SERVICE,
+        TopologyType.TOPOLOGY_SERVICE_DEPENDENCY,
+        TopologyType.TOPOLOGY_SERVICE_INSTANCE_DEPENDENCY,
+      ] as string[];
+
+      this.noEntity = topoPageTypes.includes(this.type);
+      this.isDatabase = dashboardComps.type === DASHBOARDTYPE.DATABASE;
+      this.isBrowser = dashboardComps.type === DASHBOARDTYPE.BROWSER;
       if (this.isBrowser) {
         this.EntityType = BrowserEntityType;
       }
       this.queryMetricTypesList = QueryMetricTypes[this.item.metricType] || [];
-      this.isLabel = this.itemConfig.metricType === MetricsType.LABELED_VALUE ? true : false;
-      this.isIndependentSelector =
-        this.rocketComps.tree[this.rocketComps.group].type === 'metric' || this.pageTypes.includes(this.type);
+      this.isLabel = this.itemConfig.metricType === MetricsType.LABELED_VALUE;
+      this.hasIndependentSelector = dashboardComps.type === 'metric';
       this.chartTypeOptions =
         this.itemConfig.queryMetricType === 'readMetricsValue' ? ReadValueChartType : ChartTypeOptions;
       this.isChartSlow = ['sortMetrics', 'readSampledRecords'].includes(this.itemConfig.queryMetricType);
@@ -377,6 +383,28 @@ limitations under the License. -->
       }
     }
 
+    private editComponentConfig(params: { index: number; values: unknown }) {
+      const data = {
+        ...params,
+        uuid: this.itemConfig.uuid,
+      };
+      if (this.type === TopologyType.TOPOLOGY_SERVICE) {
+        this.EDIT_TOPO_SERVICE_CONFIG(data);
+      } else if (this.type === TopologyType.TOPOLOGY_ENDPOINT) {
+        this.EDIT_TOPO_ENDPOINT_CONFIG(data);
+      } else if (this.type === TopologyType.TOPOLOGY_INSTANCE) {
+        this.EDIT_TOPO_INSTANCE_CONFIG(data);
+      } else if (this.type === TopologyType.TOPOLOGY_SERVICE_DEPENDENCY) {
+        this.EDIT_TOPO_SERVICE_DEPENDENCY_CONFIG(data);
+      } else if (this.type === TopologyType.TOPOLOGY_SERVICE_INSTANCE_DEPENDENCY) {
+        this.EDIT_TOPO_INSTANCE_DEPENDENCY_CONFIG(data);
+      } else if (this.type === TopologyType.TOPOLOGY_ENDPOINT_DEPENDENCY) {
+        this.EDIT_ENDPOINT_DEPENDENCY_CONFIG(data);
+      } else {
+        this.EDIT_COMP_CONFIG(params);
+      }
+    }
+
     private setItemConfig(params: { type: string; value: string }) {
       this.itemConfig[params.type] = params.value;
       const types = ['endpointsKey', 'instancesKey', 'currentService'];
@@ -411,18 +439,18 @@ limitations under the License. -->
       }
       if (params.type === 'independentSelector' || params.type === 'parentService') {
         this.itemConfig[params.type] = params.value === 'true' ? true : false;
-        if (this.type === this.pageTypes[0]) {
-          this.EDIT_TOPO_ENDPOINT_CONFIG({
+        if (this.type === TopologyType.TOPOLOGY_ENDPOINT) {
+          this.editComponentConfig({
             index: this.index,
             values: { [params.type]: this.itemConfig[params.type] },
           });
-        } else if (this.type === this.pageTypes[1]) {
-          this.EDIT_TOPO_INSTANCE_CONFIG({
+        } else if (this.type === TopologyType.TOPOLOGY_INSTANCE) {
+          this.editComponentConfig({
             index: this.index,
             values: { [params.type]: this.itemConfig[params.type] },
           });
         } else {
-          this.EDIT_COMP_CONFIG({ index: this.index, values: { [params.type]: this.itemConfig[params.type] } });
+          this.editComponentConfig({ index: this.index, values: { [params.type]: this.itemConfig[params.type] } });
         }
         return;
       }
@@ -430,18 +458,18 @@ limitations under the License. -->
         this.updateAggregation(params);
         return;
       }
-      if (this.type === this.pageTypes[0]) {
-        this.EDIT_TOPO_ENDPOINT_CONFIG({
+      if (this.type === TopologyType.TOPOLOGY_ENDPOINT) {
+        this.editComponentConfig({
           index: this.index,
           values: { [params.type]: params.value },
         });
-      } else if (this.type === this.pageTypes[1]) {
-        this.EDIT_TOPO_INSTANCE_CONFIG({
+      } else if (this.type === TopologyType.TOPOLOGY_INSTANCE) {
+        this.editComponentConfig({
           index: this.index,
           values: { [params.type]: params.value },
         });
       } else {
-        this.EDIT_COMP_CONFIG({ index: this.index, values: { [params.type]: params.value } });
+        this.editComponentConfig({ index: this.index, values: { [params.type]: params.value } });
       }
     }
 
@@ -462,6 +490,7 @@ limitations under the License. -->
         this.$emit('updateStatus', 'metricType', typeOfMetrics);
         this.queryMetricTypesList = QueryMetricTypes[typeOfMetrics] || [];
         this.itemConfig.queryMetricType = this.queryMetricTypesList[0] && this.queryMetricTypesList[0].value;
+        this.chartTypeOptions = ReadValueChartType;
         this.hasChartType();
         this.isLabel = typeOfMetrics === MetricsType.LABELED_VALUE ? true : false;
         const values = {
@@ -470,18 +499,18 @@ limitations under the License. -->
           chartType: MetricChartType[this.itemConfig.queryMetricType],
           metricName: params.value,
         };
-        if (this.type === this.pageTypes[0]) {
-          this.EDIT_TOPO_ENDPOINT_CONFIG({
+        if (this.type === TopologyType.TOPOLOGY_ENDPOINT) {
+          this.editComponentConfig({
             index: this.index,
             values,
           });
-        } else if (this.type === this.pageTypes[1]) {
-          this.EDIT_TOPO_INSTANCE_CONFIG({
+        } else if (this.type === TopologyType.TOPOLOGY_INSTANCE) {
+          this.editComponentConfig({
             index: this.index,
             values,
           });
         } else {
-          this.EDIT_COMP_CONFIG({
+          this.editComponentConfig({
             index: this.index,
             values,
           });
@@ -502,7 +531,7 @@ limitations under the License. -->
         ...this.itemConfig,
         ...values,
       };
-      this.EDIT_COMP_CONFIG({
+      this.editComponentConfig({
         index: this.index,
         values,
       });
@@ -513,22 +542,10 @@ limitations under the License. -->
         chartType: MetricChartType[params.value],
         [params.type]: params.value,
       };
-      if (this.type === this.pageTypes[0]) {
-        this.EDIT_TOPO_ENDPOINT_CONFIG({
-          index: this.index,
-          values,
-        });
-      } else if (this.type === this.pageTypes[1]) {
-        this.EDIT_TOPO_INSTANCE_CONFIG({
-          index: this.index,
-          values,
-        });
-      } else {
-        this.EDIT_COMP_CONFIG({
-          index: this.index,
-          values,
-        });
-      }
+      this.editComponentConfig({
+        index: this.index,
+        values,
+      });
       this.itemConfig = {
         ...this.itemConfig,
         ...values,
@@ -576,7 +593,10 @@ limitations under the License. -->
             } else {
               this.itemConfig.currentEndpoint = '';
             }
-            this.EDIT_COMP_CONFIG({ index: this.index, values: { currentEndpoint: this.itemConfig.currentEndpoint } });
+            this.editComponentConfig({
+              index: this.index,
+              values: { currentEndpoint: this.itemConfig.currentEndpoint },
+            });
           }
         });
       } else if (this.itemConfig.entityType === EntityType[3].key) {
@@ -592,7 +612,10 @@ limitations under the License. -->
             } else {
               this.itemConfig.currentInstance = '';
             }
-            this.EDIT_COMP_CONFIG({ index: this.index, values: { currentInstance: this.itemConfig.currentInstance } });
+            this.editComponentConfig({
+              index: this.index,
+              values: { currentInstance: this.itemConfig.currentInstance },
+            });
           }
         });
       }
diff --git a/src/views/components/dashboard/charts/chart-heap.vue b/src/views/components/dashboard/charts/chart-heap.vue
index a38025f..0258471 100644
--- a/src/views/components/dashboard/charts/chart-heap.vue
+++ b/src/views/components/dashboard/charts/chart-heap.vue
@@ -28,6 +28,7 @@ limitations under the License. -->
     @Prop() private title!: string;
     @Prop() private stateDashboard!: any;
     @Prop() private intervalTime!: any;
+    @Prop() private theme!: string;
     get responseConfig() {
       return {
         color: ['#3f96e3', '#3fbde3'],
@@ -44,6 +45,9 @@ limitations under the License. -->
           top: 0,
           left: 0,
           itemWidth: 12,
+          textStyle: {
+            color: this.theme === 'dark' ? '#fff' : '#333',
+          },
         },
         grid: {
           top: 10,
diff --git a/src/views/components/dashboard/charts/chart-line.vue b/src/views/components/dashboard/charts/chart-line.vue
index 1ba0622..d9f5739 100644
--- a/src/views/components/dashboard/charts/chart-line.vue
+++ b/src/views/components/dashboard/charts/chart-line.vue
@@ -25,6 +25,7 @@ limitations under the License. -->
     @Prop() private data!: any;
     @Prop() private type!: string;
     @Prop() private intervalTime!: any;
+    @Prop() private theme!: string;
     @Prop() private itemEvents!: Event[];
     public resize() {
       const chart: any = this.$refs.chart;
@@ -137,6 +138,9 @@ limitations under the License. -->
           top: 0,
           left: 0,
           itemWidth: 12,
+          textStyle: {
+            color: this.theme === 'dark' ? '#fff' : '#333',
+          },
         },
         grid: {
           top: keys.length === 1 ? 15 : 55,
diff --git a/src/views/components/dashboard/charts/chart-num.vue b/src/views/components/dashboard/charts/chart-num.vue
index 135a623..80e4893 100644
--- a/src/views/components/dashboard/charts/chart-num.vue
+++ b/src/views/components/dashboard/charts/chart-num.vue
@@ -16,7 +16,7 @@ limitations under the License. -->
 <template>
   <div class="rk-chart-num">
     <div v-for="(item, index) in data" :key="index" class="rk-num-detail">
-      <span class="b">{{
+      <span class="b" :style="`color: ${colors}`">{{
         typeof item.avgNum === 'string' ? item.avgNum : isNaN(item.avgNum) ? null : item.avgNum.toFixed(2)
       }}</span>
     </div>
@@ -29,6 +29,11 @@ limitations under the License. -->
   export default class ChartNum extends Vue {
     @Prop() private data!: any;
     @Prop() private item!: any;
+    @Prop() private theme!: string;
+
+    private get colors() {
+      return this.theme === 'dark' ? '#eee' : '#333';
+    }
   }
 </script>
 <style lang="scss" scoped>
diff --git a/src/views/components/dashboard/charts/chart-table.vue b/src/views/components/dashboard/charts/chart-table.vue
index c03e24c..0b041ef 100644
--- a/src/views/components/dashboard/charts/chart-table.vue
+++ b/src/views/components/dashboard/charts/chart-table.vue
@@ -16,7 +16,7 @@ limitations under the License. -->
 <template>
   <div class="rk-chart-table">
     <div ref="chartTable">
-      <div class="row header flex-h" :style="`width: ${nameWidth + initWidth}px`">
+      <div class="row header flex-h" :style="`width: ${nameWidth + initWidth}px`" :class="{ dark: theme === 'dark' }">
         <div class="name" :style="`width: ${nameWidth}px`">
           {{ item.tableHeaderCol1 || $t('name') }}
           <i class="r cp" ref="draggerName"><rk-icon icon="settings_ethernet"/></i>
@@ -25,7 +25,13 @@ limitations under the License. -->
           {{ item.tableHeaderCol2 || $t('value') }}
         </div>
       </div>
-      <div class="row flex-h" v-for="key in dataKeys" :key="key" :style="`width: ${nameWidth + initWidth}px`">
+      <div
+        class="row flex-h"
+        :class="{ dark: theme === 'dark' }"
+        v-for="key in dataKeys"
+        :key="key"
+        :style="`width: ${nameWidth + initWidth}px`"
+      >
         <div :style="`width: ${nameWidth}px`">{{ key }}</div>
         <div class="value-col" v-if="showTableValues">{{ data[key][dataLength(data[key])] }}</div>
       </div>
@@ -41,6 +47,7 @@ limitations under the License. -->
   export default class ChartTable extends Vue {
     @Prop() private data!: any;
     @Prop() private item: any;
+    @Prop() private theme!: string;
 
     private nameWidth: number = 0;
     private initWidth: number = 0;
@@ -106,6 +113,9 @@ limitations under the License. -->
         border-bottom: 1px solid #ccc;
       }
     }
+    .dark {
+      color: #eee;
+    }
     .row:first-child {
       div {
         border-top: 1px solid #ccc;
diff --git a/src/views/components/dashboard/charts/constant.ts b/src/views/components/dashboard/charts/constant.ts
index 7525211..5aa812f 100644
--- a/src/views/components/dashboard/charts/constant.ts
+++ b/src/views/components/dashboard/charts/constant.ts
@@ -20,6 +20,9 @@ export const EntityType = [
   { key: 'All', label: 'All' },
   { key: 'Endpoint', label: 'Service Endpoint' },
   { key: 'ServiceInstance', label: 'Service Instance' },
+  { key: 'ServiceRelation', label: 'Service Relation' },
+  { key: 'ServiceInstanceRelation', label: 'Service Instance Relation' },
+  { key: 'EndpointRelation', label: 'Endpoint Relation' },
 ];
 export const BrowserEntityType = [
   { key: 'Service', label: 'Service' },
diff --git a/src/views/components/dashboard/dashboard-item.vue b/src/views/components/dashboard/dashboard-item.vue
index 137ad4b..27a9177 100644
--- a/src/views/components/dashboard/dashboard-item.vue
+++ b/src/views/components/dashboard/dashboard-item.vue
@@ -13,18 +13,24 @@ 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>
-  <div class="rk-dashboard-item" :class="`g-sm-${width}`" :style="`height:${height}px;`">
+  <div class="rk-dashboard-item" :class="`g-sm-${width}`" :style="`height:${height}px;`" v-if="itemConfig.entityType">
     <div class="rk-dashboard-item-title ell">
-      <span v-show="rocketGlobal.edit" @click="deleteItem(index)">
+      <span v-show="rocketGlobal.edit || stateTopo.editDependencyMetrics" @click="deleteItem(index, itemConfig.uuid)">
         <rk-icon class="r edit red" icon="file-deletion" />
       </span>
       <span>{{ title }}</span>
       <span v-show="unit"> ( {{ unit }} ) </span>
       <span v-show="status === 'UNKNOWN'" class="item-status">( {{ $t('unknownMetrics') }} )</span>
-      <span v-show="!rocketGlobal.edit && !pageTypes.includes(type)" @click="editComponentConfig">
+      <span
+        v-show="!rocketGlobal.edit && !stateTopo.editDependencyMetrics && !noEditTypes.includes(type)"
+        @click="editComponentConfig"
+      >
         <rk-icon class="r edit" icon="keyboard_control" v-tooltip:bottom="{ content: $t('editConfig') }" />
       </span>
-      <span v-show="!rocketGlobal.edit && itemConfig.chartType === 'ChartTable'" @click="copyTable">
+      <span
+        v-show="!rocketGlobal.edit && stateTopo.editDependencyMetrics && itemConfig.chartType === 'ChartTable'"
+        @click="copyTable"
+      >
         <rk-icon class="r cp" icon="review-list" />
       </span>
       <rk-icon v-if="tips" class="r edit" icon="info_outline" v-tooltip:bottom="{ content: tips }" />
@@ -32,7 +38,7 @@ limitations under the License. -->
     <div class="rk-dashboard-item-body" ref="chartBody">
       <div style="height:100%;width:100%">
         <component
-          :is="rocketGlobal.edit ? 'ChartEdit' : itemConfig.chartType"
+          :is="rocketGlobal.edit || stateTopo.editDependencyMetrics ? 'ChartEdit' : itemConfig.chartType"
           ref="chart"
           :item="itemConfig"
           :index="index"
@@ -40,6 +46,7 @@ limitations under the License. -->
           :data="chartSource"
           :type="type"
           :itemEvents="itemEvents"
+          :theme="theme"
           @updateStatus="(type, value) => setStatus(type, value)"
         ></component>
       </div>
@@ -47,9 +54,10 @@ limitations under the License. -->
     <rk-sidebox
       width="70%"
       :fixed="true"
+      :right="theme === 'dark'"
       :title="$t('editConfig')"
       :show.sync="dialogConfigVisible"
-      @closeSideboxCallback="chartRender()"
+      @closeSideboxCallback="chartRender"
     >
       <div class="config-box">
         <component
@@ -59,6 +67,8 @@ limitations under the License. -->
           :index="index"
           :intervalTime="intervalTime"
           :data="chartSource"
+          :theme="theme"
+          :type="type"
         ></component>
       </div>
     </rk-sidebox>
@@ -71,7 +81,7 @@ limitations under the License. -->
   import dayjs from 'dayjs';
 
   import { QueryTypes, UpdateDashboardEvents } from './constant';
-  import { TopologyType, ObjectsType } from '../../../constants/constant';
+  import { TopologyType } from '@/constants/constant';
   import { CalculationType } from './charts/constant';
   import { State as globalState } from '@/store/modules/global';
   import { State as optionState } from '@/store/modules/global/selectors';
@@ -86,20 +96,26 @@ limitations under the License. -->
   export default class DashboardItem extends Vue {
     @State('rocketbot') private rocketGlobal!: globalState;
     @State('rocketData') private rocketData!: rocketData;
-    @Mutation('EDIT_COMP_CONFIG') private EDIT_COMP_CONFIG: any;
+    @State('rocketTopo') private stateTopo!: any;
     @Mutation('DELETE_COMP') private DELETE_COMP: any;
     @Mutation('rocketTopo/DELETE_TOPO_ENDPOINT') private DELETE_TOPO_ENDPOINT: any;
     @Mutation('rocketTopo/DELETE_TOPO_INSTANCE') private DELETE_TOPO_INSTANCE: any;
+    @Mutation('rocketTopo/DELETE_TOPO_SERVICE') private DELETE_TOPO_SERVICE: any;
+    @Mutation('rocketTopo/DELETE_TOPO_SERVICE_DEPENDENCY') private DELETE_TOPO_SERVICE_DEPENDENCY: any;
+    @Mutation('rocketTopo/DELETE_TOPO_INSTANCE_DEPENDENCY') private DELETE_TOPO_INSTANCE_DEPENDENCY: any;
+    @Mutation('rocketTopo/DELETE_TOPO_ENDPOINT_DEPENDENCY') private DELETE_TOPO_ENDPOINT_DEPENDENCY: any;
     @Action('GET_QUERY') private GET_QUERY: any;
     @Getter('intervalTime') private intervalTime: any;
     @Getter('durationTime') private durationTime: any;
     @Prop() private item!: any;
     @Prop() private index!: number;
     @Prop() private type!: string;
-    @Prop() private updateObjects!: string;
+    @Prop() private updateObjects!: boolean;
     @Prop() private rocketOption!: optionState;
+    @Prop() private templateTypes!: string[];
+    @Prop() private templateMode!: string; // server client
 
-    private pageTypes = [TopologyType.TOPOLOGY_ENDPOINT, TopologyType.TOPOLOGY_INSTANCE] as string[];
+    private noEditTypes = [TopologyType.TOPOLOGY_ENDPOINT, TopologyType.TOPOLOGY_INSTANCE] as string[];
     private dialogConfigVisible = false;
     private status = 'UNKNOWN';
     private title = 'Title';
@@ -110,6 +126,13 @@ limitations under the License. -->
     private chartSource: any = {};
     private itemConfig: any = {};
     private itemEvents: Event[] = [];
+    private theme: 'light' | 'dark' = 'light';
+    private darkThemeTypes = [
+      TopologyType.TOPOLOGY_SERVICE,
+      TopologyType.TOPOLOGY_SERVICE_DEPENDENCY,
+      TopologyType.TOPOLOGY_SERVICE_INSTANCE_DEPENDENCY,
+      TopologyType.TOPOLOGY_ENDPOINT_DEPENDENCY,
+    ] as string[];
 
     private created() {
       this.status = this.item.metricType;
@@ -120,18 +143,13 @@ limitations under the License. -->
       this.unit = this.item.unit;
       this.itemConfig = this.item;
       this.itemEvents = this.eventsFilter();
-      const types = [
-        ObjectsType.UPDATE_INSTANCES,
-        ObjectsType.UPDATE_ENDPOINTS,
-        ObjectsType.UPDATE_DASHBOARD,
-      ] as string[];
+      this.theme = this.darkThemeTypes.includes(this.type) ? 'dark' : 'light';
 
-      if (!types.includes(this.updateObjects)) {
-        return;
+      if (this.updateObjects) {
+        setTimeout(() => {
+          this.chartRender();
+        }, 1000);
       }
-      setTimeout(() => {
-        this.chartRender();
-      }, 1000);
     }
 
     private chartRender() {
@@ -144,17 +162,22 @@ limitations under the License. -->
         index: this.index,
         type: this.type,
         rocketOption: this.rocketOption,
+        templateType: this.templateTypes,
+        templateMode: this.templateMode,
       }).then((params: Array<{ metricName: string; [key: string]: any; config: any }>) => {
         if (!params) {
+          this.itemConfig = {};
           return;
         }
         if (!params.length) {
+          this.itemConfig = {};
           return;
         }
         this.itemConfig = params[0].config;
-        const { queryMetricType, chartType } = this.itemConfig;
+
+        const { queryMetricType } = this.itemConfig;
         let data = params;
-        if (queryMetricType === QueryTypes.ReadMetricsValue /*&& chartType === 'ChartSlow'*/) {
+        if (queryMetricType === QueryTypes.ReadMetricsValue) {
           const arr: any = [
             {
               config: this.itemConfig,
@@ -337,11 +360,25 @@ limitations under the License. -->
       copy(JSON.stringify(data));
     }
 
-    private deleteItem(index: number) {
-      if (this.type === this.pageTypes[0]) {
-        this.DELETE_TOPO_ENDPOINT(index);
-      } else if (this.type === this.pageTypes[1]) {
-        this.DELETE_TOPO_INSTANCE(index);
+    private deleteItem(index: number, uuid: number) {
+      if (this.type === TopologyType.TOPOLOGY_ENDPOINT) {
+        this.DELETE_TOPO_ENDPOINT(uuid);
+        this.$emit('setTemplates');
+      } else if (this.type === TopologyType.TOPOLOGY_INSTANCE) {
+        this.DELETE_TOPO_INSTANCE(uuid);
+        this.$emit('setTemplates');
+      } else if (this.type === TopologyType.TOPOLOGY_SERVICE) {
+        this.DELETE_TOPO_SERVICE(uuid);
+        this.$emit('setTemplates');
+      } else if (this.type === TopologyType.TOPOLOGY_SERVICE_DEPENDENCY) {
+        this.DELETE_TOPO_SERVICE_DEPENDENCY(uuid);
+        this.$emit('setTemplates');
+      } else if (this.type === TopologyType.TOPOLOGY_SERVICE_INSTANCE_DEPENDENCY) {
+        this.DELETE_TOPO_INSTANCE_DEPENDENCY(uuid);
+        this.$emit('setTemplates');
+      } else if (this.type === TopologyType.TOPOLOGY_ENDPOINT_DEPENDENCY) {
+        this.DELETE_TOPO_ENDPOINT_DEPENDENCY(uuid);
+        this.$emit('setTemplates');
       } else {
         this.DELETE_COMP(index);
       }
@@ -384,15 +421,32 @@ limitations under the License. -->
     }
 
     // watch selectors and events
-    @Watch('rocketOption.updateDashboard')
+    @Watch('rocketOption.updateDashboard.key')
     private watchCurrentSelectors() {
+      if (!this.rocketOption.updateDashboard) {
+        return;
+      }
+      const key = this.rocketOption.updateDashboard.key || '';
+
       this.itemEvents = this.eventsFilter();
+      if (key.includes(UpdateDashboardEvents)) {
+        return;
+      }
+      if (key.includes(TopologyType.TOPOLOGY_SERVICE) && this.itemConfig.entityType !== EntityType[0].key) {
+        return;
+      }
+      if (key.includes(TopologyType.TOPOLOGY_SERVICE_DEPENDENCY) && this.itemConfig.entityType !== EntityType[4].key) {
+        return;
+      }
       if (
-        this.rocketOption.updateDashboard.key &&
-        this.rocketOption.updateDashboard.key.includes(UpdateDashboardEvents)
+        key.includes(TopologyType.TOPOLOGY_SERVICE_INSTANCE_DEPENDENCY) &&
+        this.itemConfig.entityType !== EntityType[5].key
       ) {
         return;
       }
+      if (key.includes(TopologyType.TOPOLOGY_ENDPOINT_DEPENDENCY) && this.itemConfig.entityType !== EntityType[6].key) {
+        return;
+      }
       setTimeout(() => {
         this.chartRender();
       }, 1000);
@@ -403,6 +457,20 @@ limitations under the License. -->
     }
     @Watch('rocketGlobal.edit')
     private watchRerender() {
+      if (this.stateTopo.editDependencyMetrics) {
+        return;
+      }
+      this.chartRender();
+    }
+    @Watch('stateTopo.editDependencyMetrics')
+    private watchDependency() {
+      if (
+        (this.type !== TopologyType.TOPOLOGY_SERVICE_INSTANCE_DEPENDENCY &&
+          this.type !== TopologyType.TOPOLOGY_ENDPOINT_DEPENDENCY) ||
+        this.stateTopo.editDependencyMetrics
+      ) {
+        return;
+      }
       this.chartRender();
     }
   }
@@ -417,6 +485,9 @@ limitations under the License. -->
     .edit {
       cursor: pointer;
     }
+    .rk-sidebox-title {
+      color: #333;
+    }
   }
   .dashboard-item-shadow {
     background-color: #448dfe15;
diff --git a/src/views/components/dashboard/tool-bar/tool-bar-btns.vue b/src/views/components/dashboard/tool-bar/tool-bar-btns.vue
index 8d1f5ad..2a03715 100644
--- a/src/views/components/dashboard/tool-bar/tool-bar-btns.vue
+++ b/src/views/components/dashboard/tool-bar/tool-bar-btns.vue
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
 limitations under the License. -->
 
 <template>
-  <div class="flex-h btn-box">
+  <div class="flex-h">
     <div class="rk-dashboard-bar-btn" @click="handleSetEdit">
       <rk-icon
         class="lg"
diff --git a/src/views/components/dashboard/tool-bar/tool-bar.vue b/src/views/components/dashboard/tool-bar/tool-bar.vue
index 6708612..30a78a4 100644
--- a/src/views/components/dashboard/tool-bar/tool-bar.vue
+++ b/src/views/components/dashboard/tool-bar/tool-bar.vue
@@ -15,6 +15,7 @@ limitations under the License. -->
 <template>
   <div class="rk-dashboard-bar flex-h">
     <ToolBarBtns
+      class="tool-btns"
       :rocketGlobal="rocketGlobal"
       :rocketComps="rocketComps"
       :compType="compType"
@@ -228,6 +229,9 @@ limitations under the License. -->
 </script>
 
 <style lang="scss" scoped>
+  .tool-btns {
+    height: 58px;
+  }
   .rk-dashboard-bar {
     flex-shrink: 0;
     color: #efefef;
diff --git a/src/views/components/topology/chart-line.vue b/src/views/components/topology/chart-line.vue
deleted file mode 100644
index 12111d6..0000000
--- a/src/views/components/topology/chart-line.vue
+++ /dev/null
@@ -1,98 +0,0 @@
-<!-- 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. -->
-
-<template>
-  <div>
-    <div class="grey sm mb-5">{{ title }}</div>
-    <RkEcharts height="120px" :option="option" />
-  </div>
-</template>
-<script lang="ts">
-  import { Vue, Component, Prop } from 'vue-property-decorator';
-
-  @Component
-  export default class ChartLine extends Vue {
-    @Prop() private data!: any;
-    @Prop() private title!: string;
-    @Prop() private intervalTime!: any;
-
-    get option() {
-      const keys = Object.keys(this.data || {}).filter((i: any) => Array.isArray(this.data[i]) && this.data[i].length);
-      const temp = keys.map((i: string, index: number) => {
-        return {
-          data: this.data[i].map((item: any, itemIndex: number) => [this.intervalTime[itemIndex], item]),
-          name: i,
-          type: 'line',
-          symbol: 'none',
-          barMaxWidth: 10,
-          lineStyle: {
-            width: 1.5,
-            type: 'solid',
-          },
-        };
-      });
-      const color: string[] = [
-        '#30A4EB',
-        '#45BFC0',
-        '#FFCC55',
-        '#FF6A84',
-        '#a0a7e6',
-        '#6be6c1',
-        '#626c91',
-        '#96dee8',
-        '#3f96e3',
-      ];
-
-      return {
-        color,
-        tooltip: {
-          trigger: 'axis',
-          backgroundColor: 'rgb(50,50,50)',
-          textStyle: {
-            fontSize: 13,
-          },
-        },
-        legend: {
-          show: false,
-        },
-        grid: {
-          top: 5,
-          left: 0,
-          right: 18,
-          bottom: 5,
-          containLabel: true,
-        },
-        xAxis: {
-          type: 'category',
-          axisTick: {
-            lineStyle: { color: '#c1c5ca41' },
-            alignWithLabel: true,
-          },
-          splitLine: { show: false },
-          axisLine: { lineStyle: { color: 'rgba(0,0,0,0)' } },
-          axisLabel: { color: '#9da5b2', fontSize: '11' },
-        },
-        yAxis: {
-          type: 'value',
-          axisLine: { show: false },
-          axisTick: { show: false },
-          splitLine: { lineStyle: { color: '#c1c5ca41', type: 'dashed' } },
-          axisLabel: { color: '#9da5b2', fontSize: '11' },
-        },
-        series: temp,
-      };
-    }
-  }
-</script>
diff --git a/src/views/components/topology/dependency-sankey.vue b/src/views/components/topology/chart/dependency-sankey.vue
similarity index 87%
rename from src/views/components/topology/dependency-sankey.vue
rename to src/views/components/topology/chart/dependency-sankey.vue
index bb9ea6c..a0d6ad0 100644
--- a/src/views/components/topology/dependency-sankey.vue
+++ b/src/views/components/topology/chart/dependency-sankey.vue
@@ -20,15 +20,10 @@ limitations under the License. -->
 <script lang="ts">
   import Vue from 'vue';
   import { Component, Prop } from 'vue-property-decorator';
-  import { State, Action, Getter, Mutation } from 'vuex-class';
-  import * as echarts from 'echarts/lib/echarts';
 
   @Component
   export default class DependencySankey extends Vue {
     @Prop() private data: any;
-    @Getter('durationTime') private durationTime: any;
-    @Action('rocketTopo/GET_INSTANCE_DEPENDENCY_METRICS')
-    private GET_INSTANCE_DEPENDENCY_METRICS: any;
 
     get optionConfigs() {
       return {
diff --git a/src/views/components/topology/radial.vue b/src/views/components/topology/chart/radial.vue
similarity index 100%
rename from src/views/components/topology/radial.vue
rename to src/views/components/topology/chart/radial.vue
diff --git a/src/views/components/topology/chart/topo.vue b/src/views/components/topology/chart/topo.vue
index 802b7cc..96f3ec3 100644
--- a/src/views/components/topology/chart/topo.vue
+++ b/src/views/components/topology/chart/topo.vue
@@ -115,7 +115,7 @@ limitations under the License. -->
         this.$emit('setDialog', 'endpoint_dependency');
       },
       handleNodeClick(d) {
-        this.$emit('setCurrent', { key: d.id, label: d.name });
+        this.$emit('setCurrent', { key: d.id, label: d.name, isReal: d.isReal });
         const {x, y, vx, vy, fx, fy, index, ...rest} = d;
         this.$store.dispatch('rocketTopo/CLEAR_TOPO_INFO');
         this.$store.commit('rocketTopo/SET_NODE', rest);
@@ -125,14 +125,10 @@ limitations under the License. -->
         event.stopPropagation();
         this.$store.commit('rocketTopo/SET_NODE', {});
         this.$store.commit('rocketTopo/SET_LINK', d);
+        this.$store.commit('SET_SERVICE_DEPENDENCY', d);
         this.$store.dispatch('rocketTopo/CLEAR_TOPO_INFO');
         this.$store.commit('rocketTopo/SET_MODE', d.detectPoints);
-        this.$store.dispatch(this.$store.state.rocketTopo.mode ? 'rocketTopo/GET_TOPO_SERVICE_INFO' :
-            'rocketTopo/GET_TOPO_CLIENT_INFO', { ...d, duration: this.$store.getters.durationTime });
-        this.$store.commit('rocketTopo/SET_CALLBACK', () => {
-          this.$store.dispatch(this.$store.state.rocketTopo.mode ? 'rocketTopo/GET_TOPO_SERVICE_INFO' :
-            'rocketTopo/GET_TOPO_CLIENT_INFO', { ...d, duration: this.$store.getters.durationTime });
-        });
+        this.$store.commit('rocketTopo/SET_SELECTED_CALL', { ...d, duration: this.$store.getters.durationTime });
       },
       resize() {
         this.svg.attr('height', this.$el.clientHeight);
diff --git a/src/views/components/topology/dependency/topo-endpoint-dependency.vue b/src/views/components/topology/dependency/topo-endpoint-dependency.vue
new file mode 100644
index 0000000..932bd02
--- /dev/null
+++ b/src/views/components/topology/dependency/topo-endpoint-dependency.vue
@@ -0,0 +1,314 @@
+<!-- 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. -->
+<template>
+  <div class="rk-endpoint-dependency" :style="`height: ${height}px`">
+    <div class="endpoint-dependency-chart">
+      <DependencySankey
+        v-if="stateTopo.endpointDependency.nodes.length"
+        :data="stateTopo.endpointDependency"
+        @showMetrics="showEndpointMetrics"
+      />
+      <div v-else class="endpoint-dependency-empty">
+        No Endpoint Dependency
+      </div>
+    </div>
+    <div class="mb-5 header" v-if="stateTopo.selectedEndpointCall">
+      <span class="topo-tool-btn" @click="handleSetEdit">
+        <rk-icon
+          class="lg rk-icon"
+          :style="`color:${stateTopo.editDependencyMetrics ? '#ffc107' : ''}`"
+          :icon="stateTopo.editDependencyMetrics ? 'lock-open' : 'lock'"
+          v-tooltip:bottom="{ content: stateTopo.editDependencyMetrics ? 'view' : 'edit' }"
+        />
+      </span>
+      <span class="topo-tool-btn" v-tooltip:bottom="{ content: 'import' }">
+        <input
+          id="endpoint-tool-bar-file"
+          type="file"
+          name="file"
+          title=""
+          accept=".json"
+          @change="importEndpointDependencyMetricsTemplate"
+        />
+        <label for="endpoint-tool-bar-file">
+          <rk-icon class="lg import" icon="folder_open" />
+        </label>
+      </span>
+      <span class="topo-tool-btn" @click="exportTopoEndpointDependencyMetrics">
+        <rk-icon class="lg" icon="save_alt" v-tooltip:bottom="{ content: 'export' }" />
+      </span>
+      <span class="ml-5 pb-5 flex-h">
+        <div class="type grey">{{ $t('templateType') }}</div>
+        <RkSelect
+          class="content grey"
+          :mode="'multiple'"
+          :current="currentType"
+          :data="templateNameList"
+          :theme="'dark'"
+          @onChoose="(item) => changeTemplatesType(item)"
+        />
+      </span>
+    </div>
+    <div v-if="stateTopo.selectedEndpointCall" class="endpoint-dependency-metrics scroll_bar_style">
+      <DashboardItem
+        v-for="(i, index) in topoEndpointDependencyMetrics || []"
+        :key="i.uuid"
+        :rocketGlobal="rocketGlobal"
+        :item="i"
+        :index="index"
+        :type="type"
+        :updateObjects="true"
+        :rocketOption="stateDashboardOption"
+        :templateTypes="templateType"
+        @setTemplates="setMetricsTemplate"
+      />
+      <div v-show="stateTopo.editDependencyMetrics" class="rk-add-metric-item g-sm-3" @click="addMetrics">
+        + Add An Item
+      </div>
+    </div>
+  </div>
+</template>
+<script lang="ts">
+  import { Vue, Component, Watch } from 'vue-property-decorator';
+  import { State, Getter, Mutation } from 'vuex-class';
+  import { State as optionState } from '@/store/modules/global/selectors';
+  import { State as rocketbotGlobal } from '@/store/modules/global';
+  import { State as topoState } from '@/store/modules/topology';
+  import DependencySankey from '../chart/dependency-sankey.vue';
+  import DashboardItem from '@/views/components/dashboard/dashboard-item.vue';
+  import { readFile } from '@/utils/readFile';
+  import { saveFile } from '@/utils/saveFile';
+  import { Duration } from '@/types/global';
+  import { EndpointDependencyConidition, Call } from '@/types/topo';
+  import { DEFAULT, TopologyType } from '@/constants/constant';
+  import { Option } from '@/types/global';
+  import { uuid } from '@/utils/uuid';
+
+  @Component({
+    components: {
+      DependencySankey,
+      DashboardItem,
+    },
+  })
+  export default class TopoEndpointDependency extends Vue {
+    @Getter('durationTime') private durationTime!: Duration;
+    @Getter('intervalTime') private intervalTime: any;
+    @State('rocketTopo') private stateTopo!: topoState;
+    @State('rocketOption') private stateDashboardOption!: optionState;
+    @State('rocketbot') private rocketGlobal!: rocketbotGlobal;
+    @Mutation('rocketTopo/SET_SELECTED_ENDPOINT_CALL') private SET_SELECTED_ENDPOINT_CALL: any;
+    @Mutation('SET_ENDPOINT_DEPENDENCY') private SET_ENDPOINT_DEPENDENCY: any;
+    @Mutation('rocketTopo/EDIT_DEPENDENCY_METRICS') private EDIT_DEPENDENCY_METRICS: any;
+    @Mutation('rocketTopo/IMPORT_TREE_ENDPOINT_DEPENDENCY') private IMPORT_TREE_ENDPOINT_DEPENDENCY: any;
+    @Mutation('rocketTopo/ADD_TOPO_ENDPOINT_DEPENDENCY_COMP') private ADD_TOPO_ENDPOINT_DEPENDENCY_COMP: any;
+    @Mutation('rocketTopo/UPDATE_TOPO_TEMPLATE_TYPES') private UPDATE_TOPO_TEMPLATE_TYPES: any;
+    @Mutation('rocketTopo/SET_TOPO_ENDPOINT_DEPENDENCY') private SET_TOPO_ENDPOINT_DEPENDENCY: any;
+
+    private templateType: string[] = [];
+    private topoEndpointDependencyMetrics: any = [];
+    private type = TopologyType.TOPOLOGY_ENDPOINT_DEPENDENCY;
+    private height = 500;
+    private templateNameList: Option[] = [];
+    private currentType: Option[] = [];
+
+    private beforeMount() {
+      this.height = document.body.clientHeight - 133;
+    }
+
+    private addMetrics() {
+      this.ADD_TOPO_ENDPOINT_DEPENDENCY_COMP();
+      this.setMetricsTemplate();
+    }
+
+    private changeTemplatesType(item: Option) {
+      let topoTemplateTypes;
+      const types = this.stateTopo.topoTemplatesType;
+
+      if (this.currentType.find((d) => d.key === item.key)) {
+        this.deleteTemplateTypes(item);
+        return;
+      }
+      this.currentType.push(item);
+      topoTemplateTypes = {
+        ...types,
+        [TopologyType.TOPOLOGY_ENDPOINT_DEPENDENCY]: this.currentType,
+      };
+      this.UPDATE_TOPO_TEMPLATE_TYPES(topoTemplateTypes);
+      this.setTemplateTypes();
+      this.setMetricsTemplate();
+    }
+
+    private deleteTemplateTypes(item: any) {
+      let topoTemplateTypes = null;
+      const types = this.stateTopo.topoTemplatesType;
+      const index = this.currentType.findIndex((d) => item.key === d.key);
+
+      this.currentType.splice(index, 1);
+      topoTemplateTypes = {
+        ...types,
+        [TopologyType.TOPOLOGY_ENDPOINT_DEPENDENCY]: this.currentType,
+      };
+      this.setTemplateTypes();
+      this.UPDATE_TOPO_TEMPLATE_TYPES(topoTemplateTypes);
+      this.setMetricsTemplate();
+    }
+
+    private showEndpointMetrics(data: EndpointDependencyConidition & Call) {
+      this.SET_SELECTED_ENDPOINT_CALL(data);
+      this.SET_ENDPOINT_DEPENDENCY(data);
+      this.setTemplateTypes();
+      this.templateNameList = Object.keys(this.stateTopo.topoEndpointDependency).map((item: string) => {
+        return { label: item, key: item };
+      });
+      this.setMetricsTemplate();
+    }
+
+    private setMetricsTemplate() {
+      this.topoEndpointDependencyMetrics = [];
+      let templates: any = {};
+
+      for (const type of Object.keys(this.stateTopo.topoEndpointDependency)) {
+        const metricsTemp = this.stateTopo.topoEndpointDependency[type].map((item: any) => {
+          item.uuid = item.uuid || uuid();
+          return item;
+        });
+        templates = {
+          ...templates,
+          [type]: metricsTemp,
+        };
+      }
+      this.SET_TOPO_ENDPOINT_DEPENDENCY(templates);
+      for (const type of this.templateType) {
+        this.topoEndpointDependencyMetrics = [
+          ...this.topoEndpointDependencyMetrics,
+          ...this.stateTopo.topoEndpointDependency[type],
+        ];
+      }
+    }
+
+    private setTemplateTypes() {
+      if (!this.stateTopo.selectedEndpointCall) {
+        return;
+      }
+      const nodeType = this.stateTopo.selectedEndpointCall.type || DEFAULT;
+      const templates = this.stateTopo.topoTemplatesType || {};
+      let templateTypes = [];
+
+      if (templates[TopologyType.TOPOLOGY_ENDPOINT_DEPENDENCY]) {
+        templateTypes = templates[TopologyType.TOPOLOGY_ENDPOINT_DEPENDENCY].map((item: Option) => item.key);
+      } else {
+        templateTypes = this.stateTopo.topoEndpointDependency[nodeType] ? [nodeType] : [DEFAULT];
+      }
+
+      this.templateType = templateTypes;
+      this.currentType = templateTypes.map((d: Option) => {
+        return { key: d, label: d };
+      });
+    }
+
+    private handleSetEdit() {
+      this.EDIT_DEPENDENCY_METRICS(!this.stateTopo.editDependencyMetrics);
+    }
+
+    private async importEndpointDependencyMetricsTemplate(event: Event) {
+      try {
+        const data: any = await readFile(event);
+        if (!Array.isArray(data)) {
+          throw new Error();
+        }
+        this.IMPORT_TREE_ENDPOINT_DEPENDENCY(data[0]);
+        this.setMetricsTemplate();
+        const el: any = document.getElementById('endpoint-tool-bar-file');
+        el!.value = '';
+      } catch (e) {
+        this.$modal.show('dialog', { text: 'ERROR' });
+      }
+    }
+
+    private exportTopoEndpointDependencyMetrics() {
+      const name = 'topo_endpoint_dependency_metrics.json';
+      let group: any = {};
+
+      for (const type of Object.keys(this.stateTopo.topoEndpointDependency)) {
+        const metricsTemp = this.stateTopo.topoEndpointDependency[type].map((item: any) => {
+          delete item.uuid;
+          return item;
+        });
+        group = {
+          ...group,
+          [type]: metricsTemp,
+        };
+      }
+
+      saveFile([group], name);
+    }
+
+    @Watch('stateTopo.endpointDependency.nodes')
+    private updateMetrics() {
+      this.topoEndpointDependencyMetrics = [];
+    }
+
+    private beforeDestroy() {
+      this.stateTopo.endpointDependency = {
+        calls: [],
+        nodes: [],
+      };
+    }
+  }
+</script>
+<style lang="scss" scoped>
+  @import url('../styles/common.scss');
+  .rk-endpoint-dependency {
+    background: #333840;
+    display: flex;
+    flex-direction: column;
+    .endpoint-dependency-chart {
+      height: 75%;
+      min-height: 500px;
+    }
+    .endpoint-dependency-empty {
+      color: #fff;
+      text-align: center;
+      height: 500px;
+      line-height: 500px;
+    }
+  }
+  .endpoint-dependency-metrics {
+    background: #333840;
+    height: 25%;
+    overflow: auto;
+    min-height: 210px;
+  }
+  .header {
+    z-index: 1;
+  }
+  #endpoint-tool-bar-file {
+    display: none;
+  }
+  .topo-tool-btn {
+    cursor: pointer;
+    color: #fff;
+    margin-right: 5px;
+  }
+  .rk-add-metric-item {
+    color: #eee;
+  }
+  .type {
+    width: 100px;
+  }
+  .content {
+    width: 400px;
+  }
+</style>
diff --git a/src/views/components/topology/dependency/topo-instance-dependency.vue b/src/views/components/topology/dependency/topo-instance-dependency.vue
new file mode 100644
index 0000000..c5ddcfc
--- /dev/null
+++ b/src/views/components/topology/dependency/topo-instance-dependency.vue
@@ -0,0 +1,342 @@
+<!-- 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. -->
+<template>
+  <div class="rk-topo-instance-dependency">
+    <div class="rk-dependency-chart">
+      <DependencySankey :data="stateTopo.instanceDependency" @showMetrics="showDependencyMetrics" />
+      <div v-show="!stateTopo.instanceDependency.nodes.length">
+        No Instance Dependency
+      </div>
+    </div>
+    <div class="rk-instance-metric-box">
+      <div v-if="stateTopo.selectedInstanceCall" class="rk-instance-metric-content">
+        <div class="mb-5 clear header">
+          <span class="b dib mr-20 vm">{{ $t('detectPoint') }}</span>
+          <span
+            v-if="stateTopo.selectedInstanceCall.detectPoints.includes('CLIENT')"
+            class="link-topo-aside-box-btn tc r sm cp b"
+            :class="{ active: stateTopo.instanceDependencyMode === 'client' }"
+            @click="setMode('client')"
+          >
+            {{ $t('client') }}
+          </span>
+          <span
+            v-if="stateTopo.selectedInstanceCall.detectPoints.includes('SERVER')"
+            class="link-topo-aside-box-btn tc r sm cp b"
+            :class="{ active: stateTopo.instanceDependencyMode === 'server' }"
+            @click="setMode('server')"
+          >
+            {{ $t('server') }}
+          </span>
+          <span class="topo-tool-btn" @click="handleSetEdit">
+            <rk-icon
+              class="lg rk-icon"
+              :style="`color:${stateTopo.editDependencyMetrics ? '#ffc107' : ''}`"
+              :icon="stateTopo.editDependencyMetrics ? 'lock-open' : 'lock'"
+              v-tooltip:bottom="{ content: stateTopo.editDependencyMetrics ? 'view' : 'edit' }"
+            />
+          </span>
+          <span class="topo-tool-btn" v-tooltip:bottom="{ content: 'import' }">
+            <input
+              id="instance-tool-bar-file"
+              type="file"
+              name="file"
+              title=""
+              accept=".json"
+              @change="importInstanceDependencyMetricsTemplate"
+            />
+            <label for="instance-tool-bar-file">
+              <rk-icon class="lg import" icon="folder_open" />
+            </label>
+          </span>
+          <span class="topo-tool-btn" @click="exportTopoInstanceDependencyMetrics">
+            <rk-icon class="lg" icon="save_alt" v-tooltip:bottom="{ content: 'export' }" />
+          </span>
+        </div>
+        <div class="pl-10 pb-5 flex-h">
+          <div class="type grey">{{ $t('templateType') }}</div>
+          <RkSelect
+            class="content grey"
+            :mode="'multiple'"
+            :current="currentType"
+            :data="templateNameList"
+            :theme="'dark'"
+            @onChoose="(item) => changeTemplatesType(item)"
+          />
+        </div>
+        <div
+          v-if="stateTopo.selectedInstanceCall"
+          class="rk-instance-dependency-metrics scroll_bar_style"
+          :style="`height: ${height}px`"
+        >
+          <DashboardItem
+            v-for="(i, index) in serviceInstanceDependencyComps || []"
+            :key="i.uuid"
+            :rocketGlobal="rocketGlobal"
+            :item="i"
+            :index="index"
+            :type="type"
+            :updateObjects="true"
+            :rocketOption="stateDashboardOption"
+            :templateTypes="templateType"
+            :templateMode="stateTopo.instanceDependencyMode"
+            @setTemplates="setMetircsTemplates"
+          />
+          <div
+            v-show="stateTopo.editDependencyMetrics"
+            class="rk-add-metric-item g-sm-3"
+            @click="addInstanceDependencyMetric"
+          >
+            + Add An Item
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+<script lang="ts">
+  import { Vue, Component } from 'vue-property-decorator';
+  import { State, Getter, Mutation } from 'vuex-class';
+  import { State as topoState } from '@/store/modules/topology';
+  import { State as optionState } from '@/store/modules/global/selectors';
+  import { State as rocketbotGlobal } from '@/store/modules/global';
+  import DependencySankey from '../chart/dependency-sankey.vue';
+  import DashboardItem from '@/views/components/dashboard/dashboard-item.vue';
+  import { readFile } from '@/utils/readFile';
+  import { saveFile } from '@/utils/saveFile';
+  import { DEFAULT, TopologyType } from '@/constants/constant';
+  import { Option } from '@/types/global';
+  import { uuid } from '@/utils/uuid';
+
+  @Component({
+    components: {
+      DependencySankey,
+      DashboardItem,
+    },
+  })
+  export default class TopoInstanceDependency extends Vue {
+    @Getter('intervalTime') private intervalTime: any;
+    @Getter('durationTime') private durationTime: any;
+    @State('rocketTopo') private stateTopo!: topoState;
+    @State('rocketOption') private stateDashboardOption!: optionState;
+    @State('rocketbot') private rocketGlobal!: rocketbotGlobal;
+    @Mutation('rocketTopo/SET_INSTANCE_DEPENDENCY_MODE_STATUS') private SET_INSTANCE_DEPENDENCY_MODE_STATUS: any;
+    @Mutation('rocketTopo/SET_SELECTED_INSTANCE_CALL') private SET_SELECTED_INSTANCE_CALL: any;
+    @Mutation('SET_SERVICE_INSTANCE_DEPENDENCY') private SET_SERVICE_INSTANCE_DEPENDENCY: any;
+    @Mutation('rocketTopo/EDIT_DEPENDENCY_METRICS') private EDIT_DEPENDENCY_METRICS: any;
+    @Mutation('rocketTopo/ADD_TOPO_INSTANCE_DEPENDENCY_COMP') private ADD_TOPO_INSTANCE_DEPENDENCY_COMP: any;
+    @Mutation('rocketTopo/IMPORT_TREE_INSTANCE_DEPENDENCY') private IMPORT_TREE_INSTANCE_DEPENDENCY: any;
+    @Mutation('rocketTopo/UPDATE_TOPO_TEMPLATE_TYPES') private UPDATE_TOPO_TEMPLATE_TYPES: any;
+    @Mutation('rocketTopo/SET_TOPO_SERVICE_INSTANCE_DEPENDENCY') private SET_TOPO_SERVICE_INSTANCE_DEPENDENCY: any;
+
+    private showInfo: boolean = true;
+    private height: number = 500;
+    private serviceInstanceDependencyComps: any = [];
+    private mode: string = 'server';
+    private templateType: string[] = [];
+    private templateMode: string = '';
+    private type = TopologyType.TOPOLOGY_SERVICE_INSTANCE_DEPENDENCY;
+    private currentType: Option[] = [];
+    private templateNameList: Option[] = [];
+
+    private beforeMount() {
+      this.height = document.body.clientHeight - 250;
+    }
+
+    private setMode(mode: any) {
+      this.SET_INSTANCE_DEPENDENCY_MODE_STATUS(mode);
+      const call: any = this.stateTopo.selectedInstanceCall || { sourceObj: {} };
+      this.templateTypes();
+      this.setMetircsTemplates();
+    }
+
+    private addInstanceDependencyMetric() {
+      this.ADD_TOPO_INSTANCE_DEPENDENCY_COMP();
+      this.setMetircsTemplates();
+    }
+    private showDependencyMetrics(data: any) {
+      this.SET_INSTANCE_DEPENDENCY_MODE_STATUS(data.detectPoints[0].toLowerCase());
+      this.SET_SELECTED_INSTANCE_CALL(data);
+      this.SET_SERVICE_INSTANCE_DEPENDENCY(data);
+      this.templateTypes();
+      this.templateNameList = Object.keys(this.stateTopo.topoServicesInstanceDependency).map((item: string) => {
+        return { label: item, key: item };
+      });
+      this.setMetircsTemplates();
+    }
+
+    private changeTemplatesType(item: Option) {
+      let topoTemplateTypes;
+      const types = this.stateTopo.topoTemplatesType;
+
+      if (this.currentType.find((d) => d.key === item.key)) {
+        this.deleteTemplateTypes(item);
+        return;
+      }
+      this.currentType.push(item);
+      topoTemplateTypes = {
+        ...types,
+        [TopologyType.TOPOLOGY_SERVICE_INSTANCE_DEPENDENCY]: this.currentType,
+      };
+      this.UPDATE_TOPO_TEMPLATE_TYPES(topoTemplateTypes);
+      this.templateTypes();
+      this.setMetircsTemplates();
+    }
+
+    private deleteTemplateTypes(item: any) {
+      let topoTemplateTypes = null;
+      const types = this.stateTopo.topoTemplatesType;
+      const index = this.currentType.findIndex((d) => item.key === d.key);
+
+      this.currentType.splice(index, 1);
+      topoTemplateTypes = {
+        ...types,
+        [TopologyType.TOPOLOGY_SERVICE_INSTANCE_DEPENDENCY]: this.currentType,
+      };
+      this.templateTypes();
+      this.UPDATE_TOPO_TEMPLATE_TYPES(topoTemplateTypes);
+      this.setMetircsTemplates();
+    }
+
+    private setMetircsTemplates() {
+      this.serviceInstanceDependencyComps = [];
+      const mode = this.stateTopo.instanceDependencyMode as any;
+      let templates: any = {};
+
+      for (const type of Object.keys(this.stateTopo.topoServicesInstanceDependency)) {
+        for (const detect of ['server', 'client']) {
+          const m: any = detect;
+          if (this.stateTopo.topoServicesInstanceDependency[type][m]) {
+            const metricsTemp = this.stateTopo.topoServicesInstanceDependency[type][m].map((item: any) => {
+              item.uuid = item.uuid || uuid();
+              return item;
+            });
+            templates = {
+              ...templates,
+              [type]: {
+                ...templates[type],
+                [m]: metricsTemp,
+              },
+            };
+          }
+        }
+      }
+      this.SET_TOPO_SERVICE_INSTANCE_DEPENDENCY(templates);
+      for (const type of this.templateType) {
+        this.serviceInstanceDependencyComps = [
+          ...this.serviceInstanceDependencyComps,
+          ...this.stateTopo.topoServicesInstanceDependency[type][mode],
+        ];
+      }
+    }
+
+    private templateTypes() {
+      const nodeType = this.stateTopo.currentNode.type;
+      const templates = this.stateTopo.topoTemplatesType;
+      let templateTypes = [];
+
+      if (templates[TopologyType.TOPOLOGY_SERVICE_INSTANCE_DEPENDENCY]) {
+        templateTypes = templates[TopologyType.TOPOLOGY_SERVICE_INSTANCE_DEPENDENCY].map((item: Option) => item.key);
+      } else {
+        templateTypes = this.stateTopo.topoServicesInstanceDependency[nodeType] ? [nodeType] : [DEFAULT];
+      }
+
+      this.templateType = templateTypes;
+      this.currentType = templateTypes.map((d: Option) => {
+        return { key: d, label: d };
+      });
+    }
+
+    private handleSetEdit() {
+      this.EDIT_DEPENDENCY_METRICS(!this.stateTopo.editDependencyMetrics);
+    }
+    private async importInstanceDependencyMetricsTemplate(event: Event) {
+      try {
+        const data: any = await readFile(event);
+        if (!Array.isArray(data)) {
+          throw new Error();
+        }
+        this.IMPORT_TREE_INSTANCE_DEPENDENCY(data[0]);
+        this.setMetircsTemplates();
+        const el: any = document.getElementById('instance-tool-bar-file');
+        el!.value = '';
+      } catch (e) {
+        this.$modal.show('dialog', { text: 'ERROR' });
+      }
+    }
+    private exportTopoInstanceDependencyMetrics() {
+      let group: any = {};
+      const name = 'topo_service_instance_dependency_metrics.json';
+      for (const type of Object.keys(this.stateTopo.topoServicesInstanceDependency)) {
+        for (const mode of ['server', 'client']) {
+          const m: any = mode;
+          const metricsTemp = this.stateTopo.topoServicesInstanceDependency[type][m].map((item: any) => {
+            delete item.uuid;
+            return item;
+          });
+          group = {
+            ...group,
+            [type]: {
+              ...group[type],
+              [m]: metricsTemp,
+            },
+          };
+        }
+      }
+
+      saveFile([group], name);
+    }
+  }
+</script>
+<style lang="scss" scoped>
+  @import url('../styles/common.scss');
+  .rk-topo-instance-dependency {
+    height: 100%;
+    display: flex;
+    flex-direction: row;
+    justify-content: space-between;
+    background: #2b3037;
+    .content {
+      width: 66%;
+    }
+  }
+  .rk-instance-metric-box {
+    display: flex;
+    flex-direction: column;
+    background: #252a2f;
+  }
+  .rk-instance-dependency-metrics {
+    width: 350px;
+    overflow: auto;
+  }
+  .rk-dependency-chart {
+    height: 100%;
+    width: calc(100% - 340px);
+  }
+  .header {
+    padding: 10px;
+    width: 100%;
+    overflow: hidden;
+  }
+  .rk-add-metric-item {
+    width: 325px;
+  }
+  .topo-tool-btn {
+    cursor: pointer;
+  }
+  #instance-tool-bar-file {
+    display: none;
+  }
+</style>
diff --git a/src/views/components/topology/dependency/topo-service-dependency.vue b/src/views/components/topology/dependency/topo-service-dependency.vue
new file mode 100644
index 0000000..162a63f
--- /dev/null
+++ b/src/views/components/topology/dependency/topo-service-dependency.vue
@@ -0,0 +1,143 @@
+<!-- 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. -->
+<template>
+  <div class="service-metrics scroll_bar_style" :style="`height: ${height}px`">
+    <DashboardItem
+      v-for="(i, index) in serviceDependencyComps || []"
+      :key="i.uuid"
+      :rocketGlobal="rocketGlobal"
+      :item="i"
+      :index="index"
+      :type="pageType"
+      :updateObjects="true"
+      :rocketOption="stateDashboardOption"
+      :templateTypes="templateType"
+      :templateMode="templateMode"
+      @setTemplates="setServiceDependencyTemplates"
+    />
+    <div v-show="rocketGlobal.edit" class="rk-add-metric-item g-sm-3" @click="addServiceDependencyMetric">
+      + Add An Item
+    </div>
+  </div>
+</template>
+<script lang="ts">
+  import { State, Mutation } from 'vuex-class';
+  import { Component, Vue, Watch, Prop } from 'vue-property-decorator';
+  import { State as topoState } from '@/store/modules/topology';
+  import { State as optionState } from '@/store/modules/global/selectors';
+  import { State as rocketbotGlobal } from '@/store/modules/global';
+  import DashboardItem from '@/views/components/dashboard/dashboard-item.vue';
+  import { TopologyType, DEFAULT } from '@/constants/constant';
+  import { Option } from '@/types/global';
+  import { uuid } from '@/utils/uuid';
+
+  @Component({
+    components: {
+      DashboardItem,
+    },
+  })
+  export default class TopoServiceDependency extends Vue {
+    @Prop() private currentType: any;
+    @State('rocketOption') private stateDashboardOption!: optionState;
+    @State('rocketbot') private rocketGlobal!: rocketbotGlobal;
+    @State('rocketTopo') private stateTopo!: topoState;
+    @Mutation('rocketTopo/ADD_TOPO_SERVICE_DEPENDENCY_COMP') private ADD_TOPO_SERVICE_DEPENDENCY_COMP: any;
+    @Mutation('rocketTopo/SET_TOPO_SERVICE_DEPENDENCY') private SET_TOPO_SERVICE_DEPENDENCY: any;
+
+    private serviceDependencyComps: any[] = [];
+    private height = 800;
+    private templateType: string[] = [DEFAULT];
+    private templateMode: any = 'server';
+    private pageType: string = TopologyType.TOPOLOGY_SERVICE_DEPENDENCY;
+
+    private beforeMount() {
+      this.templateMode = this.stateTopo.mode ? 'server' : 'client';
+      this.height = document.body.clientHeight - 280;
+      this.setServiceDependencyTemplates();
+    }
+
+    private addServiceDependencyMetric() {
+      this.ADD_TOPO_SERVICE_DEPENDENCY_COMP();
+      this.setServiceDependencyTemplates();
+    }
+
+    private templateTypes() {
+      let templateTypes = [];
+      if (!this.stateTopo.selectedServiceCall) {
+        return;
+      }
+      const callType = this.stateTopo.selectedServiceCall.source.type || DEFAULT;
+      const templates = this.stateTopo.topoTemplatesType;
+
+      if (
+        templates[TopologyType.TOPOLOGY_SERVICE_DEPENDENCY] &&
+        templates[TopologyType.TOPOLOGY_SERVICE_DEPENDENCY][callType]
+      ) {
+        templateTypes = templates[TopologyType.TOPOLOGY_SERVICE_DEPENDENCY][callType].map((item: Option) => item.key);
+      } else {
+        templateTypes = this.stateTopo.topoServicesDependency[callType] ? [callType] : [DEFAULT];
+      }
+
+      this.templateType = templateTypes;
+    }
+
+    private setServiceDependencyTemplates() {
+      this.templateTypes();
+      this.templateMode = this.stateTopo.mode ? 'server' : 'client';
+      this.serviceDependencyComps = [];
+      let templates: any = {};
+
+      for (const type of Object.keys(this.stateTopo.topoServicesDependency)) {
+        for (const mode of ['server', 'client']) {
+          const m: any = mode;
+          const metricsTemp = this.stateTopo.topoServicesDependency[type][m].map((item: any) => {
+            item.uuid = item.uuid || uuid();
+            return item;
+          });
+          templates = {
+            ...templates,
+            [type]: {
+              ...templates[type],
+              [m]: metricsTemp,
+            },
+          };
+        }
+      }
+      this.SET_TOPO_SERVICE_DEPENDENCY(templates);
+      for (const tep of this.templateType) {
+        this.serviceDependencyComps = [
+          ...this.serviceDependencyComps,
+          ...this.stateTopo.topoServicesDependency[tep][this.templateMode],
+        ];
+      }
+    }
+
+    @Watch('stateTopo.mode')
+    private updateServiceDependency() {
+      this.templateMode = this.stateTopo.mode ? 'server' : 'client';
+      this.setServiceDependencyTemplates();
+    }
+    @Watch('currentType')
+    private updateServiceMetrics() {
+      this.updateServiceDependency();
+    }
+  }
+</script>
+<style lang="scss" scoped>
+  @import url('../styles/common.scss');
+  .service-metrics {
+    overflow: auto;
+  }
+</style>
diff --git a/src/constants/constant.ts b/src/views/components/topology/styles/common.scss
similarity index 57%
copy from src/constants/constant.ts
copy to src/views/components/topology/styles/common.scss
index f67961e..dbfea22 100644
--- a/src/constants/constant.ts
+++ b/src/views/components/topology/styles/common.scss
@@ -14,30 +14,13 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
-export enum TopologyType {
-  TOPOLOGY_ENDPOINT = 'TOPOLOGY_ENDPOINT',
-  TOPOLOGY_INSTANCE = 'TOPOLOGY_INSTANCE',
-}
-
-export enum ObjectsType {
-  UPDATE_INSTANCES = 'UPDATE_INSTANCES',
-  UPDATE_ENDPOINTS = 'UPDATE_ENDPOINTS',
-  UPDATE_DASHBOARD = 'UPDATE_DASHBOARD',
-}
-
-export enum TimeType {
-  MINUTE_TIME = 'MINUTE',
-  HOUR_TIME = 'HOUR',
-  DAY_TIME = 'DAY',
-}
-
-export enum PageEventsType {
-  DASHBOARD_EVENTS = 'dashboardEvents',
-  TOPO_ENDPOINT_EVENTS = 'topoEndpointEvents',
-  TOPO_INSTANCE_EVENTS = 'topoInstanceEvents',
-}
-export enum PageTypes {
-  DASHBOARD = 'Dashboard',
-  LOG = 'Log',
-}
+ .rk-add-metric-item {
+  height: 200px;
+  text-align: center;
+  line-height: 250px;
+  border: 1px dashed rgba(196, 200, 225, 0.5);
+  cursor: pointer;
+  font-size: 16px;
+  width: 340px;
+  margin-left: 5px;
+}
\ No newline at end of file
diff --git a/src/views/components/topology/topo-aside.vue b/src/views/components/topology/topo-aside.vue
index 7de491c..06be8ac 100644
--- a/src/views/components/topology/topo-aside.vue
+++ b/src/views/components/topology/topo-aside.vue
@@ -23,64 +23,21 @@ limitations under the License. -->
     >
       <use xlink:href="#issues" />
     </svg>
-    <svg
-      v-if="showServerInfo"
-      class="link-topo-aside-btn icon cp lg"
-      @click="show = !show"
-      :style="`position:absolute;left:290px;transform: rotate(${show ? 0 : 180}deg);top:45px;`"
-    >
-      <use xlink:href="#chevron-left" />
-    </svg>
     <TopoService />
-    <div v-if="show">
-      <div class="link-topo-aside-box" style="top:45px" v-if="!stateTopo.selectedServiceCall && showServerInfo">
-        <div class="mb-20">
-          <span class="b dib mr-20">{{ $t('serviceDetail') }}</span>
-        </div>
-        <div class="mb-10">
-          <span class="label grey">{{ $t('name') }}</span>
-          <span class="content">{{ stateTopo.currentNode.name }}</span>
-        </div>
-        <div class="mb-10">
-          <span class="label grey">{{ $t('type') }}</span>
-          <span class="content">{{ stateTopo.currentNode.type }}</span>
-        </div>
-        <div>
-          <TopoChart
-            v-if="stateTopo.serviceApdexScore.length"
-            :data="stateTopo.serviceApdexScore"
-            :intervalTime="intervalTime"
-            title="Service ApdexScore"
-            unit=""
-          />
-          <TopoChart
-            v-if="stateTopo.serviceSLA.length"
-            :data="stateTopo.serviceSLA"
-            :intervalTime="intervalTime"
-            :title="$t('avgSLA')"
-            unit=""
-          />
-        </div>
-      </div>
-      <TopoDetectPoint />
-    </div>
+    <TopoDetectPoint />
   </aside>
 </template>
 <script lang="ts">
   import { initState } from '@/store/modules/dashboard/dashboard-data-layout';
   import { State as topoState } from '@/store/modules/topology';
-  import { Component, Vue, Watch } from 'vue-property-decorator';
+  import { Component, Vue } from 'vue-property-decorator';
   import { Action, Getter, Mutation, State } from 'vuex-class';
-  import Radial from './radial.vue';
-  import TopoChart from './topo-chart.vue';
+  import Radial from './chart/radial.vue';
   import TopoService from './topo-services.vue';
   import TopoDetectPoint from './topo-detect-point.vue';
-  import { DurationTime } from '@/types/global';
-  import compareObj from '@/utils/comparison';
 
   @Component({
     components: {
-      TopoChart,
       TopoService,
       Radial,
       TopoDetectPoint,
@@ -94,38 +51,18 @@ limitations under the License. -->
     @Action('rocketTopo/CLEAR_TOPO_INFO') private CLEAR_TOPO_INFO: any;
     @Mutation('SET_COMPS_TREE') private SET_COMPS_TREE: any;
     @Mutation('rocketTopo/SET_MODE_STATUS') private SET_MODE_STATUS: any;
-    private dialogTopoVisible = false;
-    private drawerMainBodyHeight = '100%';
     private initState = initState;
     private radioStatus: boolean = false;
-    private show: boolean = true;
 
     private get showServerInfo() {
       return this.stateTopo.currentNode.name && this.stateTopo.currentNode.isReal;
     }
 
-    private resize() {
-      this.drawerMainBodyHeight = `${document.body.clientHeight - 50}px`;
-    }
-
     private created() {
       this.SET_COMPS_TREE(this.initState.tree);
     }
 
-    private handleRefresh() {
-      this.$store.dispatch(
-        this.stateTopo.mode ? 'rocketTopo/GET_TOPO_SERVICE_INFO' : 'rocketTopo/GET_TOPO_CLIENT_INFO',
-        { ...this.stateTopo.currentLink, duration: this.durationTime },
-      );
-    }
-
-    private mounted() {
-      this.resize();
-      window.addEventListener('resize', this.resize);
-    }
-
     private beforeDestroy() {
-      window.removeEventListener('resize', this.resize);
       this.CLEAR_TOPO_INFO();
       this.CLEAR_TOPO();
     }
@@ -145,13 +82,6 @@ limitations under the License. -->
     private showRadial() {
       this.radioStatus = !this.radioStatus;
     }
-
-    @Watch('durationTime')
-    private watchDurationTime(newValue: DurationTime, oldValue: DurationTime) {
-      if (compareObj(newValue, oldValue)) {
-        this.handleRefresh();
-      }
-    }
   }
 </script>
 <style lang="scss" scoped>
@@ -167,6 +97,9 @@ limitations under the License. -->
       border-top: 1px solid #d8d8d866;
     }
   }
+  .title {
+    padding: 10px;
+  }
 
   .link-topo-aside-btn {
     display: block;
@@ -185,7 +118,7 @@ limitations under the License. -->
     z-index: 101;
     color: #ddd;
     background-color: #2b3037;
-    padding: 15px 20px 10px;
+    // padding: 15px 20px 10px;
 
     .label {
       display: inline-block;
@@ -215,7 +148,7 @@ limitations under the License. -->
   }
 
   .link-topo-aside-box-min {
-    width: 280px;
+    width: 360px;
     animation: 0.5s linkTopoAsideBoxMin 1 running;
   }
 
diff --git a/src/views/components/topology/topo-chart.vue b/src/views/components/topology/topo-chart.vue
deleted file mode 100644
index 8e017f8..0000000
--- a/src/views/components/topology/topo-chart.vue
+++ /dev/null
@@ -1,94 +0,0 @@
-<!-- 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. -->
-<template>
-  <div>
-    <div class="grey sm mb-5">{{ title }}</div>
-    <h5 class="grey mt-0 mb-0">{{ content.toFixed(2) }} {{ unit }}</h5>
-    <RkEcharts height="100px" :option="responseConfig" />
-  </div>
-</template>
-
-<script lang="ts">
-  import Vue from 'vue';
-  import { Component, Prop } from 'vue-property-decorator';
-
-  @Component
-  export default class TopoChart extends Vue {
-    @Prop() private title!: string;
-    @Prop() private data!: any;
-    @Prop() private unit!: string;
-    @Prop() private intervalTime!: number[];
-    @Prop() private precent!: boolean;
-    get content() {
-      if (!this.data.length) {
-        return 0;
-      }
-      const noZero = this.data.filter((i: any) => i);
-      const sum = noZero.length
-        ? noZero.reduce((preValue: number, curValue: number, index: number, array: number[]) => preValue + curValue) /
-          noZero.length
-        : 0;
-      return this.precent ? sum / 100 : sum;
-    }
-    get responseConfig() {
-      return {
-        color: ['#3f96e3ee', '#6be6c1'],
-        tooltip: {
-          trigger: 'axis',
-          backgroundColor: '#333844',
-          textStyle: {
-            fontSize: 13,
-          },
-        },
-        grid: {
-          top: 4,
-          left: 0,
-          right: 0,
-          bottom: 7,
-          containLabel: true,
-        },
-        xAxis: {
-          type: 'category',
-          axisTick: {
-            lineStyle: { color: '#c1c5ca41' },
-            alignWithLabel: true,
-          },
-          splitLine: { show: false },
-          axisLine: { lineStyle: { color: 'rgba(0,0,0,0)' } },
-          axisLabel: { color: '#9da5b2', fontSize: '11' },
-        },
-        yAxis: {
-          type: 'value',
-          axisLine: { show: false },
-          axisTick: { show: false },
-          splitLine: { lineStyle: { color: '#c1c5ca41', type: 'dashed' } },
-          axisLabel: { color: '#9da5b2', fontSize: '11' },
-        },
-        series: [
-          {
-            data: this.data.map((i: any, index: number) => [this.intervalTime[index], this.precent ? i / 100 : i]),
-            // type: this.precent ? 'bar' : 'line',
-            type: 'line',
-            symbol: 'none',
-            barMaxWidth: 5,
-            lineStyle: {
-              width: 1,
-            },
-          },
-        ],
-      };
-    }
-  }
-</script>
diff --git a/src/views/components/topology/topo-detect-point.vue b/src/views/components/topology/topo-detect-point.vue
index 3697eb3..7365ff7 100644
--- a/src/views/components/topology/topo-detect-point.vue
+++ b/src/views/components/topology/topo-detect-point.vue
@@ -25,90 +25,80 @@ limitations under the License. -->
     >
       <use xlink:href="#chevron-left" />
     </svg>
-    <div class="mb-5 clear">
-      <div v-if="stateTopo.selectedServiceCall">
+    <div class="mb-5 clear flex-h">
+      <span class="tool-title" v-if="stateTopo.selectedServiceCall">
         <span class="b dib mr-20 vm">{{ $t('detectPoint') }}</span>
         <span
           v-if="stateTopo.detectPoints.indexOf('CLIENT') !== -1"
           :class="{ active: !stateTopo.mode }"
           class="link-topo-aside-box-btn tc r sm cp b"
           @click="setMode(false)"
-          >{{ $t('client') }}</span
         >
+          {{ $t('client') }}
+        </span>
         <span
           v-if="stateTopo.detectPoints.indexOf('SERVER') !== -1"
           :class="{ active: stateTopo.mode }"
           class="link-topo-aside-box-btn tc r sm cp b"
           @click="setMode(true)"
-          >{{ $t('server') }}</span
         >
+          {{ $t('server') }}
+        </span>
+      </span>
+      <span v-else-if="showServerInfo" class="b dib vm tool-title">{{ $t('serviceDetail') }}</span>
+      <div class="flex-h">
+        <div class="topo-tool-btn" @click="handleSetEdit">
+          <rk-icon
+            class="lg rk-icon"
+            :style="`color:${!rocketGlobal.edit ? '' : '#ffc107'}`"
+            :icon="!rocketGlobal.edit ? 'lock' : 'lock-open'"
+            v-tooltip:bottom="{ content: rocketGlobal.edit ? 'view' : 'edit' }"
+          />
+        </div>
+        <div class="topo-tool-btn" v-tooltip:bottom="{ content: 'import' }">
+          <input
+            id="tool-bar-file"
+            type="file"
+            name="file"
+            title=""
+            accept=".json"
+            @change="importServiceMetricsTemplate"
+          />
+          <label for="tool-bar-file">
+            <rk-icon class="lg import" icon="folder_open" />
+          </label>
+        </div>
+        <div class="topo-tool-btn" @click="exportTopoServiceMetrics">
+          <rk-icon class="lg" icon="save_alt" v-tooltip:bottom="{ content: 'export' }" />
+        </div>
       </div>
-      <span v-else-if="showServerInfo" class="b dib mr-20 vm">{{ $t('serviceDetail') }}</span>
     </div>
     <div v-if="showInfo">
-      <div v-if="stateTopo.selectedServiceCall">
-        <TopoChart
-          v-if="stateTopo.getResponseTimeTrend.length"
-          :data="stateTopo.getResponseTimeTrend"
-          :intervalTime="intervalTime"
-          :title="$t('avgResponseTime')"
-          unit="ms"
-        />
-        <TopoChart
-          v-if="stateTopo.getThroughputTrend.length"
-          :data="stateTopo.getThroughputTrend"
-          :intervalTime="intervalTime"
-          :title="$t('avgThroughput')"
-          unit="cpm"
-        />
-        <TopoChart
-          v-if="stateTopo.getSLATrend.length"
-          :data="stateTopo.getSLATrend"
-          :intervalTime="intervalTime"
-          :precent="true"
-          :title="$t('avgSLA')"
-          unit=""
-        />
-        <ChartLine
-          v-if="stateTopo.responsePercentile.p50.length"
-          :data="stateTopo.responsePercentile"
-          :intervalTime="intervalTime"
-          :title="$t('percentResponse')"
-        />
-      </div>
-      <div v-else-if="showServerInfo">
-        <TopoChart
-          v-if="stateTopo.serviceResponseTime.length"
-          :data="stateTopo.serviceResponseTime"
-          :intervalTime="intervalTime"
-          title="Service ResponseTime"
-          unit="ms"
-        />
-        <TopoChart
-          v-if="stateTopo.serviceThroughput.length"
-          :data="stateTopo.serviceThroughput"
-          :intervalTime="intervalTime"
-          title="Service Throughput"
-          unit="cpm"
-        />
-        <ChartLine
-          v-if="stateTopo.servicePercentile.p50.length"
-          :data="stateTopo.servicePercentile"
-          :intervalTime="intervalTime"
-          :title="$t('percentResponse')"
+      <div class="pl-10 pb-5 flex-h">
+        <div class="type grey">{{ $t('templateType') }}</div>
+        <RkSelect
+          class="content grey"
+          :mode="'multiple'"
+          :current="currentType"
+          :data="templateTypesList"
+          :theme="'dark'"
+          @onChoose="(item) => changeTemplatesType(item)"
         />
       </div>
+      <TopoServiceDependency v-if="stateTopo.selectedServiceCall" :currentType="currentType" ref="serviceDependency" />
+      <TopoServiceMetrics v-else-if="showServerInfo" :currentType="currentType" ref="serviceTemplate" />
     </div>
     <div class="show-dependency" v-if="stateTopo.selectedServiceCall">
       <a class="rk-btn lg" @click="openInstanceModal">{{ $t('ShowInstanceDependency') }}</a>
       <rk-sidebox
         class="instance-dependency"
-        width="80%"
+        width="100%"
         :fixed="false"
         :title="
           `${stateTopo.selectedServiceCall.source.name} -> ${stateTopo.selectedServiceCall.target.name} Instance Dependency`
         "
         :show.sync="dialogTopoVisible"
+        :closeSideboxCallback="clearInstance"
       >
         <TopoInstanceDependency />
       </rk-sidebox>
@@ -119,25 +109,35 @@ limitations under the License. -->
   import { State as topoState } from '@/store/modules/topology';
   import { Component, Vue, Watch } from 'vue-property-decorator';
   import { Action, Getter, Mutation, State } from 'vuex-class';
-  import TopoChart from './topo-chart.vue';
-  import TopoInstanceDependency from './topo-instance-dependency.vue';
-  import ChartLine from './chart-line.vue';
-  import { DurationTime } from '@/types/global';
+  import TopoInstanceDependency from './dependency/topo-instance-dependency.vue';
+  import { DurationTime, Option } from '@/types/global';
+  import TopoServiceMetrics from './topo-service-metrics.vue';
+  import ToolBarBtns from '../dashboard/tool-bar/tool-bar-btns.vue';
+  import { State as rocketbotGlobal } from '@/store/modules/global';
+  import { State as dataState } from '@/store/modules/dashboard/dashboard-data';
   import compareObj from '@/utils/comparison';
+  import { readFile } from '@/utils/readFile';
+  import { saveFile } from '@/utils/saveFile';
+  import TopoServiceDependency from './dependency/topo-service-dependency.vue';
+  import { DEFAULT, TopologyType } from '@/constants/constant';
 
   @Component({
     components: {
+      TopoServiceMetrics,
       TopoInstanceDependency,
-      TopoChart,
-      ChartLine,
+      TopoServiceDependency,
+      ToolBarBtns,
     },
   })
   export default class TopoDetectPoint extends Vue {
+    @State('rocketData') private rocketComps!: dataState;
+    @State('rocketbot') private rocketGlobal!: rocketbotGlobal;
     @State('rocketTopo') private stateTopo!: topoState;
     @Getter('intervalTime') private intervalTime: any;
-    @Getter('durationTime') private durationTime: any;
+    @Getter('durationTime') private durationTime!: DurationTime;
     @Action('MIXHANDLE_CHANGE_GROUP_WITH_CURRENT')
     private MIXHANDLE_CHANGE_GROUP_WITH_CURRENT: any;
+    @Action('SET_EDIT') private SET_EDIT: any;
     @Mutation('rocketTopo/SET_MODE_STATUS') private SET_MODE_STATUS: any;
     @Mutation('rocketTopo/SET_SELECTED_INSTANCE_CALL')
     private SET_SELECTED_INSTANCE_CALL: any;
@@ -146,17 +146,80 @@ limitations under the License. -->
     @Action('rocketTopo/CLEAR_TOPO_INFO') private CLEAR_TOPO_INFO: any;
     @Action('rocketTopo/GET_TOPO_INSTANCE_DEPENDENCY')
     private GET_INSTANCE_DEPENDENCY: any;
-    @Action('rocketTopo/GET_TOPO_SERVICE_DETAIL') private GET_TOPO_SERVICE_DETAIL: any;
+    @Mutation('rocketTopo/IMPORT_TREE_SERVICE') private IMPORT_TREE_SERVICE: any;
+    @Mutation('rocketTopo/IMPORT_TREE_SERVICE_DEPENDENCY') private IMPORT_TREE_SERVICE_DEPENDENCY: any;
+    @Mutation('UPDATE_DASHBOARD') private UPDATE_DASHBOARD: any;
+    @Mutation('rocketTopo/EDIT_DEPENDENCY_METRICS') private EDIT_DEPENDENCY_METRICS: any;
+    @Mutation('rocketTopo/UPDATE_TOPO_TEMPLATE_TYPES') private UPDATE_TOPO_TEMPLATE_TYPES: any;
 
     private isMini: boolean = true;
     private showInfoCount: number = 0;
     private showInfo: boolean = false;
     private dialogTopoVisible = false;
+    private templateTypesList: Option[] = [];
+    private currentType: Option[] = [{ key: '', label: '' }];
 
     private get showServerInfo() {
       return this.stateTopo.currentNode.name && this.stateTopo.currentNode.isReal;
     }
 
+    private changeTemplatesType(item: any) {
+      let topoTemplateTypes;
+      const types = this.stateTopo.topoTemplatesType;
+
+      if (this.currentType.find((d) => d.key === item.key)) {
+        this.deleteTemplateTypes(item);
+        return;
+      }
+      this.currentType.push(item);
+      if (this.showServerInfo) {
+        const nodeType = this.stateTopo.currentNode.type || DEFAULT;
+
+        topoTemplateTypes = {
+          ...types,
+          [TopologyType.TOPOLOGY_SERVICE]: { [nodeType]: this.currentType },
+        };
+      } else {
+        if (!(this.stateTopo.selectedServiceCall && this.stateTopo.selectedServiceCall.source)) {
+          return;
+        }
+        const callType = this.stateTopo.selectedServiceCall.source.type || DEFAULT;
+
+        topoTemplateTypes = {
+          ...types,
+          [TopologyType.TOPOLOGY_SERVICE_DEPENDENCY]: { [callType]: this.currentType },
+        };
+      }
+      this.UPDATE_TOPO_TEMPLATE_TYPES(topoTemplateTypes);
+    }
+
+    private deleteTemplateTypes(item: any) {
+      let topoTemplateTypes = null;
+      const types = this.stateTopo.topoTemplatesType;
+      const index = this.currentType.findIndex((d) => item.key === d.key);
+
+      this.currentType.splice(index, 1);
+      if (this.showServerInfo) {
+        const nodeType = this.stateTopo.currentNode.type || DEFAULT;
+
+        topoTemplateTypes = {
+          ...types,
+          [TopologyType.TOPOLOGY_SERVICE]: { [nodeType]: this.currentType },
+        };
+      } else {
+        if (!(this.stateTopo.selectedServiceCall && this.stateTopo.selectedServiceCall.source)) {
+          return;
+        }
+        const callType = this.stateTopo.selectedServiceCall.source.type || DEFAULT;
+
+        topoTemplateTypes = {
+          ...types,
+          [TopologyType.TOPOLOGY_SERVICE_DEPENDENCY]: { [callType]: this.currentType },
+        };
+      }
+      this.UPDATE_TOPO_TEMPLATE_TYPES(topoTemplateTypes);
+    }
+
     private setShowInfo() {
       this.showInfo = false;
       this.showInfoCount = 1;
@@ -166,14 +229,18 @@ limitations under the License. -->
       }, 550);
     }
 
+    private handleSetEdit() {
+      this.SET_EDIT(!this.rocketGlobal.edit);
+    }
+
     private setMode(mode: boolean) {
       this.SET_MODE_STATUS(mode);
-      this.stateTopo.callback();
     }
 
     private clearInstance() {
       this.dialogTopoVisible = false;
       this.SET_SELECTED_INSTANCE_CALL(null);
+      this.EDIT_DEPENDENCY_METRICS(false);
     }
 
     private openInstanceModal() {
@@ -189,15 +256,70 @@ limitations under the License. -->
       });
     }
 
+    private async importServiceMetricsTemplate(event: Event) {
+      try {
+        const data: any = await readFile(event);
+        if (!Array.isArray(data)) {
+          throw new Error();
+        }
+        if (this.showServerInfo) {
+          this.IMPORT_TREE_SERVICE(data[0]);
+          const service: any = this.$refs.serviceTemplate;
+          service.setServiceTemplates();
+        } else {
+          this.IMPORT_TREE_SERVICE_DEPENDENCY(data[0]);
+          const serviceDependency: any = this.$refs.serviceDependency;
+          serviceDependency.setServiceDependencyTemplates();
+        }
+        const el: any = document.getElementById('tool-bar-file');
+        el!.value = '';
+      } catch (e) {
+        this.$modal.show('dialog', { text: 'ERROR' });
+      }
+    }
+
+    private exportTopoServiceMetrics() {
+      let name = '';
+      let group: any = {};
+
+      if (this.showServerInfo) {
+        name = 'topo_service_metrics.json';
+        for (const type of Object.keys(this.stateTopo.topoServices)) {
+          const metricsTemp = this.stateTopo.topoServices[type].map((item: any) => {
+            delete item.uuid;
+            return item;
+          });
+          group = {
+            ...group,
+            [type]: metricsTemp,
+          };
+        }
+      } else {
+        name = 'topo_service_dependency_metrics.json';
+        for (const type of Object.keys(this.stateTopo.topoServicesDependency)) {
+          for (const mode of ['server', 'client']) {
+            const m: any = mode;
+            const metricsTemp = this.stateTopo.topoServicesDependency[type][m].map((item: any) => {
+              delete item.uuid;
+              return item;
+            });
+            group = {
+              ...group,
+              [type]: {
+                ...group[type],
+                [m]: metricsTemp,
+              },
+            };
+          }
+        }
+      }
+      saveFile([group], name);
+    }
+
     @Watch('durationTime')
     private watchDurationTime(newValue: DurationTime, oldValue: DurationTime) {
       if (compareObj(newValue, oldValue)) {
-        const service = this.stateTopo.currentNode;
-
-        this.GET_TOPO_SERVICE_DETAIL({
-          serviceId: service.id || '',
-          duration: this.durationTime,
-        });
+        this.UPDATE_DASHBOARD();
       }
     }
 
@@ -205,10 +327,27 @@ limitations under the License. -->
     private watchDetectPointNodeId(newValue: string) {
       if (newValue || this.stateTopo.currentNode.isReal) {
         this.showInfo = true;
+        if (!(this.stateTopo.selectedServiceCall && this.stateTopo.selectedServiceCall.source)) {
+          return;
+        }
+        const callType = this.stateTopo.selectedServiceCall.source.type || DEFAULT;
+        const topoTemplatesType: any = this.stateTopo.topoTemplatesType;
+
+        this.templateTypesList = Object.keys(this.stateTopo.topoServicesDependency).map((item: string) => {
+          return { label: item, key: item };
+        });
+        if (topoTemplatesType[TopologyType.TOPOLOGY_SERVICE_DEPENDENCY]) {
+          this.currentType = topoTemplatesType[TopologyType.TOPOLOGY_SERVICE_DEPENDENCY][callType] || [
+            { label: DEFAULT, key: DEFAULT },
+          ];
+        } else {
+          this.currentType = [{ label: DEFAULT, key: DEFAULT }];
+        }
       } else {
         this.showInfo = false;
         this.showInfoCount = 0;
         this.isMini = true;
+        this.SET_EDIT(false);
       }
     }
 
@@ -217,22 +356,43 @@ limitations under the License. -->
       const service = this.stateTopo.currentNode;
       if (this.stateTopo.currentNode.isReal) {
         this.MIXHANDLE_CHANGE_GROUP_WITH_CURRENT({ index: 0, current: 1 });
-        this.GET_TOPO_SERVICE_DETAIL({
-          serviceId: service.id || '',
-          duration: this.durationTime,
-        });
+        this.UPDATE_DASHBOARD();
       }
       if (newValue || this.stateTopo.selectedServiceCall) {
         this.showInfo = true;
+        const topoTemplatesType: any = this.stateTopo.topoTemplatesType;
+        const nodeType = this.stateTopo.currentNode.type || DEFAULT;
+
+        this.templateTypesList = Object.keys(this.stateTopo.topoServices).map((item: string) => {
+          return { label: item, key: item };
+        });
+        if (topoTemplatesType[TopologyType.TOPOLOGY_SERVICE]) {
+          this.currentType = topoTemplatesType[TopologyType.TOPOLOGY_SERVICE][nodeType] || [
+            { label: DEFAULT, key: DEFAULT },
+          ];
+        } else {
+          this.currentType = [{ label: DEFAULT, key: DEFAULT }];
+        }
       } else {
         this.showInfo = false;
         this.showInfoCount = 0;
         this.isMini = true;
+        this.SET_EDIT(false);
       }
     }
   }
 </script>
 <style lang="scss">
+  .tool-btns {
+    height: 30px;
+  }
+  #tool-bar-file {
+    display: none;
+  }
+  .topo-tool-btn {
+    margin: 0 3px;
+    cursor: pointer;
+  }
   .link-topo-aside-box-btn {
     color: #626977;
     border: 1px solid;
@@ -244,6 +404,16 @@ limitations under the License. -->
       color: #448dfe;
     }
   }
+  .instance-dependency {
+    .rk-sidebox {
+      background: #2b3037;
+      outline: none;
+      z-index: 200;
+    }
+    .rk-sidebox-inner {
+      height: 100%;
+    }
+  }
 
   .show-dependency {
     margin-top: 20px;
@@ -258,14 +428,9 @@ limitations under the License. -->
       padding-left: 40px;
       font-size: 16px;
     }
-  }
-  .instance-dependency {
-    .rk-sidebox {
-      background: #2b3037;
-      outline: none;
-    }
-    .rk-sidebox-inner {
-      height: 100%;
+
+    .rk-sidebox-title {
+      color: #eee;
     }
   }
 
@@ -276,17 +441,25 @@ limitations under the License. -->
     z-index: 101;
     color: #ddd;
     background-color: #2b3037;
-    padding: 15px 20px 10px;
 
     .label {
       display: inline-block;
       width: 40%;
     }
 
+    .type {
+      display: inline-block;
+      width: 100px;
+    }
+
+    .tool-title {
+      padding: 10px;
+    }
+
     .content {
       vertical-align: top;
       display: inline-block;
-      width: 60%;
+      width: 67%;
     }
 
     .circle {
diff --git a/src/views/components/topology/topo-endpoint-dependency.vue b/src/views/components/topology/topo-endpoint-dependency.vue
deleted file mode 100644
index 8cfc6b9..0000000
--- a/src/views/components/topology/topo-endpoint-dependency.vue
+++ /dev/null
@@ -1,126 +0,0 @@
-<!-- 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. -->
-<template>
-  <div class="rk-endpoint-dependency">
-    <div class="endpoint-dependency-chart">
-      <DependencySankey
-        v-if="stateTopo.endpointDependency.nodes.length"
-        :data="stateTopo.endpointDependency"
-        @showMetrics="showEndpointMetrics"
-      />
-      <div v-else class="endpoint-dependency-empty">
-        No Endpoint Dependency
-      </div>
-    </div>
-    <div class="endpoint-dependency-metrics">
-      <div v-if="respTime.length">
-        <TopoChart :data="respTime" :intervalTime="intervalTime" :title="$t('avgResponseTime')" unit="ms" />
-      </div>
-      <div v-if="cpm.length">
-        <TopoChart :data="cpm" :intervalTime="intervalTime" :title="$t('avgThroughput')" unit="cpm" />
-      </div>
-      <div v-if="sla.length">
-        <TopoChart :data="sla" :intervalTime="intervalTime" :precent="true" :title="$t('avgSLA')" unit="" />
-      </div>
-      <div v-if="percentile.p50">
-        <ChartLine :data="percentile" :intervalTime="intervalTime" :title="$t('percentResponse')" />
-      </div>
-    </div>
-  </div>
-</template>
-<script lang="ts">
-  import { Vue, Component, Watch } from 'vue-property-decorator';
-  import { State, Action, Getter } from 'vuex-class';
-  import { State as topoState, EndpointDependencyConidition, Call, Duration } from '@/store/modules/topology';
-  import TopoChart from './topo-chart.vue';
-  import DependencySankey from './dependency-sankey.vue';
-  import ChartLine from './chart-line.vue';
-
-  @Component({
-    components: {
-      ChartLine,
-      TopoChart,
-      DependencySankey,
-    },
-  })
-  export default class TopoEndpointDependency extends Vue {
-    @Getter('durationTime') private durationTime!: Duration;
-    @Getter('intervalTime') private intervalTime: any;
-    @State('rocketTopo') private stateTopo!: topoState;
-    @Action('rocketTopo/GET_ENDPOINT_DEPENDENCY_METRICS') private GET_ENDPOINT_DEPENDENCY_METRICS: any;
-
-    private respTime: number[] = [];
-    private cpm: number[] = [];
-    private sla: number[] = [];
-    private percentile: { [key: string]: number[] } = {};
-
-    private showEndpointMetrics(data: EndpointDependencyConidition & Call) {
-      this.GET_ENDPOINT_DEPENDENCY_METRICS({
-        serviceName: data.serviceName,
-        endpointName: data.endpointName,
-        destServiceName: data.destServiceName,
-        destEndpointName: data.destEndpointName,
-        duration: this.durationTime,
-      }).then(() => {
-        this.updateMetrics();
-      });
-    }
-
-    @Watch('stateTopo.endpointDependency.nodes')
-    private updateMetrics() {
-      this.respTime = this.stateTopo.endpointDependencyMetrics.respTime;
-      this.cpm = this.stateTopo.endpointDependencyMetrics.cpm;
-      this.sla = this.stateTopo.endpointDependencyMetrics.sla;
-      this.percentile = this.stateTopo.endpointDependencyMetrics.percentile;
-    }
-
-    private beforeDestroy() {
-      this.stateTopo.endpointDependency = {
-        calls: [],
-        nodes: [],
-      };
-    }
-  }
-</script>
-<style lang="scss" scoped>
-  .rk-endpoint-dependency {
-    background: #333840;
-    height: 100%;
-    display: flex;
-    flex-direction: column;
-    overflow: auto;
-    .endpoint-dependency-chart {
-      height: 80%;
-      min-height: 500px;
-    }
-    .endpoint-dependency-empty {
-      color: #fff;
-      text-align: center;
-      height: 500px;
-      line-height: 500px;
-    }
-  }
-  .endpoint-dependency-metrics {
-    height: 20%;
-    min-height: 100px;
-    display: flex;
-    flex-direction: row;
-    padding-left: 10px;
-    > div {
-      width: 25%;
-      height: 100%;
-    }
-  }
-</style>
diff --git a/src/views/components/topology/topo-instance-dependency.vue b/src/views/components/topology/topo-instance-dependency.vue
deleted file mode 100644
index 0a8ba60..0000000
--- a/src/views/components/topology/topo-instance-dependency.vue
+++ /dev/null
@@ -1,148 +0,0 @@
-<!-- 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. -->
-<template>
-  <div class="rk-topo-instance-dependency">
-    <div class="rk-dependency-chart">
-      <DependencySankey :data="stateTopo.instanceDependency" @showMetrics="showDependencyMetrics" />
-    </div>
-    <div class="rk-instance-metric-box">
-      <div v-if="!stateTopo.instanceDependency.nodes.length">
-        No Instance Dependency
-      </div>
-      <div v-if="stateTopo.selectedInstanceCall" class="rk-instance-dependency-metrics">
-        <div class="mb-5 clear">
-          <span class="b dib mr-20 vm">{{ $t('detectPoint') }}</span>
-          <span
-            v-if="stateTopo.selectedInstanceCall.detectPoints.includes('CLIENT')"
-            class="link-topo-aside-box-btn tc r sm cp b"
-            :class="{ active: stateTopo.queryInstanceMetricsType === 'CLIENT' }"
-            @click="setMode('CLIENT')"
-            >{{ $t('client') }}</span
-          >
-          <span
-            v-if="stateTopo.selectedInstanceCall.detectPoints.includes('SERVER')"
-            class="link-topo-aside-box-btn tc r sm cp b"
-            :class="{ active: stateTopo.queryInstanceMetricsType === 'SERVER' }"
-            @click="setMode('SERVER')"
-            >{{ $t('server') }}</span
-          >
-        </div>
-        <div v-if="stateTopo.selectedInstanceCall">
-          <TopoChart
-            v-if="stateTopo.instanceDependencyMetrics.getResponseTimeTrend"
-            :data="stateTopo.instanceDependencyMetrics.getResponseTimeTrend"
-            :intervalTime="intervalTime"
-            :title="$t('avgResponseTime')"
-            unit="ms"
-          />
-          <TopoChart
-            v-if="stateTopo.instanceDependencyMetrics.getThroughputTrend"
-            :data="stateTopo.instanceDependencyMetrics.getThroughputTrend"
-            :intervalTime="intervalTime"
-            :title="$t('avgThroughput')"
-            unit="cpm"
-          />
-          <TopoChart
-            v-if="stateTopo.instanceDependencyMetrics.getSLATrend"
-            :data="stateTopo.instanceDependencyMetrics.getSLATrend"
-            :intervalTime="intervalTime"
-            :precent="true"
-            :title="$t('avgSLA')"
-            unit="%"
-          />
-          <ChartLine
-            v-if="stateTopo.instanceDependencyMetrics.percentResponse"
-            :data="stateTopo.instanceDependencyMetrics.percentResponse"
-            :intervalTime="intervalTime"
-            :title="$t('percentResponse')"
-          />
-        </div>
-      </div>
-    </div>
-  </div>
-</template>
-<script lang="ts">
-  import { Vue, Component } from 'vue-property-decorator';
-  import { State, Action, Getter, Mutation } from 'vuex-class';
-  import { State as topoState } from '@/store/modules/topology';
-  import Topo from './chart/topo.vue';
-  import TopoChart from './topo-chart.vue';
-  import DependencySankey from './dependency-sankey.vue';
-  import ChartLine from './chart-line.vue';
-
-  @Component({
-    components: {
-      Topo,
-      ChartLine,
-      TopoChart,
-      DependencySankey,
-    },
-  })
-  export default class TopoInstanceDependency extends Vue {
-    @Getter('durationTime') private durationTime: any;
-    @State('rocketTopo') private stateTopo!: topoState;
-    @Getter('intervalTime') private intervalTime: any;
-    @Mutation('rocketTopo/SET_INSTANCE_DEPEDENCE_TYPE')
-    private SET_MODE_STATUS: any;
-    @Action('rocketTopo/GET_INSTANCE_DEPENDENCY_METRICS')
-    private GET_INSTANCE_DEPENDENCY_METRICS: any;
-
-    private showInfo: boolean = true;
-
-    private setMode(mode: string) {
-      this.GET_INSTANCE_DEPENDENCY_METRICS({
-        ...this.stateTopo.selectedInstanceCall,
-        durationTime: this.durationTime,
-        mode,
-      });
-    }
-    private showDependencyMetrics(data: any) {
-      this.GET_INSTANCE_DEPENDENCY_METRICS({
-        ...data,
-        durationTime: this.durationTime,
-        mode: data.detectPoints[0],
-      });
-    }
-  }
-</script>
-<style lang="scss" scoped>
-  .rk-topo-instance-dependency {
-    height: 100%;
-    display: flex;
-    flex-direction: row;
-    background: #2b3037;
-    & > :first-child {
-      line-height: 400px;
-      text-align: center;
-      width: 100%;
-    }
-    .rk-instance-metric-box {
-      height: 100%;
-      display: flex;
-      align-items: center;
-    }
-    .rk-instance-dependency-metrics {
-      width: 320px;
-      height: 650px;
-      margin-top: 10px;
-      background: #252a2f;
-      padding: 20px;
-    }
-    .rk-dependency-chart {
-      width: 850px;
-      height: 100%;
-    }
-  }
-</style>
diff --git a/src/views/components/topology/topo-service-metrics.vue b/src/views/components/topology/topo-service-metrics.vue
new file mode 100644
index 0000000..292cb51
--- /dev/null
+++ b/src/views/components/topology/topo-service-metrics.vue
@@ -0,0 +1,129 @@
+<!-- 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. -->
+<template>
+  <div class="service-metrics scroll_bar_style" :style="`height: ${height}px`">
+    <DashboardItem
+      v-for="(i, index) in serviceComps || []"
+      :rocketGlobal="rocketGlobal"
+      :item="i"
+      :index="index"
+      :key="i.uuid"
+      :type="type"
+      :updateObjects="true"
+      :rocketOption="stateDashboardOption"
+      :templateTypes="setTemplateTypes()"
+      @setTemplates="setServiceTemplates"
+    />
+    <div v-show="rocketGlobal.edit" class="rk-add-metric-item g-sm-3" @click="addComp">
+      + Add An Item
+    </div>
+  </div>
+</template>
+<script lang="ts">
+  import { State as topoState } from '@/store/modules/topology';
+  import { Component, Vue, Prop, Watch } from 'vue-property-decorator';
+  import { State, Mutation } from 'vuex-class';
+  import { State as optionState } from '@/store/modules/global/selectors';
+  import { State as rocketbotGlobal } from '@/store/modules/global';
+  import DashboardItem from '@/views/components/dashboard/dashboard-item.vue';
+  import { DEFAULT, TopologyType } from '@/constants/constant';
+  import { Option } from '@/types/global';
+  import { uuid } from '@/utils/uuid';
+
+  @Component({
+    components: {
+      DashboardItem,
+    },
+  })
+  export default class TopoServiceMetrics extends Vue {
+    @Prop() private currentType!: Option;
+    @State('rocketOption') private stateDashboardOption!: optionState;
+    @State('rocketbot') private rocketGlobal!: rocketbotGlobal;
+    @State('rocketTopo') private stateTopo!: topoState;
+    @Mutation('rocketTopo/ADD_TOPO_SERVICE_COMP') private ADD_TOPO_SERVICE_COMP: any;
+    @Mutation('rocketTopo/SET_TOPO_SERVICE') private SET_TOPO_SERVICE: any;
+
+    private serviceComps: unknown[] = [];
+    private height: number = 800;
+    private default = DEFAULT;
+    private type: string = '';
+
+    private beforeMount() {
+      this.type = TopologyType.TOPOLOGY_SERVICE;
+      this.height = document.body.clientHeight - 230;
+      this.setServiceTemplates();
+    }
+
+    private addComp() {
+      this.ADD_TOPO_SERVICE_COMP();
+      this.setServiceTemplates();
+    }
+
+    private setServiceTemplates() {
+      const templateTypes = this.setTemplateTypes();
+      this.serviceComps = [];
+      let templates: any = {};
+      for (const type of Object.keys(this.stateTopo.topoServices)) {
+        const metricsTemp = this.stateTopo.topoServices[type].map((item: any) => {
+          item.uuid = item.uuid || uuid();
+          return item;
+        });
+        templates = {
+          ...templates,
+          [type]: metricsTemp,
+        };
+      }
+      this.SET_TOPO_SERVICE(templates);
+      for (const type of templateTypes) {
+        this.serviceComps = [...this.serviceComps, ...this.stateTopo.topoServices[type]];
+      }
+    }
+
+    private setTemplateTypes() {
+      let templateTypes = [];
+      const nodeType = this.stateTopo.currentNode.type;
+      const templates = this.stateTopo.topoTemplatesType;
+
+      if (templates[TopologyType.TOPOLOGY_SERVICE] && templates[TopologyType.TOPOLOGY_SERVICE][nodeType]) {
+        templateTypes = templates[TopologyType.TOPOLOGY_SERVICE][nodeType].map((item: Option) => item.key);
+      } else {
+        templateTypes = this.stateTopo.topoServices[nodeType] ? [nodeType] : [DEFAULT];
+      }
+
+      return templateTypes;
+    }
+
+    @Watch('currentType')
+    private updateServiceMetrics() {
+      this.setServiceTemplates();
+    }
+  }
+</script>
+<style lang="scss">
+  .service-metrics {
+    overflow: auto;
+  }
+  .rk-add-metric-item {
+    height: 200px;
+    text-align: center;
+    line-height: 250px;
+    border: 1px dashed rgba(196, 200, 225, 0.5);
+    cursor: pointer;
+    display: inline-block;
+    font-size: 16px;
+    width: 340px;
+    margin-left: 5px;
+  }
+</style>
diff --git a/src/views/containers/dashboard.vue b/src/views/containers/dashboard.vue
index dd0545e..52ed14e 100644
--- a/src/views/containers/dashboard.vue
+++ b/src/views/containers/dashboard.vue
@@ -32,7 +32,7 @@ limitations under the License. -->
         :index="index"
         :rocketGlobal="rocketGlobal"
         :item="i"
-        :updateObjects="ObjectsType.UPDATE_DASHBOARD"
+        :updateObjects="true"
         :rocketOption="stateDashboardOption"
       >
       </DashboardItem>
@@ -50,7 +50,6 @@ limitations under the License. -->
   import ToolGroup from '@/views/components/dashboard/tool-group.vue';
   import ToolNav from '@/views/components/dashboard/tool-nav.vue';
   import DashboardItem from '@/views/components/dashboard/dashboard-item.vue';
-  import { ObjectsType } from '../../constants/constant';
   import { State as globalState } from '@/store/modules/global';
   import { State as optionState } from '@/store/modules/global/selectors';
   import { State as dataState } from '@/store/modules/dashboard/dashboard-data';
@@ -84,8 +83,6 @@ limitations under the License. -->
     @Mutation('SET_EDIT') private SET_EDIT: any;
     @Mutation('SET_TEMPLATES') private SET_TEMPLATES: any;
 
-    private ObjectsType = ObjectsType;
-
     private isRouterAlive: boolean = true;
     public reload(): void {
       this.isRouterAlive = false;
@@ -150,4 +147,19 @@ limitations under the License. -->
     display: inline-block;
     font-size: 16px;
   }
+  .dashboard-container {
+    overflow: auto;
+    padding: 20px 15px;
+    height: 100%;
+    flex-grow: 1;
+  }
+  .rk-add-dashboard-item {
+    height: 342px;
+    text-align: center;
+    line-height: 250px;
+    border: 1px dashed rgba(196, 200, 225, 0.5);
+    cursor: pointer;
+    display: inline-block;
+    font-size: 16px;
+  }
 </style>
diff --git a/src/views/containers/topology/endpoint-dependency/index.vue b/src/views/containers/topology/endpoint-dependency/index.vue
index 6bcf0ee..c064fad 100644
--- a/src/views/containers/topology/endpoint-dependency/index.vue
+++ b/src/views/containers/topology/endpoint-dependency/index.vue
@@ -41,7 +41,7 @@ limitations under the License. -->
   import { Action, Getter, State, Mutation } from 'vuex-class';
   import ToolBarSelect from '@/views/components/dashboard/tool-bar/tool-bar-select.vue';
   import ToolBarEndpointSelect from '@/views/components/dashboard/tool-bar/tool-bar-endpoint-select.vue';
-  import TopoEndpointDependency from '@/views/components/topology/topo-endpoint-dependency.vue';
+  import TopoEndpointDependency from '@/views/components/topology/dependency/topo-endpoint-dependency.vue';
 
   @Component({
     components: {
@@ -56,7 +56,6 @@ limitations under the License. -->
     @Getter('durationTime') private durationTime: any;
     @Mutation('SET_CURRENT_SERVICE') private SET_CURRENT_SERVICE: any;
     @Mutation('SET_EDIT') private SET_EDIT: any;
-    @Mutation('rocketTopo/SET_ENDPOINT_DEPENDENCY_METRICS') private SET_ENDPOINT_DEPENDENCY_METRICS: any;
     @Mutation('rocketTopo/SET_ENDPOINT_DEPTH') private SET_ENDPOINT_DEPTH: any;
     @Action('GET_SERVICE_ENDPOINTS') private GET_SERVICE_ENDPOINTS: any;
     @Action('MIXHANDLE_CHANGE_GROUP_WITH_CURRENT') private MIXHANDLE_CHANGE_GROUP_WITH_CURRENT: any;
@@ -78,7 +77,6 @@ limitations under the License. -->
     private selectEndpoint(i: any) {
       this.SELECT_ENDPOINT({ endpoint: i, duration: this.durationTime });
       this.GET_ALL_ENDPOINT_DEPENDENCY({ endpointIds: [i.key], duration: this.durationTime });
-      this.SET_ENDPOINT_DEPENDENCY_METRICS({ respTime: [], sla: [], cpm: [], percentile: {} });
     }
 
     private selectDepth(i: { key: number; label: string }) {
@@ -87,8 +85,6 @@ limitations under the License. -->
         endpointIds: [this.stateDashboardOption.currentEndpoint.key],
         duration: this.durationTime,
       });
-
-      this.SET_ENDPOINT_DEPENDENCY_METRICS({ respTime: [], sla: [], cpm: [], percentile: {} });
     }
 
     private beforeDestroy() {
diff --git a/src/views/containers/topology/endpoint/endpoints-survey.vue b/src/views/containers/topology/endpoint/endpoints-survey.vue
index 2f95aad..e18d669 100644
--- a/src/views/containers/topology/endpoint/endpoints-survey.vue
+++ b/src/views/containers/topology/endpoint/endpoints-survey.vue
@@ -16,16 +16,18 @@ limitations under the License. -->
 <template>
   <div class="dashboard-container clear">
     <DashboardItem
-      v-for="(i, index) in endpointComps || []"
-      :key="index + i.title + i.width"
+      v-for="(i, index) in topoEndpoints || []"
+      :key="i.uuid"
       :rocketGlobal="rocketGlobal"
       :item="i"
       :index="index"
-      :type="'TOPOLOGY_ENDPOINT'"
+      :type="type"
       :updateObjects="updateObjects"
       :rocketOption="stateDashboardOption"
+      :templateTypes="templateTypes"
+      @setTemplates="setTemplates"
     />
-    <div v-show="rocketGlobal.edit" class="rk-add-dashboard-item g-sm-3" @click="ADD_TOPO_ENDPOINT_COMP">
+    <div v-show="rocketGlobal.edit" class="rk-add-dashboard-item g-sm-3" @click="addMetrics()">
       + Add An Item
     </div>
   </div>
@@ -33,10 +35,14 @@ limitations under the License. -->
 
 <script lang="ts">
   import Vue from 'vue';
-  import { Component, Prop } from 'vue-property-decorator';
+  import { Component, Prop, Watch } from 'vue-property-decorator';
   import { State, Mutation } from 'vuex-class';
+  import { State as topoState } from '@/store/modules/topology';
   import { State as optionState } from '@/store/modules/global/selectors';
   import DashboardItem from '@/views/components/dashboard/dashboard-item.vue';
+  import { TopologyType, DEFAULT } from '@/constants/constant';
+  import { Option } from '@/types/global';
+  import { uuid } from '@/utils/uuid';
 
   @Component({
     components: {
@@ -44,10 +50,82 @@ limitations under the License. -->
     },
   })
   export default class InstancesSurvey extends Vue {
+    @State('rocketTopo') private stateTopo!: topoState;
     @State('rocketbot') private rocketGlobal: any;
     @State('rocketOption') private stateDashboardOption!: optionState;
     @Mutation('rocketTopo/ADD_TOPO_ENDPOINT_COMP') private ADD_TOPO_ENDPOINT_COMP: any;
-    @Prop() private endpointComps: any;
-    @Prop() private updateObjects!: string;
+    @Mutation('rocketTopo/SET_TOPO_ENDPOINT') private SET_TOPO_ENDPOINT: any;
+    @Prop() private currentType!: Option[];
+
+    private type = TopologyType.TOPOLOGY_ENDPOINT;
+    private topoEndpoints: unknown[] = [];
+    private templateTypes: string[] = [];
+    private updateObjects: boolean = false;
+
+    private beforeMount() {
+      this.setEndpointTemplates();
+    }
+
+    private async addMetrics() {
+      await this.ADD_TOPO_ENDPOINT_COMP();
+      this.setEndpointTemplates();
+    }
+
+    private setTemplates() {
+      this.updateObjects = true;
+      this.setEndpointTemplates();
+    }
+
+    private setEndpointTemplates() {
+      this.setTemplateTypes();
+      this.topoEndpoints = [];
+      let templates: any = {};
+      for (const type of Object.keys(this.stateTopo.topoEndpoints)) {
+        const metricsTemp = this.stateTopo.topoEndpoints[type].map((item: any) => {
+          item.uuid = item.uuid || uuid();
+          return item;
+        });
+        templates = {
+          ...templates,
+          [type]: metricsTemp,
+        };
+      }
+      this.SET_TOPO_ENDPOINT(templates);
+      for (const type of this.templateTypes) {
+        this.topoEndpoints = [...this.topoEndpoints, ...this.stateTopo.topoEndpoints[type]];
+      }
+    }
+
+    private setTemplateTypes() {
+      const nodeType = this.stateTopo.currentNode.type || DEFAULT;
+      const templates = this.stateTopo.topoTemplatesType;
+      if (templates[TopologyType.TOPOLOGY_ENDPOINT] && templates[TopologyType.TOPOLOGY_ENDPOINT][nodeType]) {
+        this.templateTypes = templates[TopologyType.TOPOLOGY_ENDPOINT][nodeType].map((item: Option) => item.key);
+      } else {
+        this.templateTypes = this.stateTopo.topoEndpoints[nodeType] ? [nodeType] : [DEFAULT];
+      }
+    }
+
+    @Watch('currentType')
+    private updateMetrics() {
+      this.setTemplates();
+    }
   }
 </script>
+<style lang="scss" scoped>
+  .rk-add-dashboard-item {
+    height: 342px;
+    text-align: center;
+    line-height: 250px;
+    border: 1px dashed rgba(196, 200, 225, 0.5);
+    cursor: pointer;
+    display: inline-block;
+    font-size: 16px;
+  }
+  .dashboard-container {
+    overflow: auto;
+    padding: 20px 15px;
+    height: 100%;
+    flex-grow: 1;
+  }
+</style>
diff --git a/src/views/containers/topology/endpoint/index.vue b/src/views/containers/topology/endpoint/index.vue
index 4cc39bf..0a578dc 100644
--- a/src/views/containers/topology/endpoint/index.vue
+++ b/src/views/containers/topology/endpoint/index.vue
@@ -55,6 +55,17 @@ limitations under the License. -->
             :data="stateDashboardOption.endpoints"
             icon="code"
           />
+          <div class="pl-10 pb-5 flex-h">
+            <div class="type grey">{{ $t('templateType') }}</div>
+            <RkSelect
+              class="content grey"
+              :mode="'multiple'"
+              :current="currentType"
+              :data="templateTypesList"
+              :theme="'dark'"
+              @onChoose="(item) => changeTemplatesType(item)"
+            />
+          </div>
         </div>
         <DashboardEvent
           :rocketComps="rocketComps"
@@ -64,7 +75,7 @@ limitations under the License. -->
         />
       </div>
     </div>
-    <endpoints-survey :endpointComps="endpointComps" :updateObjects="updateObjects" />
+    <endpoints-survey :currentType="currentType" ref="survey" />
   </div>
 </template>
 
@@ -77,14 +88,14 @@ limitations under the License. -->
   import ToolBarEndpointSelect from '@/views/components/dashboard/tool-bar/tool-bar-endpoint-select.vue';
   import { readFile } from '@/utils/readFile';
   import { saveFile } from '@/utils/saveFile';
-  import { ObjectsType } from '../../../../constants/constant';
   import DashboardEvent from '@/views/components/dashboard/tool-bar/dashboard-events.vue';
   import { State as optionState } from '@/store/modules/global/selectors';
   import { State as rocketData } from '@/store/modules/dashboard/dashboard-data';
   import { State as rocketbotGlobal } from '@/store/modules/global';
   import { DurationTime, Option } from '@/types/global';
   import { EntityType } from '@/views/components/dashboard/charts/constant';
-  import { PageEventsType } from '@/constants/constant';
+  import { PageEventsType, TopologyType, DEFAULT } from '@/constants/constant';
+  import { State as topoState } from '@/store/modules/topology';
 
   @Component({
     components: {
@@ -96,20 +107,45 @@ limitations under the License. -->
   })
   export default class WindowEndpoint extends Vue {
     @Prop() private current!: { key: number | string; label: number | string };
-    @Prop() private endpointComps: any;
-    @Prop() private updateObjects!: string;
     @State('rocketOption') private stateDashboardOption!: optionState;
     @State('rocketData') private rocketComps!: rocketData;
     @State('rocketbot') private rocketGlobal!: rocketbotGlobal;
+    @State('rocketTopo') private stateTopo!: topoState;
     @Getter('durationTime') private durationTime!: DurationTime;
-    @Action('SELECT_ENDPOINT') private SELECT_ENDPOINT: any;
     @Mutation('SET_CURRENT_SERVICE') private SET_CURRENT_SERVICE: any;
     @Mutation('SET_EDIT') private SET_EDIT: any;
+    @Mutation('rocketTopo/UPDATE_TOPO_TEMPLATE_TYPES') private UPDATE_TOPO_TEMPLATE_TYPES: any;
+    @Mutation('rocketTopo/SET_TOPO_ENDPOINT') private SET_TOPO_ENDPOINT: any;
     @Action('GET_SERVICE_ENDPOINTS') private GET_SERVICE_ENDPOINTS: any;
     @Action('MIXHANDLE_CHANGE_GROUP_WITH_CURRENT') private MIXHANDLE_CHANGE_GROUP_WITH_CURRENT: any;
     @Action('GET_EVENT') private GET_EVENT: any;
+    @Action('SELECT_ENDPOINT') private SELECT_ENDPOINT: any;
 
     private pageEventsType = PageEventsType;
+    private endpointMetrics: any[] = [];
+    private currentType: Option[] = [{ key: '', label: '' }];
+    private templateTypesList: Option[] = [{ key: '', label: '' }];
+
+    private beforeMount() {
+      this.SET_CURRENT_SERVICE(this.current);
+      this.MIXHANDLE_CHANGE_GROUP_WITH_CURRENT({ index: 0, current: 2 });
+      this.GET_SERVICE_ENDPOINTS({ duration: this.durationTime, serviceId: this.current.key, keyword: '' }).then(() => {
+        this.selectEndpoint(this.stateDashboardOption.endpoints[0]);
+      });
+      this.templateTypesList = Object.keys(this.stateTopo.topoEndpoints).map((item: string) => {
+        return { label: item, key: item };
+      });
+      const topoTemplatesType: any = this.stateTopo.topoTemplatesType;
+      const nodeType = this.stateTopo.currentNode.type || DEFAULT;
+
+      if (topoTemplatesType[TopologyType.TOPOLOGY_ENDPOINT]) {
+        this.currentType = topoTemplatesType[TopologyType.TOPOLOGY_ENDPOINT][nodeType] || [
+          { label: DEFAULT, key: DEFAULT },
+        ];
+      } else {
+        this.currentType = [{ label: DEFAULT, key: DEFAULT }];
+      }
+    }
 
     private selectEndpoint(i: Option) {
       if (!this.rocketComps.enableEvents) {
@@ -131,21 +167,46 @@ limitations under the License. -->
       });
     }
 
-    private beforeMount() {
-      this.SET_CURRENT_SERVICE(this.current);
-      this.MIXHANDLE_CHANGE_GROUP_WITH_CURRENT({ index: 0, current: 2 });
-      this.GET_SERVICE_ENDPOINTS({ duration: this.durationTime, serviceId: this.current.key, keyword: '' }).then(() => {
-        this.selectEndpoint(this.stateDashboardOption.endpoints[0]);
-      });
+    private changeTemplatesType(item: any) {
+      let topoTemplateTypes;
+      const types = this.stateTopo.topoTemplatesType;
+
+      if (this.currentType.find((d: any) => d.key === item.key)) {
+        this.deleteTemplateTypes(item);
+        return;
+      }
+      this.currentType.push(item);
+      const nodeType = this.stateTopo.currentNode.type || DEFAULT;
+
+      topoTemplateTypes = {
+        ...types,
+        [TopologyType.TOPOLOGY_ENDPOINT]: { [nodeType]: this.currentType },
+      };
+      this.UPDATE_TOPO_TEMPLATE_TYPES(topoTemplateTypes);
+    }
+
+    private deleteTemplateTypes(item: Option) {
+      let topoTemplateTypes;
+      const types = this.stateTopo.topoTemplatesType;
+      const index = this.currentType.findIndex((d: any) => item.key === d.key);
+
+      this.currentType.splice(index, 1);
+      const nodeType = this.stateTopo.currentNode.type || DEFAULT;
+
+      topoTemplateTypes = {
+        ...types,
+        [TopologyType.TOPOLOGY_ENDPOINT]: { [nodeType]: this.currentType },
+      };
+      this.UPDATE_TOPO_TEMPLATE_TYPES(topoTemplateTypes);
     }
 
     private async importData(event: any) {
       try {
         const data: any = await readFile(event);
-        if (!Array.isArray(data)) {
-          throw new Error();
-        }
-        this.$emit('changeEndpointComps', { json: data, type: ObjectsType.UPDATE_ENDPOINTS });
+
+        this.SET_TOPO_ENDPOINT(data);
+        const survey: any = this.$refs.survey;
+        survey.setTemplates();
         const el: any = document.getElementById('endpoint-file');
         el!.value = '';
       } catch (e) {
@@ -154,14 +215,24 @@ limitations under the License. -->
     }
 
     private exportData() {
-      const data = this.endpointComps;
+      let topoEndpoints = {};
       const name = 'endpointComps.json';
-      saveFile(data, name);
+      for (const type of Object.keys(this.stateTopo.topoEndpoints)) {
+        const metricsTemp = this.stateTopo.topoEndpoints[type].map((item: any) => {
+          delete item.uuid;
+          return item;
+        });
+        topoEndpoints = {
+          ...topoEndpoints,
+          [type]: metricsTemp,
+        };
+      }
+      saveFile(topoEndpoints, name);
     }
 
     private beforeDestroy() {
       this.SET_EDIT(false);
-      this.$emit('changeEndpointComps', { type: '' });
+      this.$emit('changeEndpointComps', { type: false });
     }
   }
 </script>
@@ -191,4 +262,14 @@ limitations under the License. -->
   .input-label.rk-btn {
     line-height: 22px !important;
   }
+  .type {
+    display: inline-block;
+    width: 100px;
+  }
+
+  .content {
+    vertical-align: top;
+    display: inline-block;
+    width: 300px;
+  }
 </style>
diff --git a/src/views/containers/topology/instance/index.vue b/src/views/containers/topology/instance/index.vue
index b0fae5b..968fc23 100644
--- a/src/views/containers/topology/instance/index.vue
+++ b/src/views/containers/topology/instance/index.vue
@@ -56,16 +56,27 @@ limitations under the License. -->
             :data="stateDashboardOption.instances"
             icon="disk"
           />
+          <div class="pl-10 pb-5 flex-h">
+            <div class="type grey">{{ $t('templateType') }}</div>
+            <RkSelect
+              class="content grey"
+              :mode="'multiple'"
+              :current="currentType"
+              :data="templateTypesList"
+              :theme="'dark'"
+              @onChoose="(item) => changeTemplatesType(item)"
+            />
+          </div>
         </div>
         <DashboardEvent
           :rocketComps="rocketComps"
           :stateDashboard="stateDashboardOption"
           :durationTime="durationTime"
-          :type="pageEventsType.TOPO_INSTANCE_EVENTS"
+          :type="pageEventsType"
         />
       </div>
     </div>
-    <instances-survey :instanceComps="instanceComps" :updateObjects="updateObjects" />
+    <instances-survey :currentType="currentType" ref="survey" />
   </div>
 </template>
 
@@ -78,14 +89,14 @@ limitations under the License. -->
   import ToolBarEndpointSelect from '@/views/components/dashboard/tool-bar/tool-bar-endpoint-select.vue';
   import { readFile } from '@/utils/readFile';
   import { saveFile } from '@/utils/saveFile';
-  import { ObjectsType } from '@/constants/constant';
   import { EntityType } from '@/views/components/dashboard/charts/constant';
   import { DurationTime, Option } from '@/types/global';
   import { State as optionState } from '@/store/modules/global/selectors';
   import { State as rocketData } from '@/store/modules/dashboard/dashboard-data';
   import { State as rocketbotGlobal } from '@/store/modules/global';
   import DashboardEvent from '@/views/components/dashboard/tool-bar/dashboard-events.vue';
-  import { PageEventsType } from '@/constants/constant';
+  import { PageEventsType, DEFAULT, TopologyType } from '@/constants/constant';
+  import { State as topoState } from '@/store/modules/topology';
 
   @Component({
     components: {
@@ -97,11 +108,10 @@ limitations under the License. -->
   })
   export default class WindowInstance extends Vue {
     @Prop() private current!: { key: number | string; label: number | string };
-    @Prop() private instanceComps: any;
-    @Prop() private updateObjects!: string;
     @State('rocketOption') private stateDashboardOption!: optionState;
     @State('rocketData') private rocketComps!: rocketData;
     @State('rocketbot') private rocketGlobal!: rocketbotGlobal;
+    @State('rocketTopo') private stateTopo!: topoState;
     @Getter('durationTime') private durationTime!: DurationTime;
     @Action('SELECT_INSTANCE') private SELECT_INSTANCE: any;
     @Action('GET_SERVICE_INSTANCES') private GET_SERVICE_INSTANCES: any;
@@ -109,8 +119,66 @@ limitations under the License. -->
     @Action('GET_EVENT') private GET_EVENT: any;
     @Mutation('SET_EDIT') private SET_EDIT: any;
     @Mutation('SET_CURRENT_SERVICE') private SET_CURRENT_SERVICE: any;
+    @Mutation('rocketTopo/UPDATE_TOPO_TEMPLATE_TYPES') private UPDATE_TOPO_TEMPLATE_TYPES: any;
+    @Mutation('rocketTopo/SET_TOPO_INSTANCE') private SET_TOPO_INSTANCE: any;
 
-    private pageEventsType = PageEventsType;
+    private pageEventsType = PageEventsType.TOPO_INSTANCE_EVENTS;
+    private currentType: Option[] = [{ key: '', label: '' }];
+    private templateTypesList: Option[] = [{ key: '', label: '' }];
+
+    private beforeMount() {
+      this.SET_CURRENT_SERVICE(this.current);
+      this.MIXHANDLE_CHANGE_GROUP_WITH_CURRENT({ index: 0, current: 3 });
+      this.GET_SERVICE_INSTANCES({ duration: this.durationTime, serviceId: this.current.key }).then(() => {
+        this.selectInstance(this.stateDashboardOption.instances[0]);
+      });
+      this.templateTypesList = Object.keys(this.stateTopo.topoInstances).map((item: string) => {
+        return { label: item, key: item };
+      });
+      const topoTemplatesType: any = this.stateTopo.topoTemplatesType;
+      const nodeType = this.stateTopo.currentNode.type || DEFAULT;
+
+      if (topoTemplatesType[TopologyType.TOPOLOGY_INSTANCE]) {
+        this.currentType = topoTemplatesType[TopologyType.TOPOLOGY_INSTANCE][nodeType] || [
+          { label: DEFAULT, key: DEFAULT },
+        ];
+      } else {
+        this.currentType = [{ label: DEFAULT, key: DEFAULT }];
+      }
+    }
+
+    private changeTemplatesType(item: Option) {
+      let topoTemplateTypes;
+      const types = this.stateTopo.topoTemplatesType;
+
+      if (this.currentType.find((d) => d.key === item.key)) {
+        this.deleteTemplateTypes(item);
+        return;
+      }
+      this.currentType.push(item);
+      const nodeType = this.stateTopo.currentNode.type || DEFAULT;
+
+      topoTemplateTypes = {
+        ...types,
+        [TopologyType.TOPOLOGY_INSTANCE]: { [nodeType]: this.currentType },
+      };
+      this.UPDATE_TOPO_TEMPLATE_TYPES(topoTemplateTypes);
+    }
+
+    private deleteTemplateTypes(item: Option) {
+      let topoTemplateTypes;
+      const types = this.stateTopo.topoTemplatesType;
+      const index = this.currentType.findIndex((d) => item.key === d.key);
+
+      this.currentType.splice(index, 1);
+      const nodeType = this.stateTopo.currentNode.type || DEFAULT;
+
+      topoTemplateTypes = {
+        ...types,
+        [TopologyType.TOPOLOGY_INSTANCE]: { [nodeType]: this.currentType },
+      };
+      this.UPDATE_TOPO_TEMPLATE_TYPES(topoTemplateTypes);
+    }
 
     private selectInstance(i: Option) {
       if (!this.rocketComps.enableEvents) {
@@ -132,21 +200,15 @@ limitations under the License. -->
       });
     }
 
-    private beforeMount() {
-      this.SET_CURRENT_SERVICE(this.current);
-      this.MIXHANDLE_CHANGE_GROUP_WITH_CURRENT({ index: 0, current: 3 });
-      this.GET_SERVICE_INSTANCES({ duration: this.durationTime, serviceId: this.current.key }).then(() => {
-        this.selectInstance(this.stateDashboardOption.instances[0]);
-      });
-    }
-
     private async importData(event: any) {
       try {
         const data: any = await readFile(event);
         if (!Array.isArray(data)) {
           throw new Error();
         }
-        this.$emit('changeInstanceComps', { json: data, type: ObjectsType.UPDATE_ENDPOINTS });
+        this.SET_TOPO_INSTANCE(data);
+        const survey: any = this.$refs.survey;
+        survey.setTemplates();
         const el: any = document.getElementById('instance-file');
         el!.value = '';
       } catch (e) {
@@ -154,13 +216,24 @@ limitations under the License. -->
       }
     }
     private exportData() {
-      const data = this.instanceComps;
+      let topoInstances = {};
       const name = 'instanceComps.json';
-      saveFile(data, name);
+
+      for (const type of Object.keys(this.stateTopo.topoInstances)) {
+        const metricsTemp = this.stateTopo.topoInstances[type].map((item: any) => {
+          delete item.uuid;
+          return item;
+        });
+        topoInstances = {
+          ...topoInstances,
+          [type]: metricsTemp,
+        };
+      }
+      saveFile(topoInstances, name);
     }
 
     private beforeDestroy() {
-      this.$emit('changeInstanceComps', { type: '' });
+      this.$emit('changeInstanceComps', { type: false });
       this.SET_EDIT(false);
     }
   }
@@ -188,4 +261,14 @@ limitations under the License. -->
     display: inline;
     line-height: inherit;
   }
+  .type {
+    display: inline-block;
+    width: 100px;
+  }
+
+  .content {
+    vertical-align: top;
+    display: inline-block;
+    width: 300px;
+  }
 </style>
diff --git a/src/views/containers/topology/instance/instances-survey.vue b/src/views/containers/topology/instance/instances-survey.vue
index 21aa2c1..85a50f6 100644
--- a/src/views/containers/topology/instance/instances-survey.vue
+++ b/src/views/containers/topology/instance/instances-survey.vue
@@ -17,15 +17,17 @@ limitations under the License. -->
   <div class="dashboard-container clear">
     <DashboardItem
       v-for="(i, index) in instanceComps || []"
-      :key="index + i.title + i.with"
+      :key="i.uuid"
       :rocketGlobal="rocketGlobal"
       :item="i"
       :index="index"
-      :type="'TOPOLOGY_INSTANCE'"
+      :type="type"
       :updateObjects="updateObjects"
       :rocketOption="stateDashboardOption"
+      :templateTypes="templateTypes"
+      @setTemplates="setTemplates"
     />
-    <div v-show="rocketGlobal.edit" class="rk-add-dashboard-item g-sm-3" @click="ADD_TOPO_INSTANCE_COMP">
+    <div v-show="rocketGlobal.edit" class="rk-add-dashboard-item g-sm-3" @click="addInstanceMetrics()">
       + Add An Item
     </div>
   </div>
@@ -33,10 +35,14 @@ limitations under the License. -->
 
 <script lang="ts">
   import Vue from 'vue';
-  import { Component, Prop } from 'vue-property-decorator';
+  import { Component, Watch, Prop } from 'vue-property-decorator';
   import { State, Mutation } from 'vuex-class';
+  import { State as topoState } from '@/store/modules/topology';
   import { State as optionState } from '@/store/modules/global/selectors';
   import DashboardItem from '@/views/components/dashboard/dashboard-item.vue';
+  import { TopologyType, DEFAULT } from '@/constants/constant';
+  import { Option } from '@/types/global';
+  import { uuid } from '@/utils/uuid';
 
   @Component({
     components: {
@@ -44,10 +50,82 @@ limitations under the License. -->
     },
   })
   export default class InstancesSurvey extends Vue {
+    @State('rocketTopo') private stateTopo!: topoState;
     @State('rocketbot') private rocketGlobal: any;
     @State('rocketOption') private stateDashboardOption!: optionState;
     @Mutation('rocketTopo/ADD_TOPO_INSTANCE_COMP') private ADD_TOPO_INSTANCE_COMP: any;
-    @Prop() private instanceComps: any;
-    @Prop() private updateObjects!: string;
+    @Mutation('rocketTopo/SET_TOPO_INSTANCE') private SET_TOPO_INSTANCE: any;
+    @Prop() private currentType: any;
+
+    private instanceComps: any = [];
+    private type: string = TopologyType.TOPOLOGY_INSTANCE;
+    private templateTypes: string[] = [];
+    private updateObjects: boolean = false;
+
+    private beforeMount() {
+      this.setInstanceTemplates();
+    }
+
+    private setTemplates() {
+      this.updateObjects = true;
+      this.setInstanceTemplates();
+    }
+
+    private addInstanceMetrics() {
+      this.ADD_TOPO_INSTANCE_COMP();
+      this.setInstanceTemplates();
+    }
+
+    private setInstanceTemplates() {
+      this.setTemplateTypes();
+      this.instanceComps = [];
+      let templates: any = {};
+      for (const type of Object.keys(this.stateTopo.topoInstances)) {
+        const metricsTemp = this.stateTopo.topoInstances[type].map((item: any) => {
+          item.uuid = item.uuid || uuid();
+          return item;
+        });
+        templates = {
+          ...templates,
+          [type]: metricsTemp,
+        };
+      }
+      this.SET_TOPO_INSTANCE(templates);
+      for (const type of this.templateTypes) {
+        this.instanceComps = [...this.instanceComps, ...this.stateTopo.topoInstances[type]];
+      }
+    }
+
+    private setTemplateTypes() {
+      const nodeType = this.stateTopo.currentNode.type || DEFAULT;
+      const templates = this.stateTopo.topoTemplatesType;
+      if (templates[TopologyType.TOPOLOGY_INSTANCE] && templates[TopologyType.TOPOLOGY_INSTANCE][nodeType]) {
+        this.templateTypes = templates[TopologyType.TOPOLOGY_INSTANCE][nodeType].map((item: Option) => item.key);
+      } else {
+        this.templateTypes = this.stateTopo.topoInstances[nodeType] ? [nodeType] : [DEFAULT];
+      }
+    }
+
+    @Watch('currentType')
+    private updateMetrics() {
+      this.setTemplates();
+    }
   }
 </script>
+<style lang="scss" scoped>
+  .rk-add-dashboard-item {
+    height: 342px;
+    text-align: center;
+    line-height: 250px;
+    border: 1px dashed rgba(196, 200, 225, 0.5);
+    cursor: pointer;
+    display: inline-block;
+    font-size: 16px;
+  }
+  .dashboard-container {
+    overflow: auto;
+    padding: 20px 15px;
+    height: 100%;
+    flex-grow: 1;
+  }
+</style>
diff --git a/src/views/containers/topology/topology.vue b/src/views/containers/topology/topology.vue
index 942be4c..a0cc91f 100644
--- a/src/views/containers/topology/topology.vue
+++ b/src/views/containers/topology/topology.vue
@@ -25,36 +25,19 @@ limitations under the License. -->
     <TopoAside />
     <TopoGroup />
     <rk-sidebox :show="dialog.length" @update:show="dialog = ''" :fixed="true" width="100%">
-      <window-endpoint
-        v-if="dialog === 'endpoint'"
-        :current="this.current"
-        :endpointComps="stateTopo.topoEndpoints"
-        @changeEndpointComps="changeEndpointComps"
-        :updateObjects="updateObjects"
-      />
-      <window-instance
-        v-if="dialog === 'instance'"
-        :current="this.current"
-        :instanceComps="stateTopo.topoInstances"
-        @changeInstanceComps="changeInstanceComps"
-        :updateObjects="updateObjects"
-      />
+      <window-endpoint v-if="dialog === 'endpoint'" :current="this.current" />
+      <window-instance v-if="dialog === 'instance'" :current="this.current" />
       <window-trace v-if="dialog === 'trace'" :current="this.current" />
       <window-alarm v-if="dialog === 'alarm'" :current="this.current" />
-      <window-endpoint-dependency
-        v-if="dialog === 'endpoint_dependency'"
-        @changeEndpointComps="changeEndpointComps"
-        :current="this.current"
-      />
+      <window-endpoint-dependency v-if="dialog === 'endpoint_dependency'" :current="this.current" />
     </rk-sidebox>
   </div>
 </template>
 <script lang="ts">
   import { Vue, Component } from 'vue-property-decorator';
-  import { State, Action, Getter, Mutation } from 'vuex-class';
-  import { AxiosResponse } from 'axios';
+  import { State, Action, Mutation } from 'vuex-class';
   import { State as topoState } from '@/store/modules/topology';
-  import { TopologyType } from '../../../constants/constant';
+  import { TopologyType, PageTypes } from '@/constants/constant';
   import WindowEndpoint from '@/views/containers/topology/endpoint/index.vue';
   import WindowInstance from '@/views/containers/topology/instance/index.vue';
   import WindowTrace from '@/views/containers/topology/trace/index.vue';
@@ -63,6 +46,7 @@ limitations under the License. -->
   import TopoAside from '../../components/topology/topo-aside.vue';
   import TopoGroup from '../../components/topology/topo-group/index.vue';
   import WindowEndpointDependency from '@/views/containers/topology/endpoint-dependency/index.vue';
+  import { Option } from '@/types/global';
 
   @Component({
     components: {
@@ -83,24 +67,76 @@ limitations under the License. -->
     @Action('GET_ALL_TEMPLATES') private GET_ALL_TEMPLATES: any;
     @Mutation('rocketTopo/SET_TOPO_ENDPOINT') private SET_TOPO_ENDPOINT: any;
     @Mutation('rocketTopo/SET_TOPO_INSTANCE') private SET_TOPO_INSTANCE: any;
+    @Mutation('rocketTopo/SET_TOPO_SERVICE') private SET_TOPO_SERVICE: any;
+    @Mutation('rocketTopo/SET_TOPO_SERVICE_DEPENDENCY') private SET_TOPO_SERVICE_DEPENDENCY: any;
+    @Mutation('rocketTopo/SET_TOPO_SERVICE_INSTANCE_DEPENDENCY') private SET_TOPO_SERVICE_INSTANCE_DEPENDENCY: any;
+    @Mutation('rocketTopo/EDIT_DEPENDENCY_METRICS') private EDIT_DEPENDENCY_METRICS: any;
+    @Mutation('rocketTopo/SET_TOPO_ENDPOINT_DEPENDENCY') private SET_TOPO_ENDPOINT_DEPENDENCY: any;
     @Mutation('SET_CURRENT_SERVICE') private SET_CURRENT_SERVICE: any;
-    @Getter('durationTime') private durationTime: any;
+    @Mutation('SET_EDIT') private SET_EDIT: any;
+    @Mutation('SET_PAGE_TYPE') private SET_PAGE_TYPE: any;
 
     private current: any = {};
     private dialog: string = '';
-    private updateObjects: string = '';
 
     private created() {
-      if (window.localStorage.getItem('topologyInstances') || window.localStorage.getItem('topologyEndpoints')) {
+      this.SET_PAGE_TYPE(PageTypes.TOPOLOGY);
+      this.initMetricsTemplate();
+    }
+    private initMetricsTemplate() {
+      localStorage.removeItem('topoTemplateTypes');
+      localStorage.removeItem('topologyServices');
+      localStorage.removeItem('topologyServicesDependency');
+
+      if (window.localStorage.getItem('topologyServices')) {
+        const serviceComps: string = `${window.localStorage.getItem('topologyServices')}`;
+        const topoService = serviceComps ? JSON.parse(serviceComps) : [];
+
+        this.SET_TOPO_SERVICE(topoService);
+      }
+      if (window.localStorage.getItem('topologyInstances')) {
         const instanceComps: string = `${window.localStorage.getItem('topologyInstances')}`;
         const topoInstance = instanceComps ? JSON.parse(instanceComps) : [];
+
+        this.SET_TOPO_INSTANCE(topoInstance);
+      }
+      if (window.localStorage.getItem('topologyEndpoints')) {
         const endpointComps: string = `${window.localStorage.getItem('topologyEndpoints')}`;
         const topoEndpoint = endpointComps ? JSON.parse(endpointComps) : [];
-        this.SET_TOPO_INSTANCE(topoInstance);
+
         this.SET_TOPO_ENDPOINT(topoEndpoint);
-      } else {
-        this.queryTemplates();
       }
+      if (localStorage.getItem('topologyServicesDependency')) {
+        const serviceDependencyComps: string = `${localStorage.getItem('topologyServicesDependency')}`;
+        const topoServiceDependency = serviceDependencyComps ? JSON.parse(serviceDependencyComps) : [];
+
+        this.SET_TOPO_SERVICE_DEPENDENCY(topoServiceDependency);
+      }
+      if (localStorage.getItem('topologyServicesInstanceDependency')) {
+        const serviceInstanceDependencyComps: string = `${localStorage.getItem('topologyServicesInstanceDependency')}`;
+        const topoServiceInstanceDependency = serviceInstanceDependencyComps
+          ? JSON.parse(serviceInstanceDependencyComps)
+          : [];
+
+        this.SET_TOPO_SERVICE_INSTANCE_DEPENDENCY(topoServiceInstanceDependency);
+      }
+      if (localStorage.getItem('topologyEndpointDependency')) {
+        const serviceEndpointComps: string = `${localStorage.getItem('topologyEndpointDependency')}`;
+        const topoEndpointDependency = serviceEndpointComps ? JSON.parse(serviceEndpointComps) : [];
+
+        this.SET_TOPO_ENDPOINT_DEPENDENCY(topoEndpointDependency);
+      }
+      if (
+        localStorage.getItem('topologyServices') &&
+        localStorage.getItem('topologyInstances') &&
+        localStorage.getItem('topologyEndpoints') &&
+        localStorage.getItem('topologyServicesDependency') &&
+        localStorage.getItem('topologyServicesInstanceDependency') &&
+        localStorage.getItem('topologyEndpointDependency')
+      ) {
+        return;
+      }
+      this.queryTemplates();
     }
     private queryTemplates() {
       this.GET_ALL_TEMPLATES().then(
@@ -113,40 +149,65 @@ limitations under the License. -->
             disabled: boolean;
           }>,
         ) => {
-          const template =
-            allTemplates.filter((item: any) => item.type === TopologyType.TOPOLOGY_INSTANCE && item.activated)[0] || {};
-          const instanceComps = JSON.parse(template.configuration) || [];
-          this.SET_TOPO_INSTANCE(instanceComps);
-          const endpointTemplate =
-            allTemplates.filter((item: any) => item.type === TopologyType.TOPOLOGY_ENDPOINT && item.activated)[0] || {};
-          const endpointComps = JSON.parse(endpointTemplate.configuration) || [];
-          this.SET_TOPO_ENDPOINT(endpointComps);
+          if (!window.localStorage.getItem('topologyInstances')) {
+            const template =
+              allTemplates.filter((item: any) => item.type === TopologyType.TOPOLOGY_INSTANCE && item.activated)[0] ||
+              {};
+            const instanceComps = JSON.parse(template.configuration) || [];
+            this.SET_TOPO_INSTANCE(instanceComps);
+          }
+          if (!window.localStorage.getItem('topologyEndpoints')) {
+            const endpointTemplate =
+              allTemplates.filter((item: any) => item.type === TopologyType.TOPOLOGY_ENDPOINT && item.activated)[0] ||
+              {};
+            const endpointComps = JSON.parse(endpointTemplate.configuration) || [];
+            this.SET_TOPO_ENDPOINT(endpointComps);
+          }
+          if (!window.localStorage.getItem('topologyServices')) {
+            const serviceTemplate =
+              allTemplates.filter((item: any) => item.type === TopologyType.TOPOLOGY_SERVICE && item.activated)[0] ||
+              {};
+            const topoService = JSON.parse(serviceTemplate.configuration) || [];
+            this.SET_TOPO_SERVICE(topoService);
+          }
+          if (!localStorage.getItem('topologyServicesDependency')) {
+            const serviceDependencyTemplate =
+              allTemplates.filter(
+                (item: any) => item.type === TopologyType.TOPOLOGY_SERVICE_DEPENDENCY && item.activated,
+              )[0] || {};
+            const topoServiceDependency = JSON.parse(serviceDependencyTemplate.configuration) || [];
+            this.SET_TOPO_SERVICE_DEPENDENCY(topoServiceDependency);
+          }
+          if (!localStorage.getItem('topologyServicesInstanceDependency')) {
+            const serviceInstanceDependencyTemplate =
+              allTemplates.filter(
+                (item: any) => item.type === TopologyType.TOPOLOGY_SERVICE_INSTANCE_DEPENDENCY && item.activated,
+              )[0] || {};
+            const topoServiceInstanceDependency = JSON.parse(serviceInstanceDependencyTemplate.configuration) || [];
+            this.SET_TOPO_SERVICE_INSTANCE_DEPENDENCY(topoServiceInstanceDependency);
+          }
+          if (!localStorage.getItem('topologyEndpointDependency')) {
+            const serviceEndpointDependencyTemplate =
+              allTemplates.filter(
+                (item: any) => item.type === TopologyType.TOPOLOGY_ENDPOINT_DEPENDENCY && item.activated,
+              )[0] || {};
+            const topoEndpointDependency = JSON.parse(serviceEndpointDependencyTemplate.configuration) || [];
+            this.SET_TOPO_ENDPOINT_DEPENDENCY(topoEndpointDependency);
+          }
         },
       );
     }
-    private setCurrent(d: any): void {
+    private setCurrent(d: Option & { isReal: boolean }): void {
       this.current = d;
       if (d.isReal) {
-        this.SET_CURRENT_SERVICE(d);
-      }
-    }
-    private changeInstanceComps(data: { type: string; json: any }) {
-      this.updateObjects = data.type;
-      if (!data.json) {
-        return;
-      }
-      this.SET_TOPO_INSTANCE(data.json);
-    }
-    private changeEndpointComps(data: { type: string; json: any }) {
-      this.updateObjects = data.type;
-      if (!data.json) {
-        return;
+        this.SET_CURRENT_SERVICE({ key: d.key, label: d.label });
       }
-      this.SET_TOPO_ENDPOINT(data.json);
     }
     private beforeDestroy() {
       this.CLEAR_TOPO_INFO();
       this.CLEAR_TOPO();
+      this.SET_EDIT(false);
+      this.EDIT_DEPENDENCY_METRICS(false);
     }
   }
 </script>