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 8d54cb4 feat: multiple metrics compare (#195)
8d54cb4 is described below
commit 8d54cb46919ca20069e727f2e86963d27f07428f
Author: Fine <[email protected]>
AuthorDate: Wed Nov 13 21:19:24 2019 +0800
feat: multiple metrics compare (#195)
* feat: multiple select component
* feat: multiple select component
* feat: query multiple value
* feat: update style
* feat: update config
* feat: add color
---
src/components/rk-select.vue | 59 ++++++++++++++++---
src/store/modules/comparison/comparison-const.ts | 4 +-
src/store/modules/comparison/comparison-store.ts | 67 ++++++++++++++--------
src/types/comparison.d.ts | 4 +-
src/views/components/comparison/chart-line.vue | 8 ++-
.../components/comparison/comparison-charts.vue | 23 +++++++-
.../components/comparison/comparison-config.vue | 30 +++++-----
.../components/dashboard/charts/chart-slow.vue | 2 +-
src/views/containers/comparison.vue | 1 +
9 files changed, 145 insertions(+), 53 deletions(-)
diff --git a/src/components/rk-select.vue b/src/components/rk-select.vue
index fed32ea..6d67952 100644
--- a/src/components/rk-select.vue
+++ b/src/components/rk-select.vue
@@ -19,8 +19,13 @@
<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 v-if="Array.isArray(current)">
+ <span class="selected" v-for="item in current" :key="item.key">
+ <span>{{item.label}}</span>
+ <span class="remove-icon" @click="removeSelected(item)">×</span>
+ </span>
+ </div>
+ <div class="ell" v-else 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>
@@ -34,7 +39,7 @@
</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 class="rk-opt ell" @click="handleSelect(i)"
:class="{'select-disabled': selectedOpt.includes(i.key)}" v-for="i in
filterData" :key="i.key">{{i.label}}</div>
</div>
</div>
</div>
@@ -42,37 +47,69 @@
<script lang="ts">
import { Vue, Component, Prop } from 'vue-property-decorator';
+const Multiple = 'multiple';
@Component
export default class RkSelect extends Vue {
+ @Prop() public mode: any;
@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);
}
+
+ get selectedOpt() {
+ return this.mode === Multiple ? this.current.map((item: any) => item.key)
: [this.current.key];
+ }
+
public handleOpen() {
this.visible = true;
}
+
public handleSelect(i: any) {
+ const selected = this.mode === Multiple ? this.current.map((item: any) =>
item.key) : [this.current.key];
+ if (selected.includes(i.key)) {
+ return;
+ }
this.$emit('onChoose', i);
this.visible = false;
}
+
+ private removeSelected(item: any) {
+ if (this.mode === Multiple) {
+ this.$emit('onChoose', item);
+ }
+ }
}
</script>
<style lang="scss" scoped>
.rk-bar-select {
position: relative;
- height: 40px;
+ min-height: 40px;
justify-content: space-between;
border: 1px solid #ddd;
background: #fff;
border-radius: 3px;
.sm{ line-height: 12px;}
.icon { flex-shrink: 0};
+ .selected {
+ display: inline-block;
+ padding: 5px;
+ border-radius: 3px;
+ margin: 3px;
+ overflow: hidden;
+ color: rgba(0, 0, 0, 0.65);
+ background-color: #fafafa;
+ border: 1px solid #e8e8e8;
+ }
+ .remove-icon {
+ display: inline-block;
+ margin-left: 5px;
+ cursor: pointer;
+ }
}
.rk-bar-i-text{
width: 100%;
@@ -81,10 +118,11 @@ export default class RkSelect extends Vue {
height: 100%;
width: 100%;
padding: 5px 15px;
+ overflow: auto;
}
.rk-sel{
position: absolute;
- top: 39px;
+ top: 100%;
background: #fff;
box-shadow: 0 1px 6px rgba(99, 99, 99, 0.2);
border: 1px solid #ddd;
@@ -102,6 +140,13 @@ export default class RkSelect extends Vue {
}
.rk-opt{
padding: 7px 15px;
+ &.select-disabled {
+ color: rgba(0, 0, 0, 0.25);
+ cursor: not-allowed;
+ }
+ &:hover{
+ background-color: #f5f5f5;
+ }
}
.rk-sel-search{
width: calc(100% - 4px);
diff --git a/src/store/modules/comparison/comparison-const.ts
b/src/store/modules/comparison/comparison-const.ts
index f77cac2..391fc05 100644
--- a/src/store/modules/comparison/comparison-const.ts
+++ b/src/store/modules/comparison/comparison-const.ts
@@ -39,11 +39,11 @@ export const ComparisonOption: ICurrentOptions = {
preService: {key: 0, label: ''},
preType: {key: 'ServiceEndpoint', label: 'Service Endpoint'},
preObject: {key: 0, label: '/projectB/{name}'},
- preMetrics: {key: 0, label: ''},
+ preMetrics: [{key: 0, label: ''}],
nextService: {key: 0, label: ''},
nextType: {key: 'ServiceEndpoint', label: 'Service Endpoint'},
nextObject: {key: 0, label: '/projectA/{name}'},
- nextMetrics: {key: 0, label: ''},
+ nextMetrics: [{key: 0, label: ''}],
};
export const InitSource: DataSourceType = {
diff --git a/src/store/modules/comparison/comparison-store.ts
b/src/store/modules/comparison/comparison-store.ts
index ae0ba6c..e55a45b 100644
--- a/src/store/modules/comparison/comparison-store.ts
+++ b/src/store/modules/comparison/comparison-store.ts
@@ -58,24 +58,33 @@ const initState: State = {
// getters
const getters = {
queryPreValue(state: State) {
- const { currentOptions } = state;
- const preMetric = currentOptions.preMetrics.key;
- const preParam = (fragmentAll as any)[preMetric];
- if (!preParam) {
- return;
- }
+ const { preMetrics } = state.currentOptions;
+ const fragments = [];
+ let variable = null;
- return `query queryData(${preParam.variable.join(',')})
{${preParam.fragment}}`;
+ for (const metric of preMetrics) {
+ const preMetric = metric.key;
+ const preParam = (fragmentAll as any)[preMetric];
+ if (preParam) {
+ variable = preParam.variable;
+ fragments.push(preParam.fragment);
+ }
+ }
+ return `query queryData(${variable}) {${fragments.join(',')}}`;
},
queryNextValue(state: State) {
- const { currentOptions } = state;
- const nextMetric = currentOptions.nextMetrics.key;
- const nextParam = (fragmentAll as any)[nextMetric];
+ const { nextMetrics } = state.currentOptions;
+ const fragments = [];
+ let variable = null;
- if (!nextParam) {
- return;
+ for (const metric of nextMetrics) {
+ const nextParam = (fragmentAll as any)[metric.key];
+ if (nextParam) {
+ variable = nextParam.variable;
+ fragments.push(nextParam.fragment);
+ }
}
- return `query queryData(${nextParam.variable.join(',')})
{${nextParam.fragment}}`;
+ return `query queryData(${variable}) {${fragments.join(',')}}`;
},
preConfig(state: State) {
const { currentOptions } = state;
@@ -203,19 +212,19 @@ const mutations = {
state.dataSource.preObjectSource = data;
state.currentOptions.preObject = data[0];
state.dataSource.preMetricsSource = metricSource[type];
- state.currentOptions.preMetrics = metricSource[type][0];
+ 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];
+ 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],
+ preMetrics: [metricSource[type][0]],
+ nextMetrics: [metricSource[type][1]],
preType: ComparisonType[2],
nextType: ComparisonType[2],
};
@@ -254,7 +263,17 @@ const mutations = {
[types.UPDATE_CONFIG](state: any, data: ISelectConfig) {
const {type, option} = data;
- state.currentOptions[type] = option;
+ if (type === ChangeType.NextMetrics || type === ChangeType.PreMetrics) {
+ const metrics = state.currentOptions[type];
+ const item = metrics.findIndex((d: any) => d.key === option.key);
+ if (item > -1) {
+ state.currentOptions[type] = metrics.filter((d: any) => d.key !==
option.key);
+ } else {
+ state.currentOptions[type].push(option);
+ }
+ } else {
+ state.currentOptions[type] = option;
+ }
},
[types.CLEAR_CHART_VAL](state: State) {
state.chartSource = {} as any;
@@ -265,10 +284,10 @@ const mutations = {
if (isPrevious === StatusType.Pre) {
state.dataSource.preMetricsSource = metricSource[preType.key] || [];
- state.currentOptions.preMetrics = metricSource[preType.key][0];
+ state.currentOptions.preMetrics = [metricSource[preType.key][0]];
} else {
state.dataSource.nextMetricsSource = metricSource[nextType.key] || [];
- state.currentOptions.nextMetrics = metricSource[nextType.key][0];
+ state.currentOptions.nextMetrics = [metricSource[nextType.key][0]];
}
},
[types.SELECT_TYPE_INSTANCE](state: State, data: any) {
@@ -277,12 +296,12 @@ const mutations = {
if (isPrevious === StatusType.Pre) {
state.dataSource.preMetricsSource = metricSource[preType.key];
- state.currentOptions.preMetrics = metricSource[preType.key][0];
+ 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.currentOptions.nextMetrics = [metricSource[nextType.key][0]];
state.dataSource.nextObjectSource = data;
state.currentOptions.nextObject = data[0];
}
@@ -293,12 +312,12 @@ const mutations = {
if (state.isPrevious === StatusType.Next) {
state.dataSource.nextMetricsSource = metricSource[nextType.key];
- state.currentOptions.nextMetrics = metricSource[nextType.key][0];
+ 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.preMetrics = [metricSource[preType.key][0]];
state.currentOptions.preObject = data[0];
state.dataSource.preObjectSource = data;
}
diff --git a/src/types/comparison.d.ts b/src/types/comparison.d.ts
index cf68c9a..8855c75 100644
--- a/src/types/comparison.d.ts
+++ b/src/types/comparison.d.ts
@@ -22,11 +22,11 @@ export interface ICurrentOptions {
preService: IOption;
preType: IOption;
preObject: IOption;
- preMetrics: IOption;
+ preMetrics: IOption[];
nextService: IOption;
nextType: IOption;
nextObject: IOption;
- nextMetrics: IOption;
+ nextMetrics: IOption[];
}
export interface DataSourceType {
preServiceSource: IOption[];
diff --git a/src/views/components/comparison/chart-line.vue
b/src/views/components/comparison/chart-line.vue
index a6cb99b..e37d851 100644
--- a/src/views/components/comparison/chart-line.vue
+++ b/src/views/components/comparison/chart-line.vue
@@ -50,9 +50,13 @@ export default class ChartLine extends Vue {
temp.push(serie);
});
const color: string[] = [
+ '#30A4EB',
+ '#45BFC0',
+ '#FFCC55',
+ '#FF6A84',
+ '#a0a7e6',
'#6be6c1',
'#626c91',
- '#a0a7e6',
'#96dee8',
'#3f96e3',
];
@@ -67,7 +71,7 @@ export default class ChartLine extends Vue {
},
},
legend: {
- show: true,
+ show: false,
icon: 'circle',
top: 0,
left: 0,
diff --git a/src/views/components/comparison/comparison-charts.vue
b/src/views/components/comparison/comparison-charts.vue
index def4035..2fbb5e0 100644
--- a/src/views/components/comparison/comparison-charts.vue
+++ b/src/views/components/comparison/comparison-charts.vue
@@ -17,7 +17,12 @@
<template>
<div class="rk-comparison-charts">
- <ChartLine :intervalTime="intervalTime" :data="chartSource" />
+ <div class="component-item" v-for="item of Object.keys(chartSource)"
:key="item">
+ <div class="title">{{item}}</div>
+ <div class="chart-item">
+ <ChartLine :intervalTime="intervalTime" :data="{[item]:
chartSource[item]}" />
+ </div>
+ </div>
</div>
</template>
@@ -41,5 +46,21 @@
flex-grow: 5;
height: 100%;
padding: 20px;
+ overflow: auto;
+ .chart-item {
+ width: 100%;
+ height: 200px;
+ }
+ .component-item {
+ width: 100%;
+ .title {
+ height: 30px;
+ line-height: 30px;
+ margin: 10px 0;
+ padding-left: 10px;
+ background-color: rgba(196,200,225,.2);
+ color: #9da5b2;
+ }
+ }
}
</style>
diff --git a/src/views/components/comparison/comparison-config.vue
b/src/views/components/comparison/comparison-config.vue
index e92bc52..52337b0 100644
--- a/src/views/components/comparison/comparison-config.vue
+++ b/src/views/components/comparison/comparison-config.vue
@@ -18,6 +18,13 @@
<template>
<div class="rk-comparison-config" v-if="currentOptions">
<h4>{{this.$t("previousService")}}</h4>
+ <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 !== 'Database'">
<label>{{this.$t("service")}}</label>
<RkSelect
@@ -27,13 +34,6 @@
@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
@@ -46,11 +46,19 @@
<label>{{this.$t("metrics")}}</label>
<RkSelect
class="mb-5"
+ :mode="'multiple'"
:current="currentOptions.preMetrics"
:data="optSource.preMetricsSource"
@onChoose="(item) => changOption(item, changeType.PreMetrics)"
/>
<h4>{{this.$t("nextService")}}</h4>
+ <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 !== 'Database'">
<label>{{this.$t("service")}}</label>
<RkSelect
@@ -60,13 +68,6 @@
@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
@@ -79,6 +80,7 @@
<label>{{this.$t("metrics")}}</label>
<RkSelect
class="mb-5"
+ :mode="'multiple'"
:current="currentOptions.nextMetrics"
:data="optSource.nextMetricsSource"
@onChoose="(item) => changOption(item, changeType.NextMetrics)"
diff --git a/src/views/components/dashboard/charts/chart-slow.vue
b/src/views/components/dashboard/charts/chart-slow.vue
index 7a3fbb9..11d4e44 100644
--- a/src/views/components/dashboard/charts/chart-slow.vue
+++ b/src/views/components/dashboard/charts/chart-slow.vue
@@ -49,7 +49,7 @@ export default class ChartSlow extends Vue {
const temp: number[] = this.data.map((i: any) => i.value);
return Math.max.apply(null, temp);
}
- getTraceId(i: any){
+ private getTraceId(i: any) {
return i.traceIds && i.traceIds[0] ? ` - ${i.traceIds[0]}` : '';
}
private handleClick(i: any) {
diff --git a/src/views/containers/comparison.vue
b/src/views/containers/comparison.vue
index fc4c9d2..f33b611 100644
--- a/src/views/containers/comparison.vue
+++ b/src/views/containers/comparison.vue
@@ -65,5 +65,6 @@
<style lang="scss">
.rk-comparison {
height: 100%;
+ overflow: auto;
}
</style>