You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@skywalking.apache.org by wu...@apache.org on 2019/12/08 09:54:51 UTC

[skywalking-rocketbot-ui] branch master updated: Revert "Feat: remove element-ui (#218)" (#220)

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

wusheng 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 472a058  Revert "Feat: remove element-ui (#218)" (#220)
472a058 is described below

commit 472a058626b6cfe1927fb1d72612c0bef7191492
Author: Kdump <ro...@gmail.com>
AuthorDate: Sun Dec 8 17:54:42 2019 +0800

    Revert "Feat: remove element-ui (#218)" (#220)
    
    This reverts commit 08c7fb5e7c57c47a436ec568ee41ec04c3fc6b5d.
---
 package.json                                      |   1 +
 src/App.vue                                       |   7 +-
 src/components/rk-back.vue                        |   4 +-
 src/components/rk-button.vue                      |   7 +-
 src/components/rk-footer.vue                      |   2 +-
 src/main.ts                                       |   3 +
 src/router.ts                                     |  17 ++-
 src/shims-tsx.d.ts                                |   2 +-
 src/store/index.ts                                |   9 --
 src/store/modules/topology/index.ts               |  20 +++
 src/views/components/alarm/alarm-tool.vue         |   4 +-
 src/views/components/dashboard/dashboard-comp.vue |   4 +-
 src/views/components/dashboard/tool-bar.vue       |   5 +-
 src/views/components/topology/radial.vue          |   1 +
 src/views/components/topology/topo-aside.vue      |  60 ++++++++-
 src/views/components/topology/topo-chart.vue      |   4 +-
 src/views/components/topology/topo-response.vue   |   2 +-
 src/views/components/topology/topo.vue            |  64 +++++-----
 src/views/components/trace/trace-search.vue       |   5 +-
 src/views/containers/alarm.vue                    |  14 +-
 src/views/containers/dashboard.vue                |   6 +
 src/views/containers/endpoint-survey-window.vue   | 148 ++++++++++++++++++++++
 src/views/containers/instances-survey-window.vue  | 142 +++++++++++++++++++++
 src/views/containers/topology.vue                 |   6 +-
 src/views/containers/trace.vue                    |   9 +-
 25 files changed, 469 insertions(+), 77 deletions(-)

diff --git a/package.json b/package.json
index 7a405f4..f5397b4 100644
--- a/package.json
+++ b/package.json
@@ -15,6 +15,7 @@
     "d3-tip": "^0.9.1",
     "dayjs": "^1.8.8",
     "echarts": "^4.1.0",
+    "element-ui": "^2.12.0",
     "lodash": "^4.17.15",
     "noty": "^3.2.0-beta",
     "popper.js": "^1.14.7",
diff --git a/src/App.vue b/src/App.vue
index 5f1618f..ac0e195 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -16,12 +16,7 @@
  */
 
 <template>
-<div class="container">
- <keep-alive :max="1">
-    <router-view v-if="$route.meta.keepAlive"></router-view>
-  </keep-alive>
-  <router-view v-if="!$route.meta.keepAlive"></router-view>
-</div>
+  <router-view></router-view>
 </template>
 <script lang="ts">
 import { Component, Vue } from 'vue-property-decorator';
diff --git a/src/components/rk-back.vue b/src/components/rk-back.vue
index daf24f2..51ccf9f 100644
--- a/src/components/rk-back.vue
+++ b/src/components/rk-back.vue
@@ -29,8 +29,8 @@ export default class RkBack extends Vue {
   @Prop({ default: '' }) private size!: string;
   private handleBack() {
     const query = this.$route.query as any;
-    if (query.from) {
-      this.$router.push(query.from);
+    if (query.form) {
+      this.$router.push(query.form);
     } else {
       this.$emit('back');
     }
diff --git a/src/components/rk-button.vue b/src/components/rk-button.vue
index 1bb7db1..73622fe 100644
--- a/src/components/rk-button.vue
+++ b/src/components/rk-button.vue
@@ -16,9 +16,8 @@
  */
 
 <template>
-  <a class="rk-btn" :class="`${size} ${ghost?'ghost':''}`" @click="$emit('click')">
-    <rk-icon v-if="icon" :icon="icon" :offset="true"/>
-    <slot/>
+  <a class="rk-btn" :class="{size, 'ghost': ghost}" @click="$emit('click')">
+    <svg class="icon"><use xlink:href="#chevron-left"></use></svg>
   </a>
 </template>
 <script lang="ts">
@@ -28,7 +27,6 @@ import { Component, Prop } from 'vue-property-decorator';
 @Component
 export default class RkBtn extends Vue {
   @Prop({ default: '' }) private size!: string;
-  @Prop({ default: '' }) private icon!: string;
   @Prop({ default: false }) private ghost!: boolean;
 }
 </script>
@@ -39,7 +37,6 @@ export default class RkBtn extends Vue {
   background-color: #448dfe;
   border-radius: 4px;
   color: #fff;
-  display: inline-block;
   transition: background-color .3s;
   &.sm{
     line-height: 24px;
diff --git a/src/components/rk-footer.vue b/src/components/rk-footer.vue
index f34e46c..37eaac7 100644
--- a/src/components/rk-footer.vue
+++ b/src/components/rk-footer.vue
@@ -87,7 +87,7 @@ export default class Footerssd extends Vue {
   border-top: 1px solid #448dfe;
 }
 .rk-footer-utc{
-  color:inherit;background: 0;border: 0;outline: none; width:35px;padding-bottom: 0;
+  color:inherit;background: 0;border: 0;outline: none; width:27px;padding-bottom: 0;
 }
 .rk-footer-inner{
   justify-content: space-between;
diff --git a/src/main.ts b/src/main.ts
index db06627..af4c833 100644
--- a/src/main.ts
+++ b/src/main.ts
@@ -37,10 +37,13 @@ import 'echarts/lib/component/legend';
 import 'echarts/lib/component/tooltip';
 import VModal from 'vue-js-modal';
 import './assets';
+import ElementUI from 'element-ui';
+import 'element-ui/lib/theme-chalk/index.css';
 
 Vue.use(eventBus);
 Vue.use(VueI18n);
 Vue.use(components);
+Vue.use(ElementUI);
 Vue.use(VModal, {dialog: true});
 Vue.directive('clickout', clickout);
 Vue.directive('tooltip', tooltip);
diff --git a/src/router.ts b/src/router.ts
index 6e0bfa9..7df8dfd 100644
--- a/src/router.ts
+++ b/src/router.ts
@@ -33,6 +33,11 @@ const router = new Router({
   base: process.env.BASE_URL,
   linkActiveClass: 'active',
   routes: [
+    // {
+    //   path: '/login',
+    //   component: Login,
+    //   meta: { login: true },
+    // },
     {
       path: '/',
       component: Index,
@@ -48,9 +53,6 @@ const router = new Router({
         {
           path: 'topology',
           component: Topology,
-          meta: {
-            keepAlive: true,
-          },
         },
         {
           path: 'alarm',
@@ -73,6 +75,15 @@ router.beforeEach((to, from, next) => {
     }
     window.axiosCancel = [];
   }
+  // if (to.meta.login && (token === null || token === 'guest')) {
+  //   next();
+  // } else if (token === null || token === 'guest') {
+  //   next('/login');
+  // } else if (to.meta.login) {
+  //   next(from.path);
+  // } else {
+  //   next();
+  // }
   next();
 });
 
diff --git a/src/shims-tsx.d.ts b/src/shims-tsx.d.ts
index a7f977c..bb364ee 100644
--- a/src/shims-tsx.d.ts
+++ b/src/shims-tsx.d.ts
@@ -27,7 +27,7 @@ declare global {
       [elem: string]: any;
     }
   }
-  interface Window {
+  interface Window { 
     Promise: any;
     moment: any;
     axiosCancel: any;
diff --git a/src/store/index.ts b/src/store/index.ts
index 595db78..cea2bb0 100644
--- a/src/store/index.ts
+++ b/src/store/index.ts
@@ -21,9 +21,6 @@ import rocketbot, { State as RocketbotState } from './modules/global';
 import rocketOption, { State as DashboardOptionState } from './modules/dashboard/modules/dashboard-option';
 import rocketData, { State as DashboardDataState } from './modules/dashboard/modules/dashboard-data';
 import rocketDashboard, { State as DashboardState } from './modules/dashboard/source';
-import rocketTopo, { State as TopoState} from '@/store/modules/topology';
-import rocketTrace, { State as TraceState} from '@/store/modules/trace';
-import rocketAlarm, { State as AlarmState} from '@/store/modules/alarm';
 Vue.use(Vuex);
 
 export interface State {
@@ -31,9 +28,6 @@ export interface State {
   rocketOption: DashboardOptionState;
   rocketData: DashboardDataState;
   rocketDashboard: DashboardState;
-  rocketTopo: TopoState;
-  rocketTrace: TraceState;
-  rocketAlarm: AlarmState;
 }
 
 export default new Vuex.Store({
@@ -42,8 +36,5 @@ export default new Vuex.Store({
     rocketOption,
     rocketData,
     rocketDashboard,
-    rocketTopo,
-    rocketTrace,
-    rocketAlarm,
   },
 });
diff --git a/src/store/modules/topology/index.ts b/src/store/modules/topology/index.ts
index 5ad1904..0cf662c 100644
--- a/src/store/modules/topology/index.ts
+++ b/src/store/modules/topology/index.ts
@@ -62,6 +62,10 @@ export interface State {
   p95: number[];
   p99: number[];
   honeycombNode: any;
+  showAlarmDialog: boolean;
+  showTraceDialog: boolean;
+  showInstancesDialog: boolean;
+  showEndpointDialog: boolean;
 }
 
 const initState: State = {
@@ -85,6 +89,10 @@ const initState: State = {
   p95: [],
   p99: [],
   honeycombNode: {},
+  showAlarmDialog: false,
+  showTraceDialog: false,
+  showInstancesDialog: false,
+  showEndpointDialog: false,
 };
 
 // getters
@@ -95,6 +103,18 @@ const mutations = {
   [types.SET_HONEYCOMB_NODE](state: State, data: any) {
     state.honeycombNode = data;
   },
+  [types.SET_SHOW_ALARM_DIALOG](state: State, isShow: boolean) {
+    state.showAlarmDialog = isShow;
+  },
+  [types.SET_SHOW_TRACE_DIALOG](state: State, isShow: boolean) {
+    state.showTraceDialog = isShow;
+  },
+  [types.SET_SHOW_INSTANCES_DIALOG](state: State, isShow: boolean) {
+    state.showInstancesDialog = isShow;
+  },
+  [types.SET_SHOW_ENDPOINT_DIALOG](state: State, isShow: boolean) {
+    state.showEndpointDialog = isShow;
+  },
   [types.SET_CALLBACK](state: State, data: any) {
     state.callback = data;
   },
diff --git a/src/views/components/alarm/alarm-tool.vue b/src/views/components/alarm/alarm-tool.vue
index 77753f0..786aedd 100644
--- a/src/views/components/alarm/alarm-tool.vue
+++ b/src/views/components/alarm/alarm-tool.vue
@@ -17,7 +17,6 @@
 
 <template>
   <nav class="rk-alarm-tool flex-h">
-    <RkBack v-if="$route.query.from"/>
     <AlarmSelect v-show="!inTopo" :title="this.$t('filterScope')" :value="alarmScope" @input="handleFilter" :data="alarmOptions"/>
     <div class="mr-10" style="padding: 3px 15px 0">
       <div class="sm grey">{{this.$t('searchKeyword')}}</div>
@@ -40,7 +39,7 @@ export default class AlarmTool extends Vue {
   @Prop() private durationTime: any;
   @Prop() private total!: number;
   private pageNum: number = 1;
-  @Prop({default: () => ({label: 'All', key: ''})})
+  @Prop({default: {label: 'All', key: ''}})
   private alarmScope: any;
   @Prop({default: false, type: Boolean})
   private inTopo!: boolean;
@@ -76,7 +75,6 @@ export default class AlarmTool extends Vue {
   }
   private beforeMount() {
     this.SET_EVENTS([() => { this.handleRefresh(1); } ]);
-    this.handleRefresh(1);
   }
 }
 </script>
diff --git a/src/views/components/dashboard/dashboard-comp.vue b/src/views/components/dashboard/dashboard-comp.vue
index b5879aa..7faeca8 100644
--- a/src/views/components/dashboard/dashboard-comp.vue
+++ b/src/views/components/dashboard/dashboard-comp.vue
@@ -66,9 +66,7 @@ export default class DashboardComp extends Vue {
       Database: [],
     };
     this.rocketComps.data[this.compType].forEach((i: any) => {
-      if (temp[i.o]) {
-        temp[i.o].push(i);
-      }
+      temp[i.o] && temp[i.o].push(i);
     });
     return temp;
   }
diff --git a/src/views/components/dashboard/tool-bar.vue b/src/views/components/dashboard/tool-bar.vue
index d061184..230efc3 100644
--- a/src/views/components/dashboard/tool-bar.vue
+++ b/src/views/components/dashboard/tool-bar.vue
@@ -18,12 +18,11 @@
 <template>
   <div>
     <div class="rk-dashboard-bar flex-h" v-if="compType === 'service'">
-      <RkBack v-if="$route.query.from" class="ml-5"/>
       <div class="rk-dashboard-bar-reload">
-        <rk-button :icon="!rocketGlobal.edit?'#lock':'#lock-open'" :size="'lg'" :ghost="true" @click="handleSetEdit"></rk-button>
+        <svg class="icon lg vm cp rk-btn ghost" :style="`color:${!rocketGlobal.edit? '' :'#ffc107'}`" @click="handleSetEdit"><use :xlink:href="!rocketGlobal.edit?'#lock':'#lock-open'"></use></svg>
       </div>
       <div class="rk-dashboard-bar-reload">
-        <rk-button icon="#retry" :size="'lg'" :ghost="true" @click="handleOption"></rk-button>
+        <svg class="icon lg vm cp rk-btn ghost" @click="handleOption"><use xlink:href="#retry"></use></svg>
       </div>
       <ToolBarSelect @onChoose="selectService" :title="this.$t('currentService')" :current="stateDashboard.currentService" :data="stateDashboard.services" icon="package"/>
       <ToolBarEndpointSelect @onChoose="selectEndpoint" :title="this.$t('currentEndpoint')" :current="stateDashboard.currentEndpoint" :data="stateDashboard.endpoints" icon="code"/>
diff --git a/src/views/components/topology/radial.vue b/src/views/components/topology/radial.vue
index f47bff9..550ab4e 100644
--- a/src/views/components/topology/radial.vue
+++ b/src/views/components/topology/radial.vue
@@ -17,6 +17,7 @@
 
 <template>
   <div class="micro-radil-chart">
+    <!-- <div class="micro-radil-chart-btn rk-btn ghost cp" @click="$emit('showRadial', false)">X</div> -->
     <RkEcharts height="100%" :option="responseConfig" ref="radial" />
   </div>
 </template>
diff --git a/src/views/components/topology/topo-aside.vue b/src/views/components/topology/topo-aside.vue
index 35817d0..a70a887 100644
--- a/src/views/components/topology/topo-aside.vue
+++ b/src/views/components/topology/topo-aside.vue
@@ -114,6 +114,41 @@
         />
       </div>
     </div>
+    <el-drawer
+        v-if="stateTopo.showAlarmDialog"
+        custom-class="performance-metrics-window"
+        size="75%"
+        destroy-on-close
+        :visible.sync="stateTopo.showAlarmDialog"
+    >
+      <alarm-containers :style="`height: ${drawerMainBodyHeight}`"
+                        :alarmScope="{label: 'Service', key: 'Service'}"
+                        inTopo
+                        :keyword="stateTopo.honeycombNode.name"
+      ></alarm-containers>
+    </el-drawer>
+    <el-drawer
+        custom-class="performance-metrics-window"
+        v-if="stateTopo.showTraceDialog"
+        size="75%"
+        destroy-on-close
+        :visible.sync="stateTopo.showTraceDialog"
+    >
+      <trace-containers :style="`height: ${drawerMainBodyHeight}`"
+                        :service="{label: stateTopo.honeycombNode.name, key: stateTopo.honeycombNode.id}"
+                        inTopo
+      ></trace-containers>
+    </el-drawer>
+    <instances-survey-window
+        v-if="stateTopo.showInstancesDialog"
+        :is-show.sync="stateTopo.showInstancesDialog"
+        :instances="stateDashboardOption.instances"
+    ></instances-survey-window>
+    <endpoint-survey-window
+        v-if="stateTopo.showEndpointDialog"
+        :is-show.sync="stateTopo.showEndpointDialog"
+        :endpoints="stateDashboardOption.endpoints"
+    ></endpoint-survey-window>
   </aside>
 </template>
 <script lang="ts">
@@ -124,9 +159,14 @@ import TopoChart from './topo-chart.vue';
 import TopoService from './topo-services.vue';
 import ChartResponse from './topo-response.vue';
 import Radial from './radial.vue';
+import AlarmContainers from '@/views/containers/alarm.vue';
+import TraceContainers from '@/views/containers/trace.vue';
+import InstancesSurveyWindow from '@/views/containers/instances-survey-window.vue';
+import EndpointSurveyWindow from '@/views/containers/endpoint-survey-window.vue';
 import { initState } from '@/store/modules/dashboard/modules/dashboard-data-layout';
 
-@Component({components: {TopoChart, TopoService, ChartResponse, Radial}})
+@Component({components: {TopoChart, TopoService, ChartResponse, Radial, AlarmContainers,
+    TraceContainers, InstancesSurveyWindow, EndpointSurveyWindow}})
 export default class TopoAside extends Vue {
   @State('rocketTopo') private stateTopo!: topoState;
   @State('rocketOption') private stateDashboardOption!: any;
@@ -138,6 +178,7 @@ export default class TopoAside extends Vue {
   @Action('rocketTopo/CLEAR_TOPO_INFO') private CLEAR_TOPO_INFO: any;
   @Mutation('SET_COMPS_TREE') private SET_COMPS_TREE: any;
 
+  private drawerMainBodyHeight = '100%';
   private initState = initState;
   private radioStatus: boolean = false;
   private show: boolean = true;
@@ -145,18 +186,33 @@ export default class TopoAside extends Vue {
   private isMini: boolean = true;
   private showInfoCount: number = 0;
 
+  private resize() {
+    this.drawerMainBodyHeight = `${document.body.clientHeight - 50}px`;
+  }
+
+  private beforeCreate() {
+    this.$store.registerModule('rocketTopo', topo);
+  }
+
   private async created() {
     this.getTopo();
     this.SET_COMPS_TREE(this.initState.tree);
   }
 
+  private mounted() {
+    this.resize();
+    window.addEventListener('resize', this.resize);
+  }
+
   private getTopo() {
     this.GET_TOPO({ duration: this.durationTime });
   }
 
   private beforeDestroy() {
+    window.removeEventListener('resize', this.resize);
     this.CLEAR_TOPO_INFO();
     this.CLEAR_TOPO();
+    this.$store.unregisterModule('rocketTopo');
   }
 
   get types() {
@@ -239,7 +295,7 @@ export default class TopoAside extends Vue {
   width: 280px;
   z-index: 101;
   color: #ddd;
-  background-color: #252a2f;
+  background-color: #333;
   padding: 15px 20px 10px;
   .label{
     display: inline-block;
diff --git a/src/views/components/topology/topo-chart.vue b/src/views/components/topology/topo-chart.vue
index eb3a8d1..88087be 100644
--- a/src/views/components/topology/topo-chart.vue
+++ b/src/views/components/topology/topo-chart.vue
@@ -18,8 +18,8 @@
 <template>
   <div>
     <div class="grey sm mb-5">{{title}}</div>
-    <div class="mb-5">{{content.toFixed(2)}} {{unit}}</div>
-    <RkEcharts height="80px" :option="responseConfig"/>
+    <h5 class="mt-0 mb-0">{{content.toFixed(2)}} {{unit}}</h5>
+    <RkEcharts height="100px" :option="responseConfig"/>
   </div>
 
 </template>
diff --git a/src/views/components/topology/topo-response.vue b/src/views/components/topology/topo-response.vue
index d824889..c248bc1 100644
--- a/src/views/components/topology/topo-response.vue
+++ b/src/views/components/topology/topo-response.vue
@@ -18,7 +18,7 @@
 <template>
   <div>
     <div class="grey sm mb-5">{{title}}</div>
-    <RkEcharts height="80px" :option="responseConfig"/>
+    <RkEcharts height="120px" :option="responseConfig"/>
   </div>
 </template>
 
diff --git a/src/views/components/topology/topo.vue b/src/views/components/topology/topo.vue
index d7ddaeb..1b8efca 100644
--- a/src/views/components/topology/topo.vue
+++ b/src/views/components/topology/topo.vue
@@ -110,7 +110,6 @@ export default {
     this.tip.hide({}, this);
     window.removeEventListener('resize', this.resize);
     d3.selectAll('.d3-tip-grey').remove();
-    this.removeHoneycomb(this);
     // this.$store.commit('skywalking/setCurrentNode', []);
   },
   mounted() {
@@ -199,7 +198,6 @@ export default {
         this.toggleNode(this.node, d, false);
         this.toggleLine(this.line, d, false);
         this.toggleLine(this.lineNode, d, false);
-        that.removeHoneycomb(that);
       });
       this.defs = this.graph.append('defs');
       this.arrowMarker = this.defs
@@ -228,33 +226,16 @@ export default {
         .on('mouseover', function(d, i) {
            that.tipName.show(d, this);
         })
-        .on('mouseout', function(d, i) {
-          that.tipName.hide(d, this);
-        })
-        .on('click', function(d, i) {
-          that.removeHoneycomb(that);
-          event.stopPropagation();
-          that.tip.hide({}, this);
-          that.node.attr('class', '');
-          d3.select(this).attr('class', 'node-active');
-          const copyD = JSON.parse(JSON.stringify(d));
-          delete copyD.x;
-          delete copyD.y;
-          delete copyD.vx;
-          delete copyD.vy;
-          delete copyD.fx;
-          delete copyD.fy;
-          delete copyD.index;
-          that.$store.commit('rocketTopo/SET_NODE', copyD);
-          that.toggleNode(that.node, d, true);
-          that.toggleLine(that.line, d, true);
-          that.toggleLine(that.lineNode, d, true);
-          if (d.isReal) {
+          .on('contextmenu', function (d) {
+           if (d.isReal) {
             const honeycombFrames = d3.select('#honeycomb-selector_honeycomb-frames');
             const appGovernTopoHoneycombFrames = that.graph.append('g')
                 .attr('id', 'app-govern-topo-honeycomb-frames')
                 .attr('style', honeycombFrames.attr('style'))
-                .attr('stroke', honeycombFrames.attr('stroke')).html(honeycombFrames.html());
+                .attr('stroke', honeycombFrames.attr('stroke')).html(honeycombFrames.html())
+                .on('mouseleave', function () {
+                 that.removeHoneycomb(that);
+                });
             const nodeTranslate = CssHelper.translateSerialization(this.getAttribute('transform'));
             const appGovernTopoHoneycombFramesTranslate = CssHelper.matrixSerialization(honeycombFrames.attr('transform'));
             appGovernTopoHoneycombFramesTranslate.tx = nodeTranslate.x - 83;
@@ -265,20 +246,45 @@ export default {
             that.$store.commit('rocketTopo/SET_HONEYCOMB_NODE', d);
 
             d3.selectAll('#honeycomb-selector_honeycomb-group-top-right').on('click', () => {
-              that.$router.push({path: '/alarm', query: { from: '/topology' , keyword: d.name}})
+             that.$store.commit('rocketTopo/SET_SHOW_ALARM_DIALOG', true);
+             that.removeHoneycomb(that);
             });
             d3.selectAll('#honeycomb-selector_honeycomb-group-below-right').on('click', () => {
-              that.$router.push({path: '/trace', query: { from: '/topology', scope: JSON.stringify({ key: d.id, label: d.name }) }})
+             that.$store.commit('rocketTopo/SET_SHOW_TRACE_DIALOG', true);
+             that.removeHoneycomb(that);
             });
             d3.selectAll('#honeycomb-selector_honeycomb-group-below-left').on('click', () => {
              that.$store.commit('SET_CURRENT_SERVICE', { key: d.id, label: d.name });
-             that.$router.push({path: '/', query: { from: '/topology' }})
+             that.$store.commit('rocketTopo/SET_SHOW_INSTANCES_DIALOG', true);
+             that.removeHoneycomb(that);
             });
             d3.selectAll('#honeycomb-selector_honeycomb-group-top-left').on('click', () => {
              that.$store.commit('SET_CURRENT_SERVICE', { key: d.id, label: d.name });
-             that.$router.push({path: '/', query: { from: '/topology' }})
+             that.$store.commit('rocketTopo/SET_SHOW_ENDPOINT_DIALOG', true);
+             that.removeHoneycomb(that);
             });
            }
+          })
+        .on('mouseout', function(d, i) {
+          that.tipName.hide(d, this);
+        })
+        .on('click', function(d, i) {
+          event.stopPropagation();
+          that.tip.hide({}, this);
+          that.node.attr('class', '');
+          d3.select(this).attr('class', 'node-active');
+          const copyD = JSON.parse(JSON.stringify(d));
+          delete copyD.x;
+          delete copyD.y;
+          delete copyD.vx;
+          delete copyD.vy;
+          delete copyD.fx;
+          delete copyD.fy;
+          delete copyD.index;
+          that.$store.commit('rocketTopo/SET_NODE', copyD);
+          that.toggleNode(that.node, d, true);
+          that.toggleLine(that.line, d, true);
+          that.toggleLine(that.lineNode, d, true);
         });
       this.node
         .append('image')
diff --git a/src/views/components/trace/trace-search.vue b/src/views/components/trace/trace-search.vue
index dea57de..3555f9e 100644
--- a/src/views/components/trace/trace-search.vue
+++ b/src/views/components/trace/trace-search.vue
@@ -17,7 +17,7 @@
 
 <template>
   <div class="rk-trace-search">
-    <div class="clear">
+    <div>
       <a class="rk-trace-clear-btn r" @click="status = !status">
         <span class="mr-5 vm">{{this.$t('more')}}</span>
         <svg class="icon trans vm" :style="`transform: rotate(${status?180:0}deg);`">
@@ -37,7 +37,6 @@
         <span class="vm">{{this.$t('clear')}}</span>
       </a>
       <div class="flex-h">
-        <RkBack v-if="$route.query.from"/>
         <TraceSelect :hasSearch="true" :title="this.$t('service')" :value="service" @input="chooseService"
                      :data="rocketTrace.services" :readonly="inTopo"/>
         <TraceSelect :hasSearch="true" :title="this.$t('instance')" v-model="instance" :data="rocketTrace.instances"/>
@@ -93,7 +92,7 @@
     private status: boolean = true;
     private maxTraceDuration: string = localStorage.getItem('maxTraceDuration') || '';
     private minTraceDuration: string = localStorage.getItem('minTraceDuration') || '';
-    @Prop({default: () => ({label: 'All', key: ''})})
+    @Prop({default: {label: 'All', key: ''}})
     private service!: Option;
     private instance: Option = {label: 'All', key: ''};
     private endpointName: string = localStorage.getItem('endpointName') || '';
diff --git a/src/views/containers/alarm.vue b/src/views/containers/alarm.vue
index 1bb8b8f..61c6afb 100644
--- a/src/views/containers/alarm.vue
+++ b/src/views/containers/alarm.vue
@@ -17,7 +17,7 @@
 
 <template>
   <div class="rk-alarm flex-v">
-    <AlarmTool :durationTime="durationTime" :total="rocketAlarm.total" :alarmScope="alarmScope" :inTopo="inTopo" :keyword="$route.query.keyword || ''"/>
+    <AlarmTool :durationTime="durationTime" :total="rocketAlarm.total" :alarmScope="alarmScope" :inTopo="inTopo" :keyword="keyword"/>
     <div style="flex-grow: 1;overflow: auto;height: 100%;">
       <AlarmTable :data="rocketAlarm.alarmService"/>
     </div>
@@ -27,6 +27,7 @@
 <script lang="ts">
 import Vue from 'vue';
 import Component from 'vue-class-component';
+import alarm from '@/store/modules/alarm';
 import { Prop } from 'vue-property-decorator';
 import AlarmTool from '../components/alarm/alarm-tool.vue';
 import AlarmTable from '../components/alarm/alarm-table.vue';
@@ -38,10 +39,19 @@ import { State, Action, Getter } from 'vuex-class';
 export default class Alarm extends Vue {
   @State('rocketAlarm') private rocketAlarm!: any;
   @Getter('durationTime') private durationTime: any;
-  @Prop({default: () => ({label: 'All', key: ''})})
+  @Prop({default: {label: 'All', key: ''}})
   private alarmScope: any;
   @Prop({default: false, type: Boolean})
   private inTopo!: boolean;
+  @Prop({default: ''})
+  private keyword!: string;
+  private beforeCreate() {
+    this.$store.registerModule('rocketAlarm', alarm);
+  }
+  private beforeDestroy() {
+    this.$store.unregisterModule('rocketAlarm');
+
+  }
 }
 </script>
 
diff --git a/src/views/containers/dashboard.vue b/src/views/containers/dashboard.vue
index cfb2fa8..96bc79d 100644
--- a/src/views/containers/dashboard.vue
+++ b/src/views/containers/dashboard.vue
@@ -86,6 +86,9 @@ export default class Dashboard extends Vue {
     return this.MIXHANDLE_GET_OPTION({compType: this.compType, duration: this.durationTime})
       .then(() => {this.handleRefresh(); });
   }
+  // private beforeCreate() {
+  //   this.$store.registerModule('rocketDashboard', dashboard);
+  // }
   private beforeMount() {
     if (window.localStorage.getItem('dashboard')) {
       const data: string = `${window.localStorage.getItem('dashboard')}`;
@@ -94,6 +97,9 @@ export default class Dashboard extends Vue {
     this.handleOption();
     this.SET_EVENTS([this.handleRefresh]);
   }
+  // private beforeDestroy() {
+  //   this.$store.unregisterModule('rocketDashboard');
+  // }
 }
 </script>
 <style lang="scss">
diff --git a/src/views/containers/endpoint-survey-window.vue b/src/views/containers/endpoint-survey-window.vue
new file mode 100644
index 0000000..6a86585
--- /dev/null
+++ b/src/views/containers/endpoint-survey-window.vue
@@ -0,0 +1,148 @@
+/**
+* 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="performance-metrics-window">
+    <el-drawer
+      :destroy-on-close="true"
+      :visible.sync="isShowSync"
+      direction="rtl"
+      size="80%">
+      <div class="rk-dashboard-bar flex-h">
+        <ToolBarSelect
+            :selectable="false"
+            :title="this.$t('currentService')"
+            :current="stateDashboardOption.currentService"
+            :data="stateDashboardOption.services"
+            icon="package"/>
+        <ToolBarEndpointSelect @onChoose="selectEndpoint" :title="$t('currentEndpoint')"
+                               :current="stateDashboardOption.currentEndpoint" :data="endpoints" icon="code">
+        </ToolBarEndpointSelect>
+      </div>
+      <endpoints-survey v-if="!rocketComps.loading" :style="`overflow: auto; height: ${endpointsSurveyHeight}`" />
+    </el-drawer>
+  </div>
+</template>
+
+<script lang="ts">
+  import EndpointsSurvey from '@/views/components/topology/endpoints-survey.vue';
+  import ToolBarSelect from '@/views/components/dashboard/tool-bar-select.vue';
+  import ToolBarEndpointSelect from '@/views/components/dashboard/tool-bar-endpoint-select.vue';
+  import _ from 'lodash';
+  import Vue from 'vue';
+  import { Component, PropSync, Watch } from 'vue-property-decorator';
+  import { Action, Getter, State } from 'vuex-class';
+
+  interface Endpoint {
+    label: string;
+    key: string;
+    name?: string;
+  }
+
+  @Component({
+    components: {
+      EndpointsSurvey,
+      ToolBarSelect,
+      ToolBarEndpointSelect,
+    },
+  })
+  export default class InstancesSurveyWindow extends Vue {
+    @State('rocketOption') private stateDashboardOption!: any;
+    @State('rocketData') private rocketComps!: any;
+    @Getter('durationTime') private durationTime: any;
+    @Action('SELECT_ENDPOINT') private SELECT_ENDPOINT: any;
+    @Action('MIXHANDLE_CHANGE_GROUP_WITH_CURRENT') private MIXHANDLE_CHANGE_GROUP_WITH_CURRENT: any;
+    @Action('MIXHANDLE_GET_OPTION') private MIXHANDLE_GET_OPTION: any;
+    @Action('GET_QUERY') private GET_QUERY: any;
+    @PropSync('isShow', { default: false })
+    private isShowSync!: boolean;
+    private endpointsSurveyHeight = '100%';
+
+    private tabsLoading = true;
+    private endpointName: string = '0';
+    private endpointKey: string = '0';
+    private endpoints: any[] = [];
+
+    private dragIndex: number = NaN;
+
+    public dragStart(index: number) {
+      this.dragIndex = index;
+    }
+
+    private selectEndpoint(i: any) {
+      this.SELECT_ENDPOINT({endpoint: i, duration: this.durationTime});
+    }
+
+    private handleRefresh() {
+      this.GET_QUERY({
+        serviceId: this.stateDashboardOption.currentService.key || '',
+        endpointId: this.endpointKey || '',
+        endpointName: this.endpointName || '',
+        duration: this.durationTime,
+      });
+    }
+
+    private handleOption() {
+      this.MIXHANDLE_CHANGE_GROUP_WITH_CURRENT({ index: 0, current: 2 });
+      return this.MIXHANDLE_GET_OPTION({ compType: 'service', duration: this.durationTime })
+      .then(() => {
+        this.handleRefresh();
+      });
+    }
+
+    @Watch('stateDashboardOption.endpoints')
+    private watchInstances(endpoints: Endpoint[]) {
+      _.forEach(endpoints, (endpoint) => {
+        endpoint.name = endpoint.label;
+      });
+      this.endpoints = endpoints;
+      if (endpoints.length > 0 && (this.endpointName === '0')) {
+        this.SELECT_ENDPOINT({ endpoint: endpoints[0], duration: this.durationTime });
+        if (endpoints[0].name) {
+          this.endpointName = endpoints[0].name;
+          this.endpointKey = endpoints[0].key;
+        }
+      }
+      this.tabsLoading = false;
+    }
+
+    private beforeMount() {
+      this.handleOption();
+    }
+
+    private mounted() {
+      this.resize();
+      window.addEventListener('resize', this.resize);
+    }
+
+    private resize() {
+      this.endpointsSurveyHeight = `${document.body.clientHeight - 101}px`;
+    }
+
+    private beforeDestroy() {
+      window.removeEventListener('resize', this.resize);
+    }
+  }
+</script>
+
+<style lang="scss">
+  .rk-dashboard-bar {
+    flex-shrink: 0;
+    color: #efefef;
+    background-color: #333840;
+  }
+</style>
diff --git a/src/views/containers/instances-survey-window.vue b/src/views/containers/instances-survey-window.vue
new file mode 100644
index 0000000..ed6d767
--- /dev/null
+++ b/src/views/containers/instances-survey-window.vue
@@ -0,0 +1,142 @@
+/**
+* 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="performance-metrics-window">
+    <el-drawer
+      :destroy-on-close="true"
+      title="Instances"
+      :visible.sync="isShowSync"
+      direction="rtl"
+      size="80%">
+      <div class="rk-dashboard-bar flex-h">
+        <ToolBarSelect
+            :selectable="false"
+            :title="this.$t('currentService')"
+            :current="stateDashboardOption.currentService"
+            :data="stateDashboardOption.services" icon="package"/>
+        <ToolBarSelect
+            @onChoose="selectInstance"
+            :title="$t('currentInstance')"
+            :current="stateDashboardOption.currentInstance"
+            :data="instances" icon="disk"/>
+      </div>
+      <instances-survey v-if="isShowSync" :style="`overflow: auto; height: ${instancesSurveyHeight}`" />
+    </el-drawer>
+  </div>
+</template>
+
+<script lang="ts">
+  import InstancesSurvey from '@/views/components/topology/instances-survey.vue';
+  import ToolBarSelect from '@/views/components/dashboard/tool-bar-select.vue';
+  import ToolBarEndpointSelect from '@/views/components/dashboard/tool-bar-endpoint-select.vue';
+  import _ from 'lodash';
+  import Vue from 'vue';
+  import { Component, PropSync, Watch } from 'vue-property-decorator';
+  import { Action, Getter, State } from 'vuex-class';
+
+  interface Instance {
+    label: string;
+    key: string;
+    name?: string;
+  }
+
+  @Component({
+    components: {
+      InstancesSurvey,
+      ToolBarSelect,
+      ToolBarEndpointSelect,
+    },
+  })
+  export default class InstancesSurveyWindow extends Vue {
+    @State('rocketOption') private stateDashboardOption!: any;
+    @State('rocketData') private rocketComps!: any;
+    @Getter('durationTime') private durationTime: any;
+    @Action('SELECT_INSTANCE') private SELECT_INSTANCE: any;
+    @Action('MIXHANDLE_CHANGE_GROUP_WITH_CURRENT') private MIXHANDLE_CHANGE_GROUP_WITH_CURRENT: any;
+    @Action('MIXHANDLE_GET_OPTION') private MIXHANDLE_GET_OPTION: any;
+    @Action('GET_QUERY') private GET_QUERY: any;
+    @PropSync('isShow', { default: false })
+    private isShowSync!: boolean;
+    private instancesSurveyHeight = '100%';
+
+    private tabsLoading = true;
+    private instanceName: string = '0';
+    private instances: any[] = [];
+
+    private dragIndex: number = NaN;
+
+    public dragStart(index: number) {
+      this.dragIndex = index;
+    }
+
+    private selectInstance(i: any) {
+      this.SELECT_INSTANCE({instance: i, duration: this.durationTime});
+    }
+
+    private handleRefresh() {
+      this.GET_QUERY({
+        serviceId: this.stateDashboardOption.currentService.key || '',
+        duration: this.durationTime,
+      });
+    }
+
+    private handleOption() {
+      this.MIXHANDLE_CHANGE_GROUP_WITH_CURRENT({ index: 0, current: 3 });
+      return this.MIXHANDLE_GET_OPTION({ compType: 'service', duration: this.durationTime })
+      .then(() => {
+        this.handleRefresh();
+      });
+    }
+
+    @Watch('stateDashboardOption.instances')
+    private watchInstances(instances: Instance[]) {
+      _.forEach(instances, (instance) => {
+        instance.name = instance.label.includes('@') ? instance.label.split('@')[1] : instance.label;
+      });
+      this.instances = instances;
+      if (instances.length > 0 && (this.instanceName === '0')) {
+        this.SELECT_INSTANCE({ instance: instances[0], duration: this.durationTime });
+        if (instances[0].name) {
+          this.instanceName = instances[0].name;
+        }
+      }
+      this.tabsLoading = false;
+    }
+
+    private beforeMount() {
+      this.handleOption();
+    }
+
+    private mounted() {
+      this.resize();
+      window.addEventListener('resize', this.resize);
+    }
+
+    private resize() {
+      this.instancesSurveyHeight = `${document.body.clientHeight - 101}px`;
+    }
+
+    private beforeDestroy() {
+      window.removeEventListener('resize', this.resize);
+    }
+  }
+</script>
+
+<style lang="less" scoped>
+
+</style>
diff --git a/src/views/containers/topology.vue b/src/views/containers/topology.vue
index 64734f3..25c3da8 100644
--- a/src/views/containers/topology.vue
+++ b/src/views/containers/topology.vue
@@ -28,7 +28,7 @@ import { AxiosResponse } from 'axios';
 import Topo from '../components/topology/topo.vue';
 import TopoDate from '../components/topology/topo-date.vue';
 import TopoAside from '../components/topology/topo-aside.vue';
-import { State as topoState} from '@/store/modules/topology';
+import topo, { State as topoState} from '@/store/modules/topology';
 
 @Component({components: {Topo, TopoAside, TopoDate}})
 export default class Topology extends Vue {
@@ -48,9 +48,13 @@ export default class Topology extends Vue {
   private getTopo() {
     this.GET_TOPO({duration: this.durationTime});
   }
+  private beforeCreate() {
+    this.$store.registerModule('rocketTopo', topo);
+  }
   private beforeDestroy() {
     this.CLEAR_TOPO_INFO();
     this.CLEAR_TOPO();
+    this.$store.unregisterModule('rocketTopo');
   }
 }
 
diff --git a/src/views/containers/trace.vue b/src/views/containers/trace.vue
index 4098450..a58bc8f 100644
--- a/src/views/containers/trace.vue
+++ b/src/views/containers/trace.vue
@@ -17,7 +17,7 @@
 
 <template>
   <div class="rk-trace flex-v">
-    <TraceSearch :service="$route.query.scope?JSON.parse($route.query.scope):service" :inTopo="inTopo"/>
+    <TraceSearch :service="service" :inTopo="inTopo"/>
     <div class="rk-trace-inner">
       <TraceTable/>
       <TraceDetail :current="stateTrace.currentTrace" :spans="stateTrace.traceSpans"/>
@@ -32,6 +32,7 @@ import { State, Action, Mutation } from 'vuex-class';
 import TraceSearch from '@/views/components/trace/trace-search.vue';
 import TraceTable from '@/views/components/trace/trace-table.vue';
 import TraceDetail from '@/views/components/trace/trace-detail.vue';
+import trace from '../../store/modules/trace';
 @Component({
   components: {
     TraceTable, TraceDetail, TraceSearch,
@@ -50,9 +51,15 @@ export default class Trace extends Vue {
   private inTopo!: boolean;
 
   private show: boolean = true;
+  private beforeCreate() {
+    this.$store.registerModule('rocketTrace', trace);
+  }
   private beforeMount() {
      this.SET_EVENTS([]);
   }
+  private beforeDestroy() {
+    this.$store.unregisterModule('rocketTrace');
+  }
 }
 </script>
 <style lang="scss">