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>