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 06d9898  Metrics Comparison View (#180)
06d9898 is described below

commit 06d9898c8d902a2f4a51b22744a72527dc74d694
Author: Fine <[email protected]>
AuthorDate: Sun Nov 10 20:50:50 2019 +0800

    Metrics Comparison View (#180)
    
    * feat: add comparison entry
    
    * refactor: update apiname
    
    * feat: add components
    
    * feat: add metrics config
    
    * feat: get service
    
    * feat: init comparison config
    
    * feat: add query chart
    
    * feat: add next service param
    
    * refactor: update comparison store
    
    * refactor: update store
    
    * feat: update query val
    
    * feat: change select
    
    * feat: select config and render chartt
    
    * feat: add dataBase type
    
    * feat: update config
    
    * doc: git ignore
    
    * feat: translate
    
    * feat: add metric source
    
    * feat: update interface
    
    * chord: rm yarn lock
    
    * refactor: add reload and update store
    
    * feat: update chart style
    
    * style: rm dead code
    
    * doc: update config
    
    * fix: typo
    
    * feat: add select component
    
    * fix: next service config
    
    * fix: init config by reload btn
    
    * feat: reset config
    
    * fix: clear cache
    
    * feat: format soruce value
---
 .gitignore                                         |   1 +
 src/assets/lang/en.ts                              |   6 +
 src/assets/lang/zh.ts                              |   6 +
 src/components/index.ts                            |   3 +-
 src/components/rk-echarts.vue                      |   4 +-
 src/components/rk-header.vue                       |   6 +
 src/components/rk-select.vue                       | 120 +++++
 src/router.ts                                      |   5 +
 src/store/modules/comparison/comparison-const.ts   |  77 ++++
 src/store/modules/comparison/comparison-store.ts   | 498 +++++++++++++++++++++
 .../modules/comparison}/index.ts                   |  23 +-
 src/store/modules/dashboard/fragments/database.ts  |  42 +-
 .../modules/dashboard/modules/dashboard-data.ts    |  72 +--
 src/store/mutation-types.ts                        |  11 +
 src/types/comparison.d.ts                          |  52 +++
 src/utils/queryChartData.ts                        |  87 ++++
 src/views/components/comparison/chart-line.vue     | 104 +++++
 .../components/comparison/comparison-charts.vue}   |  47 +-
 .../components/comparison/comparison-config.vue    | 172 +++++++
 .../components/comparison}/index.ts                |  24 +-
 src/views/containers/comparison.vue                |  69 +++
 21 files changed, 1293 insertions(+), 136 deletions(-)

diff --git a/.gitignore b/.gitignore
index 9620a91..9501864 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,6 +5,7 @@ npm-debug.log*
 yarn-debug.log*
 yarn-error.log*
 node
+yarn.lock
 
 # Editor directories and files
 .idea
diff --git a/src/assets/lang/en.ts b/src/assets/lang/en.ts
index b3fb772..70a2a0b 100644
--- a/src/assets/lang/en.ts
+++ b/src/assets/lang/en.ts
@@ -98,6 +98,12 @@ const m = {
   serverZone: 'Server Zone',
   percentResponse: 'Percent Response',
   exportImage: 'Export image',
+  comparison: 'Metrics Comparison',
+  queryData: 'Query',
+  previousService: 'Previous Service',
+  nextService: 'Next Service',
+  object: 'Object',
+  metrics: 'Metrics',
 };
 
 export default m;
diff --git a/src/assets/lang/zh.ts b/src/assets/lang/zh.ts
index a2f7613..91a64fd 100644
--- a/src/assets/lang/zh.ts
+++ b/src/assets/lang/zh.ts
@@ -98,6 +98,12 @@ const m = {
   serverZone: '服务器时区',
   percentResponse: '百分比响应',
   exportImage: '导出为图片',
+  comparison: '指标对比',
+  queryData: '数据查询',
+  previousService: '上一个服务',
+  nextService: '下一个服务',
+  object: '粒度',
+  metrics: '指标',
 };
 
 export default m;
diff --git a/src/components/index.ts b/src/components/index.ts
index 2b921e0..44d43f2 100644
--- a/src/components/index.ts
+++ b/src/components/index.ts
@@ -25,9 +25,10 @@ import RkPanel from './rk-panel.vue';
 import RkSidebox from './rk-sidebox.vue';
 import RkEcharts from './rk-echarts.vue';
 import noty from './noty';
+import RkSelect from './rk-select.vue';
 
 const components: any = {
-  RkHeader, RkFooter, RkProgress, RkDate, RkPanel, RkEcharts, RkPage, 
RkSidebox, RkFooterTime,
+  RkHeader, RkFooter, RkProgress, RkDate, RkPanel, RkEcharts, RkPage, 
RkSidebox, RkFooterTime, RkSelect,
 };
 const componentsName: string[] = Object.keys(components);
 export default {install: (vue: any) => {
diff --git a/src/components/rk-echarts.vue b/src/components/rk-echarts.vue
index 31649eb..840b56d 100644
--- a/src/components/rk-echarts.vue
+++ b/src/components/rk-echarts.vue
@@ -44,9 +44,9 @@ export default class RkEcharts extends Vue {
   private onoptionChanged(newVal: any, oldVal: any): void {
     if (this.myChart) {
       if (newVal) {
-        this.myChart.setOption(newVal);
+        this.myChart.setOption(newVal, true); // clear cache
       } else {
-        this.myChart.setOption(oldVal);
+        this.myChart.setOption(oldVal, true);
       }
     } else {
       this.drawEcharts();
diff --git a/src/components/rk-header.vue b/src/components/rk-header.vue
index fb51037..c493e35 100644
--- a/src/components/rk-header.vue
+++ b/src/components/rk-header.vue
@@ -46,6 +46,12 @@
         </svg>
         <span class="vm hide-xs ml-5">{{this.$t('alarm')}}</span>
       </router-link>
+      <router-link class="nav-link mr-20" to="/comparison">
+        <svg class="icon sm vm">
+          <use xlink:href="#chart"></use>
+        </svg>
+        <span class="vm hide-xs ml-5">{{this.$t('comparison')}}</span>
+      </router-link>
     </div>
     <div class="flex-h">
       <a class="rk-btn mr-5 sm" :class="auto?'blue':'ghost'" 
@click="handleAuto">
diff --git a/src/components/rk-select.vue b/src/components/rk-select.vue
new file mode 100644
index 0000000..fed32ea
--- /dev/null
+++ b/src/components/rk-select.vue
@@ -0,0 +1,120 @@
+/**
+ * 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-bar-select cp flex-h" v-clickout="() => { visible = 
false;search = '';}" :class="{'active':visible}">
+    <div class="rk-bar-i flex-h" @click="visible = !visible">
+      <div class="mr-15 rk-bar-i-text">
+        <div class="sm grey">{{title}}</div>
+        <div class="ell" v-tooltip:right.ellipsis="current.label || 
''">{{current.label}}</div>
+      </div>
+      <svg class="icon lg trans" :style="`transform: 
rotate(${visible?180:0}deg)`">
+        <use xlink:href="#arrow-down"></use>
+      </svg>
+    </div>
+    <div class="rk-sel" v-if="visible">
+      <div>
+        <input type="text" class="rk-sel-search" v-model="search">
+        <svg class="icon sm close" @click="search = ''" v-if="search">
+          <use xlink:href="#clear"></use>
+        </svg>
+      </div>
+      <div class="rk-opt-wrapper scroll_hide">
+        <div class="rk-opt ell" @click="handleSelect(i)" 
:class="{'active':i.key === current.key}" v-for="i in filterData" 
:key="i.key">{{i.label}}</div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script lang="ts">
+import { Vue, Component, Prop } from 'vue-property-decorator';
+@Component
+export default class RkSelect extends Vue {
+  @Prop() public data!: any;
+  @Prop() public current!: any;
+  @Prop() public title!: string;
+  @Prop() public icon!: string;
+  public search: string = '';
+  public visible: boolean = false;
+  get filterData() {
+    return this.data.filter((i: any) => 
i.label.toUpperCase().indexOf(this.search.toUpperCase()) !== -1);
+  }
+  public handleOpen() {
+    this.visible = true;
+  }
+  public handleSelect(i: any) {
+    this.$emit('onChoose', i);
+    this.visible = false;
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.rk-bar-select {
+  position: relative;
+  height: 40px;
+  justify-content: space-between;
+  border: 1px solid #ddd;
+  background: #fff;
+  border-radius: 3px;
+  .sm{ line-height: 12px;}
+  .icon { flex-shrink: 0};
+}
+.rk-bar-i-text{
+  width: 100%;
+}
+.rk-bar-i {
+  height: 100%;
+  width: 100%;
+  padding: 5px 15px;
+}
+.rk-sel{
+  position: absolute;
+  top: 39px;
+  background: #fff;
+  box-shadow: 0 1px 6px rgba(99, 99, 99, 0.2);
+  border: 1px solid #ddd;
+  width: 100%;
+  border-radius: 0 0 3px 3px;
+  border-right-width: 1px !important;
+  z-index: 10;
+  .close{
+    position: absolute;
+    right: 10px;
+    top: 12px;
+    opacity: 0.6;
+    &:hover{opacity: 1;}
+  }
+}
+.rk-opt{
+  padding: 7px 15px;
+}
+.rk-sel-search{
+  width: calc(100% - 4px);
+  border:0;
+  border-bottom: 1px solid #ddd;
+  outline: 0;
+  padding: 7px 25px 7px 10px;
+  margin: 2px;
+  border-radius: 3px;
+}
+.rk-opt-wrapper{
+  overflow: auto;
+  max-height: 200px;
+  padding-bottom: 2px;
+}
+</style>
diff --git a/src/router.ts b/src/router.ts
index 7fc74b6..7df8dfd 100644
--- a/src/router.ts
+++ b/src/router.ts
@@ -23,6 +23,7 @@ import Dashboard from './views/containers/dashboard.vue';
 import Trace from './views/containers/trace.vue';
 import Topology from './views/containers/topology.vue';
 import Alarm from './views/containers/alarm.vue';
+import Comparison from './views/containers/comparison.vue';
 
 Vue.use(Router);
 window.axiosCancel = [];
@@ -57,6 +58,10 @@ const router = new Router({
           path: 'alarm',
           component: Alarm,
         },
+        {
+          path: 'comparison',
+          component: Comparison,
+        },
       ],
     },
   ],
diff --git a/src/store/modules/comparison/comparison-const.ts 
b/src/store/modules/comparison/comparison-const.ts
new file mode 100644
index 0000000..f77cac2
--- /dev/null
+++ b/src/store/modules/comparison/comparison-const.ts
@@ -0,0 +1,77 @@
+/**
+ * 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.
+ */
+import { IOption, ICurrentOptions, DataSourceType } from '@/types/comparison';
+
+export const ComparisonType: IOption[] = [
+  {key: 'Service', label: 'Service'},
+  {key: 'ServiceInstance', label: 'Service Instance'},
+  {key: 'ServiceEndpoint', label: 'Service Endpoint'},
+  {key: 'Database', label: 'Database'},
+];
+
+export enum ObjectType {
+  Service = 'Service',
+  ServiceInstance = 'ServiceInstance',
+  ServiceEndpoint = 'ServiceEndpoint',
+  Database = 'Database',
+}
+
+export enum ServiceType {
+  PREVIOUS = 'PREVIOUS',
+  NEXT = 'NEXT',
+}
+
+export const ComparisonOption: ICurrentOptions = {
+  preService: {key: 0, label: ''},
+  preType: {key: 'ServiceEndpoint', label: 'Service Endpoint'},
+  preObject: {key: 0, label: '/projectB/{name}'},
+  preMetrics: {key: 0, label: ''},
+  nextService: {key: 0, label: ''},
+  nextType: {key: 'ServiceEndpoint', label: 'Service Endpoint'},
+  nextObject: {key: 0, label: '/projectA/{name}'},
+  nextMetrics: {key: 0, label: ''},
+};
+
+export const InitSource: DataSourceType = {
+  preServiceSource: [],
+  preTypeSource: ComparisonType,
+  preObjectSource: [],
+  preMetricsSource: [],
+  nextServiceSource: [],
+  nextTypeSource: ComparisonType,
+  nextObjectSource: [],
+  nextMetricsSource: [],
+};
+
+export enum ChangeType {
+  PreService = 'preService',
+  PreType = 'preType',
+  PreObject = 'preObject',
+  PreMetrics = 'preMetrics',
+  NextService = 'nextService',
+  NextType = 'nextType',
+  NextObject = 'nextObject',
+  NextMetrics = 'nextMetrics',
+}
+
+export enum StatusType {
+  Init = 'init',
+  Pre = 'pre',
+  Next = 'next',
+}
+
+export const LinearType = ['ChartBar', 'ChartLine'];
diff --git a/src/store/modules/comparison/comparison-store.ts 
b/src/store/modules/comparison/comparison-store.ts
new file mode 100644
index 0000000..ae0ba6c
--- /dev/null
+++ b/src/store/modules/comparison/comparison-store.ts
@@ -0,0 +1,498 @@
+/**
+ * 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.
+ */
+
+import { Commit, ActionTree, Dispatch } from 'vuex';
+import axios, { AxiosResponse } from 'axios';
+
+import graph from '@/graph';
+import { cancelToken } from '@/utils/cancelToken';
+import * as types from '../../mutation-types';
+import { DurationTime } from '@/types/global';
+import { queryChartData } from '@/utils/queryChartData';
+import fragmentAll from '@/store/modules/dashboard/fragments';
+import { ICurrentOptions, DataSourceType, ISelectConfig, MetricsType } from 
'@/types/comparison';
+import {
+  ComparisonOption, InitSource, LinearType, ComparisonType,
+  ObjectType, ServiceType, ChangeType, StatusType,
+} from './comparison-const';
+
+type GenericIdentityFn<T> = (arg: T) => T;
+
+function identity<T>(arg: T): T {
+  return arg;
+}
+export interface State {
+  currentOptions: ICurrentOptions;
+  dataSource: DataSourceType;
+  chartSource: GenericIdentityFn<any>;
+  isPrevious: StatusType;
+  metricSource: MetricsType;
+}
+
+interface ActionsParamType {
+  duration: DurationTime;
+}
+
+const initState: State = {
+  currentOptions: ComparisonOption,
+  dataSource: InitSource,
+  chartSource: identity,
+  isPrevious: StatusType.Init,
+  metricSource: {} as MetricsType,
+};
+
+// getters
+const getters = {
+  queryPreValue(state: State) {
+    const { currentOptions } = state;
+    const preMetric = currentOptions.preMetrics.key;
+    const preParam = (fragmentAll as any)[preMetric];
+    if (!preParam) {
+      return;
+    }
+
+    return `query queryData(${preParam.variable.join(',')}) 
{${preParam.fragment}}`;
+  },
+  queryNextValue(state: State) {
+    const { currentOptions } = state;
+    const nextMetric =  currentOptions.nextMetrics.key;
+    const nextParam = (fragmentAll as any)[nextMetric];
+
+    if (!nextParam) {
+      return;
+    }
+    return `query queryData(${nextParam.variable.join(',')}) 
{${nextParam.fragment}}`;
+  },
+  preConfig(state: State) {
+    const { currentOptions } = state;
+    const variablesData = {
+      serviceId: currentOptions.preService.key,
+    } as any;
+    const { key } = currentOptions.preType;
+
+    if (key === ObjectType.ServiceEndpoint) {
+        variablesData.endpointId = currentOptions.preObject.key;
+        variablesData.endpointName = currentOptions.preObject.label;
+    } else if (key === ObjectType.ServiceInstance) {
+      variablesData.instanceId = currentOptions.preObject.key;
+    } else if (key === ObjectType.Database) {
+      delete variablesData.serviceId;
+      variablesData.databaseId = currentOptions.preObject.key;
+    }
+
+    return variablesData;
+  },
+  nextConfig(state: State) {
+    const { currentOptions } = state;
+    const { nextType, nextService, nextObject } = currentOptions;
+    let variablesData = {serviceId: nextService.key} as any;
+
+    if (nextType.key === ObjectType.ServiceEndpoint) {
+      variablesData = {
+        ...variablesData,
+        endpointId: nextObject.key,
+        endpointName: nextObject.label,
+      };
+    } else if (nextType.key === ObjectType.ServiceInstance) {
+      variablesData = {
+        ...variablesData,
+        instanceId: nextObject.key,
+      };
+    } else if (nextType.key === ObjectType.Database) {
+      variablesData.databaseId = nextObject.key;
+    }
+
+    return variablesData;
+  },
+  ChangeType() {
+    return {
+      PreService: ChangeType.PreService,
+      PreType: ChangeType.PreType,
+      PreObject: ChangeType.PreObject,
+      PreMetrics: ChangeType.PreMetrics,
+      NextService: ChangeType.NextService,
+      NextType: ChangeType.NextType,
+      NextObject: ChangeType.NextObject,
+      NextMetrics: ChangeType.NextMetrics,
+    };
+  },
+  AllMetrics() {
+    const { service, database } = queryChartData;
+    const MetricsObj = {
+      Service: [],
+      ServiceEndpoint: [],
+      ServiceInstance: [],
+      Database: [],
+    } as MetricsType;
+
+    for (const item of service) {
+      if (!LinearType.includes(item.c)) {
+        continue;
+      }
+      if (item.o === ObjectType.Service) {
+        MetricsObj.Service.push({
+          label: item.t,
+          key: item.d,
+        });
+      } else if (item.o === ObjectType.ServiceInstance) {
+        MetricsObj.ServiceInstance.push({
+          label: item.t,
+          key: item.d,
+        });
+      } else if (item.o === ObjectType.ServiceEndpoint) {
+        MetricsObj.ServiceEndpoint.push({
+          label: item.t,
+          key: item.d,
+        });
+      }
+    }
+    for (const data of database) {
+      if (!LinearType.includes(data.c)) {
+        continue;
+      }
+      if (data.o === ObjectType.Database) {
+        MetricsObj.Database.push({
+          label: data.t,
+          key: data.d,
+        });
+      }
+    }
+
+    return MetricsObj;
+  },
+};
+
+// mutations
+const mutations = {
+  [types.SET_ISPREVIOUS](state: State, data: StatusType) {
+    state.isPrevious = data;
+  },
+  [types.SET_METRICSOURCE](state: State, source: MetricsType) {
+    state.metricSource = source;
+  },
+  [types.SET_SERVICES](state: State, data: {services: any[]}) {
+    const { services } = data;
+
+    if (!services.length) {
+      return;
+    }
+    state.dataSource.preServiceSource = services;
+    state.dataSource.nextServiceSource = services;
+    state.currentOptions.preService = services[0];
+    state.currentOptions.nextService = services[0];
+  },
+  [types.SET_CONFIG](state: State, data: any[]) {
+    const { isPrevious, currentOptions, metricSource } = state as any;
+    const type = isPrevious === StatusType.Pre ? currentOptions.preType.key : 
currentOptions.nextType.key;
+
+    if (isPrevious === StatusType.Pre) {
+      state.dataSource.preObjectSource = data;
+      state.currentOptions.preObject = data[0];
+      state.dataSource.preMetricsSource = metricSource[type];
+      state.currentOptions.preMetrics = metricSource[type][0];
+    } else if (isPrevious === StatusType.Next) {
+      state.dataSource.nextObjectSource = data;
+      state.currentOptions.nextObject = data[0];
+      state.dataSource.nextMetricsSource = metricSource[type];
+      state.currentOptions.nextMetrics = metricSource[type][1];
+    } else {
+      state.currentOptions = {
+        ...state.currentOptions,
+        nextObject: data[0],
+        preObject: data[0],
+        preMetrics: metricSource[type][0],
+        nextMetrics: metricSource[type][1],
+        preType: ComparisonType[2],
+        nextType: ComparisonType[2],
+      };
+      state.dataSource = {
+        ...state.dataSource,
+        nextObjectSource: data,
+        preObjectSource: data,
+        preMetricsSource: metricSource[type],
+        nextMetricsSource: metricSource[type],
+      };
+    }
+  },
+  [types.SET_CHARTVAL](state: State, data: {value: any, type: string}) {
+    const keys = Object.keys(data.value);
+    const obj = {} as any;
+    for (const key of keys) {
+      const value = data.value[key].values.map((d: {value: number}) => 
d.value);
+      if (data.type === ServiceType.PREVIOUS) {
+        const { preObject, preService, preType } = state.currentOptions;
+        const str = `${preService.label}-`;
+        const strKeyPre = `${preType.key === ObjectType.Database ? '' : 
str}${preType.key === ObjectType.Service ? '' : preObject.label}-${key}`;
+        obj[strKeyPre] = value;
+      } else {
+        const { nextObject, nextService, nextType } = state.currentOptions;
+        const str = `${nextObject.label}`;
+        const servicesLabel =  `${nextService.label}-`;
+        const strKeyNext = `${nextType.key === ObjectType.Database ? '' : 
servicesLabel}${nextType.key === ObjectType.Service ? '' : str}-${key}`;
+        obj[strKeyNext] = value;
+      }
+    }
+    state.chartSource = {
+      ...obj,
+      ...state.chartSource,
+    };
+  },
+  [types.UPDATE_CONFIG](state: any, data: ISelectConfig) {
+    const {type, option} = data;
+
+    state.currentOptions[type] = option;
+  },
+  [types.CLEAR_CHART_VAL](state: State) {
+    state.chartSource = {} as any;
+  },
+  [types.SELECT_TYPE_SERVICES](state: State) {
+    const { preType, nextType } = state.currentOptions;
+    const { isPrevious, metricSource } = state as any;
+
+    if (isPrevious === StatusType.Pre) {
+      state.dataSource.preMetricsSource = metricSource[preType.key] || [];
+      state.currentOptions.preMetrics = metricSource[preType.key][0];
+    } else {
+      state.dataSource.nextMetricsSource = metricSource[nextType.key] || [];
+      state.currentOptions.nextMetrics = metricSource[nextType.key][0];
+    }
+  },
+  [types.SELECT_TYPE_INSTANCE](state: State, data: any) {
+    const { preType, nextType } = state.currentOptions;
+    const { isPrevious, metricSource } = state as any;
+
+    if (isPrevious === StatusType.Pre) {
+      state.dataSource.preMetricsSource = metricSource[preType.key];
+      state.currentOptions.preMetrics = metricSource[preType.key][0];
+      state.dataSource.preObjectSource = data;
+      state.currentOptions.preObject = data[0];
+    } else if (isPrevious === StatusType.Next) {
+      state.dataSource.nextMetricsSource = metricSource[nextType.key];
+      state.currentOptions.nextMetrics = metricSource[nextType.key][0];
+      state.dataSource.nextObjectSource = data;
+      state.currentOptions.nextObject = data[0];
+    }
+  },
+  [types.SELECT_TYPE_DATABASE](state: State, data: any) {
+    const { preType, nextType } = state.currentOptions;
+    const metricSource = state.metricSource as any;
+
+    if (state.isPrevious === StatusType.Next) {
+      state.dataSource.nextMetricsSource = metricSource[nextType.key];
+      state.currentOptions.nextMetrics = metricSource[nextType.key][0];
+      state.currentOptions.nextObject = data[0];
+      state.dataSource.nextObjectSource = data;
+    } else {
+      state.dataSource.preMetricsSource = metricSource[preType.key];
+      state.currentOptions.preMetrics = metricSource[preType.key][0];
+      state.currentOptions.preObject = data[0];
+      state.dataSource.preObjectSource = data;
+    }
+  },
+};
+
+// actions
+const actions: ActionTree<State, ActionsParamType> = {
+  GET_SERVICES(context: {commit: Commit, dispatch: Dispatch, getters: any, 
state: State}, params: {
+    duration: string;
+  }) {
+    if (context.state.isPrevious !== StatusType.Init) {
+      return;
+    }
+
+    context.commit(types.SET_METRICSOURCE, context.getters.AllMetrics);
+    context.commit(types.SET_ISPREVIOUS, StatusType.Init);
+    return graph.query('queryServices').params(params)
+      .then((res: AxiosResponse) => {
+        if (!res.data.data) {
+          return;
+        }
+        context.commit(types.SET_SERVICES, {services: res.data.data.services});
+      }).then(() => {
+        context.dispatch('GET_SERVICE_ENDPOINTS', params.duration);
+      });
+  },
+  GET_SERVICE_ENDPOINTS(context: { commit: Commit, state: State, dispatch: 
Dispatch }, date: string) {
+    if (!context.state.currentOptions.preService) {
+      return new Promise((resolve) => resolve());
+    }
+    const { isPrevious, currentOptions } = context.state;
+    const servicesId = isPrevious === StatusType.Pre ? 
currentOptions.preService.key : currentOptions.nextService.key;
+    graph
+      .query('queryEndpoints')
+      .params({serviceId: servicesId, keyword: ''})
+      .then((res: AxiosResponse) => {
+        if (!res.data.data) {
+          return;
+        }
+        context.commit(types.SET_CONFIG, res.data.data.getEndpoints);
+      }).then(() => {
+        if (isPrevious === StatusType.Init) {
+          context.dispatch('RENDER_CHART', date);
+        }
+      });
+  },
+  GET_SERVICE_INSTANCES(context: { commit: Commit, state: State }, params) {
+    const { isPrevious, currentOptions } = context.state;
+    params.serviceId = isPrevious === StatusType.Pre ? 
currentOptions.preService.key : currentOptions.nextService.key;
+    return graph
+      .query('queryInstances')
+      .params(params)
+      .then((res: AxiosResponse) => {
+        if (!res.data) {
+          return;
+        }
+        context.commit(types.SELECT_TYPE_INSTANCE, 
res.data.data.getServiceInstances);
+      });
+  },
+  GET_DATABASES(context: { commit: Commit, state: State  }, params: {duration: 
string}) {
+    return graph
+      .query('queryDatabases')
+      .params(params)
+      .then((res: AxiosResponse) => {
+        if (!res.data) {
+          return;
+        }
+        context.commit(types.SELECT_TYPE_DATABASE, res.data.data.services);
+      });
+  },
+  RENDER_CHART(context: {dispatch: Dispatch, commit: Commit}, date: string) {
+    context.commit(types.CLEAR_CHART_VAL);
+    context.dispatch('GET_COMPARISON', {duration: date, type: 
ServiceType.PREVIOUS});
+    context.dispatch('GET_COMPARISON', {duration: date, type: 
ServiceType.NEXT});
+  },
+  SELECT_CONFIG(context: {commit: Commit, state: State, dispatch: Dispatch}, 
params: any) {
+    const isPrevious = params.type.includes(StatusType.Next) ? StatusType.Next 
: StatusType.Pre;
+
+    context.commit(types.SET_ISPREVIOUS, isPrevious);
+    context.commit(types.UPDATE_CONFIG, params);
+
+    const { currentOptions } = context.state;
+    const objType = isPrevious === StatusType.Next ? currentOptions.nextType : 
currentOptions.preType;
+    const typeList = [ChangeType.PreService, ChangeType.NextService, 
ChangeType.PreType, ChangeType.NextType];
+
+    if (typeList.includes(params.type)) {
+      if (objType.key === ObjectType.Service) {
+        context.commit(types.SELECT_TYPE_SERVICES);
+      } else if (objType.key === ObjectType.ServiceInstance) {
+        context.dispatch('GET_SERVICE_INSTANCES', {
+          duration: params.duration,
+        });
+      } else if (objType.key === ObjectType.ServiceEndpoint) {
+        context.dispatch('GET_SERVICE_ENDPOINTS', params.duration);
+      } else if (objType.key === ObjectType.Database) {
+        context.dispatch('GET_DATABASES', {duration: params.duration});
+      }
+    }
+  },
+  GET_COMPARISON(
+    context: {commit: Commit, state: State, dispatch: Dispatch, getters: any}, 
param: {duration: string, type: string},
+  ) {
+    let variablesData = {
+      duration: param.duration,
+    } as any;
+    let queryVal = '';
+    if (param.type === ServiceType.PREVIOUS) {
+      variablesData = {
+        ...variablesData,
+        ...context.getters.preConfig,
+      };
+      queryVal = context.getters.queryPreValue;
+    } else {
+      variablesData = {
+        ...variablesData,
+        ...context.getters.nextConfig,
+      };
+      queryVal = context.getters.queryNextValue;
+    }
+    return axios.post('/graphql', {
+      query: queryVal,
+      variables: variablesData,
+    }, {cancelToken: cancelToken()}).then((res: AxiosResponse<any>) => {
+        const data = res.data.data;
+        if (!data) {
+          return;
+        }
+        context.dispatch('FORMAT_VALUE', {value: data, type: param.type});
+    });
+  },
+  FORMAT_VALUE(context: {commit: Commit, state: State, dispatch: Dispatch}, 
params: {value: any, type: string}) {
+    if (!(params && params.value)) {
+      return;
+    }
+    if (params.value.endpointSLA) {
+      params.value.endpointSLA.values = 
params.value.endpointSLA.values.map((i: any) => {
+        return {value: i.value / 100};
+      });
+    }
+    if (params.value.databaseSLA) {
+      params.value.databaseSLA.values = 
params.value.databaseSLA.values.map((i: any) => {
+        return {value: i.value / 100};
+    });
+    }
+    if (params.value.serviceSLA) {
+      params.value.serviceSLA.values = params.value.serviceSLA.values.map((i: 
any) => {
+        return {value: i.value / 100};
+      });
+    }
+    if (params.value.instanceSLA) {
+      params.value.instanceSLA.values = 
params.value.instanceSLA.values.map((i: any) => {
+        return {value: i.value / 100};
+      });
+    }
+    if (params.value.heap && params.value.maxHeap) {
+      params.value.heap.values = params.value.heap.values.map((i: any) => {
+        return {value: (i.value / 1048576).toFixed(2)};
+      });
+      params.value.maxHeap.values = params.value.maxHeap.values.map((i: any, 
index: number) => {
+        const val = i.value > -1 ? ((i.value / 1048576) - 
params.value.heap.values[index].value).toFixed(2) : 0;
+        return {value: val};
+      });
+      if (Math.max.apply(Math, params.value.maxHeap.values) === -1) {
+        params.value.maxHeap.values = 'Max Heap Unlimited';
+      }
+    }
+    if (params.value.nonheap && params.value.maxNonHeap) {
+      params.value.nonheap.values = params.value.nonheap.values.map((i: any) 
=> {
+        return {value : (i.value / 1048576).toFixed(2)};
+      });
+      params.value.maxNonHeap.values = params.value.maxNonHeap.values
+        .map((i: any, index: number) => {
+          const val = i.value > -1 ? ((i.value / 1048576) - 
params.value.nonheap.values[index].value).toFixed(2) : 0;
+          return {value: val};
+        });
+      if (Math.max.apply(Math, params.value.maxNonHeap.values) === -1) {
+        params.value.maxNonHeap.values = 'Max NonHeap Unlimited';
+      }
+    }
+    if (params.value.clrHeap) {
+      params.value.clrHeap.values =
+      params.value.clrHeap.values.map((i: any) => {
+        return { value: (i.value / 1048576 ).toFixed(2)};
+      });
+    }
+    context.commit(types.SET_CHARTVAL, params);
+  },
+};
+
+export default {
+  namespaced: true,
+  state: initState,
+  getters,
+  actions,
+  mutations,
+};
diff --git a/src/components/index.ts b/src/store/modules/comparison/index.ts
similarity index 52%
copy from src/components/index.ts
copy to src/store/modules/comparison/index.ts
index 2b921e0..3fb58be 100644
--- a/src/components/index.ts
+++ b/src/store/modules/comparison/index.ts
@@ -14,25 +14,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+import comparisonStore from './comparison-store';
 
-import RkHeader from './rk-header.vue';
-import RkFooter from './rk-footer.vue';
-import RkFooterTime from './rk-footer-time.vue';
-import RkProgress from './rk-progress.vue';
-import RkPage from './rk-page.vue';
-import RkDate from './rk-date.vue';
-import RkPanel from './rk-panel.vue';
-import RkSidebox from './rk-sidebox.vue';
-import RkEcharts from './rk-echarts.vue';
-import noty from './noty';
-
-const components: any = {
-  RkHeader, RkFooter, RkProgress, RkDate, RkPanel, RkEcharts, RkPage, 
RkSidebox, RkFooterTime,
-};
-const componentsName: string[] = Object.keys(components);
-export default {install: (vue: any) => {
-  componentsName.forEach((i) => {
-    vue.component(i, components[i]);
-  });
-  vue.use(noty);
-}};
+export { comparisonStore };
diff --git a/src/store/modules/dashboard/fragments/database.ts 
b/src/store/modules/dashboard/fragments/database.ts
index 8d25693..d12275f 100644
--- a/src/store/modules/dashboard/fragments/database.ts
+++ b/src/store/modules/dashboard/fragments/database.ts
@@ -17,7 +17,7 @@
 
 
 export const databaseResponseTime =  {
-  variable: ['$duration: Duration!'],
+  variable: ['$databaseId: ID!', '$duration: Duration!'],
   fragment: `
   databaseResponseTime: getLinearIntValues(metric: {
     name: "database_access_resp_time"
@@ -51,6 +51,46 @@ export const databaseSLA =  {
     }
   }`,
 };
+export const databaseP99 =  {
+  variable: ['$databaseId: ID!', '$duration: Duration!'],
+  fragment: `
+  databaseP99: getLinearIntValues(metric: {
+    name: "database_access_p99"
+    id: $databaseId
+  }, duration: $duration) { values { value } }`,
+};
+export const databaseP95 =  {
+  variable: ['$databaseId: ID!', '$duration: Duration!'],
+  fragment: `
+  databaseP99: getLinearIntValues(metric: {
+    name: "database_access_p95"
+    id: $databaseId
+  }, duration: $duration) { values { value } }`,
+};
+export const databaseP90 =  {
+  variable: ['$databaseId: ID!', '$duration: Duration!'],
+  fragment: `
+  databaseP99: getLinearIntValues(metric: {
+    name: "database_access_p90"
+    id: $databaseId
+  }, duration: $duration) { values { value } }`,
+};
+export const databaseP75 =  {
+  variable: ['$databaseId: ID!', '$duration: Duration!'],
+  fragment: `
+  databaseP99: getLinearIntValues(metric: {
+    name: "database_access_p75"
+    id: $databaseId
+  }, duration: $duration) { values { value } }`,
+};
+export const databaseP50 =  {
+  variable: ['$databaseId: ID!', '$duration: Duration!'],
+  fragment: `
+  databaseP99: getLinearIntValues(metric: {
+    name: "database_access_p50"
+    id: $databaseId
+  }, duration: $duration) { values { value } }`,
+};
 export const databasePercent =  {
   variable: ['$databaseId: ID!', '$duration: Duration!'],
   fragment: `
diff --git a/src/store/modules/dashboard/modules/dashboard-data.ts 
b/src/store/modules/dashboard/modules/dashboard-data.ts
index be0d769..7925ca4 100644
--- a/src/store/modules/dashboard/modules/dashboard-data.ts
+++ b/src/store/modules/dashboard/modules/dashboard-data.ts
@@ -19,6 +19,7 @@ import { ActionTree, MutationTree, Commit, Dispatch } from 
'vuex';
 import { CompsTree } from '@/types/dashboard';
 import dashboardLayout from './dashboard-data-layout';
 import dashboardQuery from './dashboard-data-query';
+import { queryChartData } from '@/utils/queryChartData';
 
 export interface State {
   current: number;
@@ -29,76 +30,7 @@ export interface State {
 
 const initState: State = {
   ...dashboardLayout.state,
-  data: {
-    service: [
-      // global
-      {
-        o: 'Global', d: 'globalHeatmap', c: 'ChartHeatmap', t: 'Global 
Heatmap', w: 3, h: 250,
-      }, {
-        o: 'Global', d: 'globalPercent', c: 'ChartLine', t: 'Global Percent 
Response', w: 3, h: 250,
-      }, {
-        o: 'Global', d: 'globalBrief', c: 'ChartBrief', t: 'Global Brief', w: 
3, h: 250,
-      }, {
-        o: 'Global', d: 'globalThroughput', c: 'ChartTrace', t: 'Global Top 
Throughput', w: 3, h: 250,
-      }, {
-        o: 'Global', d: 'globalSlow', c: 'ChartSlow', t: 'Global Top Slow 
Endpoint', w: 3, h: 250,
-      },
-      // service
-      { o: 'Service', d: 'serviceResponseTime', c: 'ChartNum', t: 'Service Avg 
ResponseTime', w: 3, h: 250 },
-      { o: 'Service', d: 'serviceThroughput', c: 'ChartNum', t: 'Service Avg 
Throughput', w: 3, h: 250 },
-      { o: 'Service', d: 'serviceSLA', c: 'ChartNum', t: 'Service Avg SLA', w: 
3, h: 250 },
-      { o: 'Service', d: 'serviceResponseTime', c: 'ChartLine', t: 'Service 
ResponseTime', w: 3, h: 250 },
-      { o: 'Service', d: 'serviceThroughput', c: 'ChartLine', t: 'Service 
Throughput', w: 3, h: 250 },
-      { o: 'Service', d: 'serviceSLA', c: 'ChartBar', t: 'Service SLA', w: 3, 
h: 250 },
-      { o: 'Service', d: 'serviceInstanceThroughput', c: 'ChartTrace', t: 
'Running ServiceInstance', w: 3, h: 250 },
-      { o: 'Service', d: 'servicePercent', c: 'ChartLine', t: 'Service Percent 
Response', w: 3, h: 250 },
-      { o: 'Service', d: 'serviceSlowEndpoint', c: 'ChartSlow', t: 'Service 
Slow Endpoint', w: 3, h: 250 },
-      // Endpoint
-      { o: 'ServiceEndpoint', d: 'endpointResponseTime', c: 'ChartNum', t: 
'Endpoint Avg ResponseTime', w: 3, h: 250 },
-      { o: 'ServiceEndpoint', d: 'endpointThroughput', c: 'ChartNum', t: 
'Endpoint Avg Throughput', w: 3, h: 250 },
-      { o: 'ServiceEndpoint', d: 'endpointSLA', c: 'ChartNum', t: 'Endpoint 
Avg SLA', w: 3, h: 250 },
-      { o: 'ServiceEndpoint', d: 'endpointResponseTime', c: 'ChartLine', t: 
'Endpoint ResponseTime', w: 3, h: 250 },
-      { o: 'ServiceEndpoint', d: 'endpointThroughput', c: 'ChartLine', t: 
'Endpoint Throughput', w: 3, h: 250 },
-      { o: 'ServiceEndpoint', d: 'endpointSLA', c: 'ChartBar', t: 'Endpoint 
SLA', w: 3, h: 250 },
-      { o: 'ServiceEndpoint', d: 'endpointPercent', c: 'ChartLine', t: 
'Endpoint Percent Response', w: 3, h: 250 },
-      { o: 'ServiceEndpoint', d: 'endpointTraces', c: 'ChartSlow', t: 
'Endpoint Slow', w: 3, h: 250 },
-      { o: 'ServiceEndpoint', d: 'endpointTopology', c: 'ChartSankey', t: 
'Dependency Map', w: 3, h: 250 },
-      // instance
-      { o: 'ServiceInstance', d: 'globalBrief', c: 'ChartInstance', t: 
'Instance Info', w: 3, h: 250 },
-      { o: 'ServiceInstance', d: 'instanceResponseTime', c: 'ChartNum', t: 
'Instance Avg ResponseTime', w: 3, h: 250 },
-      { o: 'ServiceInstance', d: 'instanceThroughput', c: 'ChartNum', t: 
'Instance Avg Throughput', w: 3, h: 250 },
-      { o: 'ServiceInstance', d: 'instanceSLA', c: 'ChartNum', t: 'Instance 
Avg SLA', w: 3, h: 250 },
-      { o: 'ServiceInstance', d: 'instanceResponseTime', c: 'ChartLine', t: 
'Instance ResponseTime', w: 3, h: 250 },
-      { o: 'ServiceInstance', d: 'instanceThroughput', c: 'ChartLine', t: 
'Instance Throughput', w: 3, h: 250 },
-      { o: 'ServiceInstance', d: 'instanceSLA', c: 'ChartLine', t: 'Instance 
SLA', w: 3, h: 250 },
-      { o: 'ServiceInstance', d: 'instanceHeap', c: 'ChartLine', t: 'JVM Heap 
(MB)', w: 3, h: 250 },
-      { o: 'ServiceInstance', d: 'instanceNonheap', c: 'ChartLine', t: 'JVM 
Non-Heap (MB)', w: 3, h: 250 },
-      { o: 'ServiceInstance', d: 'instanceGC', c: 'ChartLine', t: 'JVM GC 
(ms)', w: 3, h: 250 },
-      { o: 'ServiceInstance', d: 'instanceGCCount', c: 'ChartCount', t: 'JVM 
GC Count', w: 3, h: 250 },
-      { o: 'ServiceInstance', d: 'instanceCPU', c: 'ChartLine', t: 'JVM CPU 
(%)', w: 3, h: 250 },
-      { o: 'ServiceInstance', d: 'instanceClrCPU', c: 'ChartLine', t: 'CLR CPU 
(%)', w: 3, h: 250 },
-      { o: 'ServiceInstance', d: 'instanceClrGC', c: 'ChartLine', t: 'CLR GC 
(Count)', w: 3, h: 250 },
-      { o: 'ServiceInstance', d: 'instanceClrHeap', c: 'ChartLine', t: 'CLR 
HeapMemory (MB)', w: 3, h: 250 },
-    ],
-    proxy: [],
-    database: [
-        // global
-        { o: 'Global', d: 'globalHeatmap', c: 'ChartHeatmap', t: 'Global 
Heatmap', w: 3, h: 250 },
-        { o: 'Global', d: 'globalPercent', c: 'ChartLine', t: 'Global Percent 
Response', w: 3, h: 250 },
-        { o: 'Global', d: 'globalBrief', c: 'ChartBrief', t: 'Global Brief', 
w: 3, h: 250 },
-        { o: 'Global', d: 'globalThroughput', c: 'ChartTrace', t: 'Global Top 
Throughput', w: 3, h: 250 },
-        { o: 'Global', d: 'globalSlow', c: 'ChartSlow', t: 'Global Top Slow 
Endpoint', w: 3, h: 250 },
-        // database
-        { o: 'Database', d: 'databaseResponseTime', c: 'ChartNum', t: 
'Database Avg ResponseTime', w: 3, h: 250 },
-        { o: 'Database', d: 'databaseThroughput', c: 'ChartNum', t: 'Database 
Avg Throughput', w: 3, h: 250 },
-        { o: 'Database', d: 'databaseSLA', c: 'ChartNum', t: 'Database Avg 
SLA', w: 3, h: 250 },
-        { o: 'Database', d: 'databaseResponseTime', c: 'ChartLine', t: 
'Database ResponseTime', w: 3, h: 250 },
-        { o: 'Database', d: 'databaseThroughput', c: 'ChartLine', t: 'Database 
Throughput', w: 3, h: 250 },
-        { o: 'Database', d: 'databaseSLA', c: 'ChartBar', t: 'Database SLA', 
w: 3, h: 250 },
-        { o: 'Database', d: 'databasePercent', c: 'ChartLine', t: 'Database 
Percent', w: 3, h: 250 },
-        { o: 'Database', d: 'databaseTopNRecords', c: 'ChartSlow', t: 
'Database TopN Records', w: 3, h: 250 },
-    ],
-  },
+  data: queryChartData,
 };
 
 // mutations
diff --git a/src/store/mutation-types.ts b/src/store/mutation-types.ts
index 1a4c6d0..79a48c4 100644
--- a/src/store/mutation-types.ts
+++ b/src/store/mutation-types.ts
@@ -79,3 +79,14 @@ 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';
+
+// comparison
+export const SET_CHARTVAL = 'SET_CHARTVAL';
+export const UPDATE_CONFIG = 'UPDATE_CONFIG';
+export const CLEAR_CHART_VAL = 'CLEAR_CHART_VAL';
+export const SELECT_TYPE_SERVICES = 'SELECT_TYPE_SERVICES';
+export const SELECT_TYPE_INSTANCE = 'SELECT_TYPE_INSTANCE';
+export const SET_ISPREVIOUS = 'SET_ISPREVIOUS';
+export const SELECT_TYPE_DATABASE = 'SELECT_TYPE_DATABASE';
+export const SET_METRICSOURCE = 'SET_METRICSOURCE';
+export const SET_CONFIG = 'SET_CONFIG';
diff --git a/src/types/comparison.d.ts b/src/types/comparison.d.ts
new file mode 100644
index 0000000..cf68c9a
--- /dev/null
+++ b/src/types/comparison.d.ts
@@ -0,0 +1,52 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the 'License'); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an 'AS IS' BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+export type IOption = {
+  key: number | string;
+  label: string;
+}
+export interface ICurrentOptions {
+  preService: IOption;
+  preType: IOption;
+  preObject: IOption;
+  preMetrics: IOption;
+  nextService: IOption;
+  nextType: IOption;
+  nextObject: IOption;
+  nextMetrics: IOption;
+}
+export interface DataSourceType {
+  preServiceSource: IOption[];
+  preTypeSource: IOption[];
+  preObjectSource: IOption[];
+  preMetricsSource: IOption[];
+  nextServiceSource: IOption[];
+  nextTypeSource: IOption[];
+  nextObjectSource: IOption[];
+  nextMetricsSource: IOption[];
+}
+export interface ISelectConfig {
+  option: IOption;
+  type: string;
+  duration: string
+}
+
+export interface MetricsType {
+  Service: IOption[];
+  ServiceEndpoint: IOption[];
+  ServiceInstance: IOption[];
+  Database: IOption[];
+}
diff --git a/src/utils/queryChartData.ts b/src/utils/queryChartData.ts
new file mode 100644
index 0000000..c430001
--- /dev/null
+++ b/src/utils/queryChartData.ts
@@ -0,0 +1,87 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+export const queryChartData = {
+  service: [
+    // global
+    {
+      o: 'Global', d: 'globalHeatmap', c: 'ChartHeatmap', t: 'Global Heatmap', 
w: 3, h: 250,
+    }, {
+      o: 'Global', d: 'globalPercent', c: 'ChartLine', t: 'Global Percent 
Response', w: 3, h: 250,
+    }, {
+      o: 'Global', d: 'globalBrief', c: 'ChartBrief', t: 'Global Brief', w: 3, 
h: 250,
+    }, {
+      o: 'Global', d: 'globalThroughput', c: 'ChartTrace', t: 'Global Top 
Throughput', w: 3, h: 250,
+    }, {
+      o: 'Global', d: 'globalSlow', c: 'ChartSlow', t: 'Global Top Slow 
Endpoint', w: 3, h: 250,
+    },
+    // service
+    { o: 'Service', d: 'serviceResponseTime', c: 'ChartNum', t: 'Service Avg 
ResponseTime', w: 3, h: 250 },
+    { o: 'Service', d: 'serviceThroughput', c: 'ChartNum', t: 'Service Avg 
Throughput', w: 3, h: 250 },
+    { o: 'Service', d: 'serviceSLA', c: 'ChartNum', t: 'Service Avg SLA', w: 
3, h: 250 },
+    { o: 'Service', d: 'serviceResponseTime', c: 'ChartLine', t: 'Service 
ResponseTime', w: 3, h: 250 },
+    { o: 'Service', d: 'serviceThroughput', c: 'ChartLine', t: 'Service 
Throughput', w: 3, h: 250 },
+    { o: 'Service', d: 'serviceSLA', c: 'ChartBar', t: 'Service SLA', w: 3, h: 
250 },
+    { o: 'Service', d: 'serviceInstanceThroughput', c: 'ChartTrace', t: 
'Running ServiceInstance', w: 3, h: 250 },
+    { o: 'Service', d: 'servicePercent', c: 'ChartLine', t: 'Service Percent 
Response', w: 3, h: 250 },
+    { o: 'Service', d: 'serviceSlowEndpoint', c: 'ChartSlow', t: 'Service Slow 
Endpoint', w: 3, h: 250 },
+    // Endpoint
+    { o: 'ServiceEndpoint', d: 'endpointResponseTime', c: 'ChartNum', t: 
'Endpoint Avg ResponseTime', w: 3, h: 250 },
+    { o: 'ServiceEndpoint', d: 'endpointThroughput', c: 'ChartNum', t: 
'Endpoint Avg Throughput', w: 3, h: 250 },
+    { o: 'ServiceEndpoint', d: 'endpointSLA', c: 'ChartNum', t: 'Endpoint Avg 
SLA', w: 3, h: 250 },
+    { o: 'ServiceEndpoint', d: 'endpointResponseTime', c: 'ChartLine', t: 
'Endpoint ResponseTime', w: 3, h: 250 },
+    { o: 'ServiceEndpoint', d: 'endpointThroughput', c: 'ChartLine', t: 
'Endpoint Throughput', w: 3, h: 250 },
+    { o: 'ServiceEndpoint', d: 'endpointSLA', c: 'ChartBar', t: 'Endpoint 
SLA', w: 3, h: 250 },
+    { o: 'ServiceEndpoint', d: 'endpointPercent', c: 'ChartLine', t: 'Endpoint 
Percent Response', w: 3, h: 250 },
+    { o: 'ServiceEndpoint', d: 'endpointTraces', c: 'ChartSlow', t: 'Endpoint 
Slow', w: 3, h: 250 },
+    { o: 'ServiceEndpoint', d: 'endpointTopology', c: 'ChartSankey', t: 
'Dependency Map', w: 3, h: 250 },
+    // instance
+    { o: 'ServiceInstance', d: 'globalBrief', c: 'ChartInstance', t: 'Instance 
Info', w: 3, h: 250 },
+    { o: 'ServiceInstance', d: 'instanceResponseTime', c: 'ChartNum', t: 
'Instance Avg ResponseTime', w: 3, h: 250 },
+    { o: 'ServiceInstance', d: 'instanceThroughput', c: 'ChartNum', t: 
'Instance Avg Throughput', w: 3, h: 250 },
+    { o: 'ServiceInstance', d: 'instanceSLA', c: 'ChartNum', t: 'Instance Avg 
SLA', w: 3, h: 250 },
+    { o: 'ServiceInstance', d: 'instanceResponseTime', c: 'ChartLine', t: 
'Instance ResponseTime', w: 3, h: 250 },
+    { o: 'ServiceInstance', d: 'instanceThroughput', c: 'ChartLine', t: 
'Instance Throughput', w: 3, h: 250 },
+    { o: 'ServiceInstance', d: 'instanceSLA', c: 'ChartLine', t: 'Instance 
SLA', w: 3, h: 250 },
+    { o: 'ServiceInstance', d: 'instanceHeap', c: 'ChartLine', t: 'JVM Heap 
(MB)', w: 3, h: 250 },
+    { o: 'ServiceInstance', d: 'instanceNonheap', c: 'ChartLine', t: 'JVM 
Non-Heap (MB)', w: 3, h: 250 },
+    { o: 'ServiceInstance', d: 'instanceGC', c: 'ChartLine', t: 'JVM GC (ms)', 
w: 3, h: 250 },
+    { o: 'ServiceInstance', d: 'instanceGCCount', c: 'ChartCount', t: 'JVM GC 
Count', w: 3, h: 250 },
+    { o: 'ServiceInstance', d: 'instanceCPU', c: 'ChartLine', t: 'JVM CPU 
(%)', w: 3, h: 250 },
+    { o: 'ServiceInstance', d: 'instanceClrCPU', c: 'ChartLine', t: 'CLR CPU 
(%)', w: 3, h: 250 },
+    { o: 'ServiceInstance', d: 'instanceClrGC', c: 'ChartLine', t: 'CLR GC 
(Count)', w: 3, h: 250 },
+    { o: 'ServiceInstance', d: 'instanceClrHeap', c: 'ChartLine', t: 'CLR 
HeapMemory (MB)', w: 3, h: 250 },
+  ],
+  proxy: [],
+  database: [
+      // global
+      { o: 'Global', d: 'globalHeatmap', c: 'ChartHeatmap', t: 'Global 
Heatmap', w: 3, h: 250 },
+      { o: 'Global', d: 'globalPercent', c: 'ChartLine', t: 'Global Percent 
Response', w: 3, h: 250 },
+      { o: 'Global', d: 'globalBrief', c: 'ChartBrief', t: 'Global Brief', w: 
3, h: 250 },
+      { o: 'Global', d: 'globalThroughput', c: 'ChartTrace', t: 'Global Top 
Throughput', w: 3, h: 250 },
+      { o: 'Global', d: 'globalSlow', c: 'ChartSlow', t: 'Global Top Slow 
Endpoint', w: 3, h: 250 },
+      // database
+      { o: 'Database', d: 'databaseResponseTime', c: 'ChartNum', t: 'Database 
Avg ResponseTime', w: 3, h: 250 },
+      { o: 'Database', d: 'databaseThroughput', c: 'ChartNum', t: 'Database 
Avg Throughput', w: 3, h: 250 },
+      { o: 'Database', d: 'databaseSLA', c: 'ChartNum', t: 'Database Avg SLA', 
w: 3, h: 250 },
+      { o: 'Database', d: 'databaseResponseTime', c: 'ChartLine', t: 'Database 
ResponseTime', w: 3, h: 250 },
+      { o: 'Database', d: 'databaseThroughput', c: 'ChartLine', t: 'Database 
Throughput', w: 3, h: 250 },
+      { o: 'Database', d: 'databaseSLA', c: 'ChartBar', t: 'Database SLA', w: 
3, h: 250 },
+      { o: 'Database', d: 'databasePercent', c: 'ChartLine', t: 'Database 
Percent', w: 3, h: 250 },
+      { o: 'Database', d: 'databaseTopNRecords', c: 'ChartSlow', t: 'Database 
TopN Records', w: 3, h: 250 },
+  ],
+};
diff --git a/src/views/components/comparison/chart-line.vue 
b/src/views/components/comparison/chart-line.vue
new file mode 100644
index 0000000..a6cb99b
--- /dev/null
+++ b/src/views/components/comparison/chart-line.vue
@@ -0,0 +1,104 @@
+/**
+ * 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>
+  <RkEcharts ref="chart" :option="option" :autoResize="true"/>
+</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 intervalTime!: any;
+  public resize() {
+    const chart: any = this.$refs.chart;
+    chart.myChart.resize();
+  }
+  get option() {
+    const temp: any = [];
+    const keys = Object.keys(this.data || {}).filter((i: any) => 
Array.isArray(this.data[i]) && this.data[i].length);
+    keys.forEach((i: any, index: number) => {
+      const serie: any = {
+          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',
+          },
+      };
+      temp.push(serie);
+    });
+    const color: string[] = [
+      '#6be6c1',
+      '#626c91',
+      '#a0a7e6',
+      '#96dee8',
+      '#3f96e3',
+    ];
+
+    return {
+      color,
+      tooltip: {
+        trigger: 'axis',
+        backgroundColor: 'rgb(50,50,50)',
+        textStyle: {
+          fontSize: 13,
+        },
+      },
+      legend: {
+        show: true,
+        icon: 'circle',
+        top: 0,
+        left: 0,
+        itemWidth: 12,
+      },
+      grid: {
+        top: keys.length === 1 ? 15 : 55,
+        left: 0,
+        right: 10,
+        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/components/index.ts 
b/src/views/components/comparison/comparison-charts.vue
similarity index 52%
copy from src/components/index.ts
copy to src/views/components/comparison/comparison-charts.vue
index 2b921e0..def4035 100644
--- a/src/components/index.ts
+++ b/src/views/components/comparison/comparison-charts.vue
@@ -15,24 +15,31 @@
  * limitations under the License.
  */
 
-import RkHeader from './rk-header.vue';
-import RkFooter from './rk-footer.vue';
-import RkFooterTime from './rk-footer-time.vue';
-import RkProgress from './rk-progress.vue';
-import RkPage from './rk-page.vue';
-import RkDate from './rk-date.vue';
-import RkPanel from './rk-panel.vue';
-import RkSidebox from './rk-sidebox.vue';
-import RkEcharts from './rk-echarts.vue';
-import noty from './noty';
+<template>
+  <div class="rk-comparison-charts">
+    <ChartLine :intervalTime="intervalTime" :data="chartSource" />
+  </div>
+</template>
 
-const components: any = {
-  RkHeader, RkFooter, RkProgress, RkDate, RkPanel, RkEcharts, RkPage, 
RkSidebox, RkFooterTime,
-};
-const componentsName: string[] = Object.keys(components);
-export default {install: (vue: any) => {
-  componentsName.forEach((i) => {
-    vue.component(i, components[i]);
-  });
-  vue.use(noty);
-}};
+<script lang="ts">
+  import { Component, Vue, Prop } from 'vue-property-decorator';
+  import { State, Action, Getter } from 'vuex-class';
+
+  import ChartLine from './chart-line.vue';
+
+  @Component({
+    components: { ChartLine },
+  })
+  export default class ComparisonCharts extends Vue {
+    @Prop() private chartSource: any;
+    @Getter('intervalTime') private intervalTime: any;
+  }
+</script>
+
+<style lang="scss">
+  .rk-comparison-charts {
+    flex-grow: 5;
+    height: 100%;
+    padding: 20px;
+  }
+</style>
diff --git a/src/views/components/comparison/comparison-config.vue 
b/src/views/components/comparison/comparison-config.vue
new file mode 100644
index 0000000..e92bc52
--- /dev/null
+++ b/src/views/components/comparison/comparison-config.vue
@@ -0,0 +1,172 @@
+/**
+ * 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-comparison-config" v-if="currentOptions">
+    <h4>{{this.$t("previousService")}}</h4>
+    <div v-if="currentOptions.preType.key !== 'Database'">
+      <label>{{this.$t("service")}}</label>
+      <RkSelect
+        class="mb-5"
+        :current="currentOptions.preService"
+        :data="optSource.preServiceSource"
+        @onChoose="(item) => changOption(item, changeType.PreService)"
+      />
+    </div>
+    <label>{{this.$t("type")}}</label>
+    <RkSelect
+      class="mb-5"
+      :current="currentOptions.preType"
+      :data="optSource.preTypeSource"
+      @onChoose="(item) => changOption(item, changeType.PreType)"
+    />
+    <div v-if="currentOptions.preType.key !== 'Service'">
+      <label>{{this.$t("object")}}</label>
+      <RkSelect
+        class="mb-5"
+        :current="currentOptions.preObject"
+        :data="optSource.preObjectSource"
+        @onChoose="(item) => changOption(item, changeType.PreObject)"
+      />
+    </div>
+    <label>{{this.$t("metrics")}}</label>
+    <RkSelect
+      class="mb-5"
+      :current="currentOptions.preMetrics"
+      :data="optSource.preMetricsSource"
+      @onChoose="(item) => changOption(item, changeType.PreMetrics)"
+    />
+    <h4>{{this.$t("nextService")}}</h4>
+    <div v-if="currentOptions.nextType.key !== 'Database'">
+      <label>{{this.$t("service")}}</label>
+      <RkSelect
+        class="mb-5"
+        :current="currentOptions.nextService"
+        :data="optSource.nextServiceSource"
+        @onChoose="(item) => changOption(item, changeType.NextService)"
+      />
+    </div>
+    <label>{{this.$t("type")}}</label>
+    <RkSelect
+      class="mb-5"
+      :current="currentOptions.nextType"
+      :data="optSource.nextTypeSource"
+      @onChoose="(item) => changOption(item, changeType.NextType)"
+    />
+    <div v-if="currentOptions.nextType.key !== 'Service'">
+      <label>{{this.$t("object")}}</label>
+      <RkSelect
+        class="mb-5"
+        :current="currentOptions.nextObject"
+        :data="optSource.nextObjectSource"
+        @onChoose="(item) => changOption(item, changeType.NextObject)"
+      />
+    </div>
+    <label>{{this.$t("metrics")}}</label>
+    <RkSelect
+      class="mb-5"
+      :current="currentOptions.nextMetrics"
+      :data="optSource.nextMetricsSource"
+      @onChoose="(item) => changOption(item, changeType.NextMetrics)"
+    />
+    <div class="mb-5 query-data">
+      <a @click="updateChart">{{this.$t("queryData")}}</a>
+      <a @click="resetService">{{this.$t("reset")}}</a>
+    </div>
+  </div>
+</template>
+<script lang="ts">
+  import { Component, Vue, Prop } from 'vue-property-decorator';
+  import { State, Action, Getter } from 'vuex-class';
+  import { IOption } from '@/types/comparison';
+
+  @Component
+  export default class ComparisonConfig extends Vue {
+    @Prop() private currentOptions: any;
+    @Prop() private optSource: any;
+    @Getter('durationTime') private durationTime: any;
+    @Getter('comparisonStore/ChangeType') private changeType: any;
+
+    private changOption(item: IOption, key: string) {
+      this.$store.dispatch('comparisonStore/SELECT_CONFIG', {
+        duration: this.durationTime,
+        type: key,
+        option: item,
+      });
+    }
+
+    private updateChart() {
+      this.$store.dispatch('comparisonStore/RENDER_CHART', this.durationTime);
+    }
+
+    private resetService() {
+      this.$store.commit('comparisonStore/SET_ISPREVIOUS', 'init');
+      this.$store.dispatch('comparisonStore/GET_SERVICES', {duration: 
this.durationTime});
+    }
+  }
+</script>
+
+<style lang='scss'>
+  .rk-comparison-config {
+    width: 380px;
+    height: 100%;
+    padding: 20px;
+    border: 1px solid #ddd;
+    overflow: auto;
+    h4 {
+      margin: 0;
+    }
+    h4:not(:first-child) {
+      margin-top: 50px;
+    }
+    label {
+      display: inline-block;
+      margin: 10px 0;
+      font-weight: bold;
+    }
+    .reload {
+      background: #fff;
+      color: #333;
+      position: absolute;
+      top: 3px;
+    }
+    .reload-icon {
+      position: relative;
+      display: inline-block;
+      width: 40px;
+      height: 20px;
+    }
+    a {
+      display: inline-block;
+      width: 78px;
+      height: 40px;
+      line-height: 40px;
+      text-align: center;
+      font-size: 14px;
+      background: #448dfe;
+      color: #fff;
+      border-radius: 4px;
+    }
+    .query-data {
+      margin-top: 70px;
+      :first-child {
+        border-right: 1px solid #fff;
+        width: 260px;
+      }
+    }
+  }
+</style>
diff --git a/src/components/index.ts b/src/views/components/comparison/index.ts
similarity index 52%
copy from src/components/index.ts
copy to src/views/components/comparison/index.ts
index 2b921e0..4b86b62 100644
--- a/src/components/index.ts
+++ b/src/views/components/comparison/index.ts
@@ -14,25 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+import ConparisonConfig from './comparison-config.vue';
+import ConparisonCharts from './comparison-charts.vue';
 
-import RkHeader from './rk-header.vue';
-import RkFooter from './rk-footer.vue';
-import RkFooterTime from './rk-footer-time.vue';
-import RkProgress from './rk-progress.vue';
-import RkPage from './rk-page.vue';
-import RkDate from './rk-date.vue';
-import RkPanel from './rk-panel.vue';
-import RkSidebox from './rk-sidebox.vue';
-import RkEcharts from './rk-echarts.vue';
-import noty from './noty';
-
-const components: any = {
-  RkHeader, RkFooter, RkProgress, RkDate, RkPanel, RkEcharts, RkPage, 
RkSidebox, RkFooterTime,
-};
-const componentsName: string[] = Object.keys(components);
-export default {install: (vue: any) => {
-  componentsName.forEach((i) => {
-    vue.component(i, components[i]);
-  });
-  vue.use(noty);
-}};
+export { ConparisonConfig, ConparisonCharts };
diff --git a/src/views/containers/comparison.vue 
b/src/views/containers/comparison.vue
new file mode 100644
index 0000000..fc4c9d2
--- /dev/null
+++ b/src/views/containers/comparison.vue
@@ -0,0 +1,69 @@
+/**
+ * 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-comparison flex-h">
+    <ConparisonCharts :chartSource="comparison.chartSource" />
+    <ConparisonConfig :currentOptions="comparison.currentOptions" 
:optSource="comparison.dataSource" />
+  </div>
+</template>
+
+<script lang="ts">
+  import { Component, Vue } from 'vue-property-decorator';
+  import { State, Getter, Mutation } from 'vuex-class';
+
+  import { comparisonStore } from '@/store/modules/comparison';
+  import { ConparisonConfig, ConparisonCharts } from 
'../components/comparison';
+  import { DurationTime } from '@/types/global';
+  import compareObj from '@/utils/comparison';
+
+  @Component({
+    components: {
+      ConparisonConfig,
+      ConparisonCharts,
+    },
+  })
+  export default class Comparison extends Vue {
+    @State('comparisonStore') private comparison: any;
+    @Getter('durationTime') private durationTime: any;
+    @Mutation('SET_EVENTS') private SET_EVENTS: any;
+    @Mutation('comparisonStore/SET_ISPREVIOUS') private SET_ISPREVIOUS: any;
+
+    private beforeCreate() {
+      this.$store.registerModule('comparisonStore', comparisonStore);
+    }
+
+    private beforeMount() {
+      this.$store.dispatch('comparisonStore/GET_SERVICES', {duration: 
this.durationTime});
+      this.SET_EVENTS([this.reloadConfig]);
+    }
+
+    private reloadConfig() {
+      this.$store.dispatch('comparisonStore/RENDER_CHART', this.durationTime);
+    }
+
+    private beforeDestroy() {
+      this.$store.unregisterModule('comparisonStore');
+    }
+  }
+</script>
+
+<style lang="scss">
+  .rk-comparison {
+    height: 100%;
+  }
+</style>

Reply via email to