You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@skywalking.apache.org by wu...@apache.org on 2021/04/06 00:22:00 UTC
[skywalking-rocketbot-ui] branch master updated: feat: extend table
chart (#459)
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 fa32fdb feat: extend table chart (#459)
fa32fdb is described below
commit fa32fdb0d925f3bf5568f23e5ded47e86cd2ba13
Author: Qiuxia Fan <fi...@outlook.com>
AuthorDate: Tue Apr 6 08:21:50 2021 +0800
feat: extend table chart (#459)
---
src/assets/lang/en.ts | 4 +
src/assets/lang/zh.ts | 4 +
.../components/dashboard/charts/chart-edit.vue | 250 ++++++++++++---------
.../components/dashboard/charts/chart-table.vue | 94 ++++++--
src/views/components/dashboard/dashboard-comp.vue | 4 +-
src/views/components/dashboard/dashboard-item.vue | 18 +-
6 files changed, 242 insertions(+), 132 deletions(-)
diff --git a/src/assets/lang/en.ts b/src/assets/lang/en.ts
index cafc189..645d8c1 100644
--- a/src/assets/lang/en.ts
+++ b/src/assets/lang/en.ts
@@ -201,6 +201,10 @@ const m = {
keywordsOfContentLogTips: 'Current storage of SkyWalking OAP server does not support this.',
instanceAttributes: 'Instance Attributes',
value: 'Value',
+ tableHeader: 'Header Names',
+ tableValues: 'Table Values',
+ show: 'Show',
+ hide: 'Hide',
};
export default m;
diff --git a/src/assets/lang/zh.ts b/src/assets/lang/zh.ts
index bc9c321..f222588 100644
--- a/src/assets/lang/zh.ts
+++ b/src/assets/lang/zh.ts
@@ -199,6 +199,10 @@ const m = {
keywordsOfContentLogTips: 'SkyWalking OAP服务器的当前存储不支持此操作',
instanceAttributes: '查看实例属性',
value: '数值',
+ tableHeader: '表头名称',
+ tableValues: '表值',
+ show: '展示',
+ hide: '隐藏',
};
export default m;
diff --git a/src/views/components/dashboard/charts/chart-edit.vue b/src/views/components/dashboard/charts/chart-edit.vue
index e161df1..d7bf985 100755
--- a/src/views/components/dashboard/charts/chart-edit.vue
+++ b/src/views/components/dashboard/charts/chart-edit.vue
@@ -205,7 +205,6 @@ limitations under the License. -->
>
<option :value="'DES'">{{ $t('descendOrder') }}</option>
<option :value="'ASC'">{{ $t('increaseOrder') }}</option>
- <!-- <option :value="''" v-if="isBrowser">{{ $t('defaultOrder') }}</option>-->
</select>
</div>
<div class="flex-h mb-5">
@@ -218,6 +217,27 @@ limitations under the License. -->
/>
</div>
<div class="flex-h mb-5">
+ <div class="title grey sm">{{ $t('width') }}:</div>
+ <input
+ type="number"
+ min="1"
+ max="12"
+ class="rk-chart-edit-input long"
+ :value="itemConfig.width"
+ @change="setItemConfig({ type: 'width', value: $event.target.value })"
+ />
+ </div>
+ <div class="flex-h mb-5">
+ <div class="title grey sm">{{ $t('height') }}:</div>
+ <input
+ type="number"
+ min="1"
+ class="rk-chart-edit-input long"
+ :value="itemConfig.height"
+ @change="setItemConfig({ type: 'height', value: $event.target.value })"
+ />
+ </div>
+ <div class="flex-h mb-5">
<div class="title grey sm">{{ $t('aggregation') }}:</div>
<select
class="long"
@@ -233,27 +253,34 @@ limitations under the License. -->
@change="setItemConfig({ type: 'aggregationNum', value: $event.target.value })"
/>
</div>
- <div class="flex-h mb-5">
- <div class="title grey sm">{{ $t('width') }}:</div>
+ <div class="flex-h mb-5" v-show="itemConfig.chartType === ChartTypeOptions[3].value">
+ <div class="title grey sm">{{ $t('tableHeader') }}:</div>
<input
- type="number"
- min="1"
- max="12"
+ type="text"
class="rk-chart-edit-input long"
- :value="itemConfig.width"
- @change="setItemConfig({ type: 'width', value: $event.target.value })"
+ placeholder="col-1"
+ :value="itemConfig.tableHeaderCol1"
+ @change="setItemConfig({ type: 'tableHeaderCol1', value: $event.target.value })"
/>
- </div>
- <div class="flex-h">
- <div class="title grey sm">{{ $t('height') }}:</div>
<input
- type="number"
- min="1"
+ type="text"
class="rk-chart-edit-input long"
- :value="itemConfig.height"
- @change="setItemConfig({ type: 'height', value: $event.target.value })"
+ placeholder="col-2"
+ :value="itemConfig.tableHeaderCol2"
+ @change="setItemConfig({ type: 'tableHeaderCol2', value: $event.target.value })"
/>
</div>
+ <div class="flex-h mb-5" v-show="itemConfig.chartType === ChartTypeOptions[3].value">
+ <div class="title grey sm">{{ $t('tableValues') }}:</div>
+ <select
+ class="long"
+ v-model="itemConfig.showTableValues"
+ @change="setItemConfig({ type: 'showTableValues', value: $event.target.value })"
+ >
+ <option :value="true">{{ $t('show') }}</option>
+ <option :value="false">{{ $t('hide') }}</option>
+ </select>
+ </div>
</div>
</div>
</template>
@@ -262,8 +289,7 @@ limitations under the License. -->
import Vue from 'vue';
import { State, Getter, Mutation, Action } from 'vuex-class';
import { Component, Prop, Watch } from 'vue-property-decorator';
-
- import { TopologyType, ObjectsType } from '../../../../constants/constant';
+ import { TopologyType } from '@/constants/constant';
import {
EntityType,
BrowserEntityType,
@@ -306,12 +332,20 @@ limitations under the License. -->
private isLabel = false;
private isIndependentSelector = false;
private nameMetrics = ['sortMetrics', 'readSampledRecords'];
- private pageTypes = [TopologyType.TOPOLOGY_ENDPOINT, TopologyType.TOPOLOGY_INSTANCE] as any[];
+ private pageTypes = [TopologyType.TOPOLOGY_ENDPOINT, TopologyType.TOPOLOGY_INSTANCE] as string[];
private isChartType = false;
private isReadSingleValue = false;
private created() {
this.itemConfig = this.item;
+ this.initConfig();
+ if (!this.itemConfig.independentSelector || this.pageTypes.includes(this.type)) {
+ return;
+ }
+ this.setItemServices();
+ }
+
+ private initConfig() {
this.isDatabase = this.pageTypes.includes(this.type)
? false
: this.rocketComps.tree[this.rocketComps.group].type === DASHBOARDTYPE.DATABASE
@@ -328,10 +362,6 @@ limitations under the License. -->
this.isIndependentSelector =
this.rocketComps.tree[this.rocketComps.group].type === 'metric' || this.pageTypes.includes(this.type);
this.isChartType = ['readMetricsValues', 'readLabeledMetricsValues'].includes(this.itemConfig.queryMetricType);
- if (!this.itemConfig.independentSelector || this.pageTypes.includes(this.type)) {
- return;
- }
- this.setItemServices();
}
private setItemConfig(params: { type: string; value: string }) {
@@ -353,129 +383,137 @@ limitations under the License. -->
}
}
if (params.type === 'metricName') {
- this.TYPE_METRICS({ name: params.value }).then((data: Array<{ typeOfMetrics: string }>) => {
- if (!data.length) {
- return;
- }
- if (data.length > 1) {
- const length = data.filter((d: { typeOfMetrics: string }) => d.typeOfMetrics !== MetricsType.REGULAR_VALUE)
- .length;
- if (length) {
- this.$emit('updateStatus', 'metricType', MetricsType.UNKNOWN);
- return;
- }
- }
- const { typeOfMetrics } = data[0];
- this.$emit('updateStatus', 'metricType', typeOfMetrics);
- this.queryMetricTypesList = QueryMetricTypes[typeOfMetrics] || [];
- this.itemConfig.queryMetricType = this.queryMetricTypesList[0] && this.queryMetricTypesList[0].value;
- this.isChartType = ['readMetricsValues', 'readLabeledMetricsValues'].includes(
- this.itemConfig.queryMetricType,
- );
- this.isLabel = typeOfMetrics === MetricsType.LABELED_VALUE ? true : false;
- const values = {
- metricType: typeOfMetrics,
- queryMetricType: this.itemConfig.queryMetricType,
- chartType: MetricChartType[this.itemConfig.queryMetricType],
- metricName: params.value,
- };
- if (this.type === this.pageTypes[0]) {
- this.EDIT_TOPO_ENDPOINT_CONFIG({
- index: this.index,
- values,
- });
- } else if (this.type === this.pageTypes[1]) {
- this.EDIT_TOPO_INSTANCE_CONFIG({
- index: this.index,
- values,
- });
- } else {
- this.EDIT_COMP_CONFIG({
- index: this.index,
- values,
- });
- }
- this.itemConfig = {
- ...this.itemConfig,
- ...values,
- };
- });
+ this.updateMetricName(params);
return;
}
if (params.type === 'queryMetricType') {
- const values = {
- chartType: MetricChartType[params.value],
- [params.type]: params.value,
- };
+ this.updateQueryMetricType(params);
+ return;
+ }
+ if (params.type === 'independentSelector' || params.type === 'parentService') {
+ this.itemConfig[params.type] = params.value === 'true' ? true : false;
if (this.type === this.pageTypes[0]) {
this.EDIT_TOPO_ENDPOINT_CONFIG({
index: this.index,
- values,
+ values: { [params.type]: this.itemConfig[params.type] },
});
} else if (this.type === this.pageTypes[1]) {
this.EDIT_TOPO_INSTANCE_CONFIG({
index: this.index,
- values,
+ values: { [params.type]: this.itemConfig[params.type] },
});
} else {
- this.EDIT_COMP_CONFIG({
- index: this.index,
- values,
- });
+ this.EDIT_COMP_CONFIG({ index: this.index, values: { [params.type]: this.itemConfig[params.type] } });
}
- this.itemConfig = {
- ...this.itemConfig,
- ...values,
- };
- this.isChartType = ['readMetricsValues', 'readLabeledMetricsValues'].includes(this.itemConfig.queryMetricType);
+ }
+ if (params.type === 'aggregation' && ['milliseconds', 'seconds'].includes(this.itemConfig.aggregation)) {
+ this.updateAggregation(params);
return;
}
- if (params.type === 'independentSelector' || params.type === 'parentService') {
- this.itemConfig[params.type] = params.value === 'true' ? true : false;
+ if (this.type === this.pageTypes[0]) {
+ this.EDIT_TOPO_ENDPOINT_CONFIG({
+ index: this.index,
+ values: { [params.type]: params.value },
+ });
+ } else if (this.type === this.pageTypes[1]) {
+ this.EDIT_TOPO_INSTANCE_CONFIG({
+ index: this.index,
+ values: { [params.type]: params.value },
+ });
+ } else {
+ this.EDIT_COMP_CONFIG({ index: this.index, values: { [params.type]: params.value } });
+ }
+ }
+
+ private updateMetricName(params: { type: string; value: string }) {
+ this.TYPE_METRICS({ name: params.value }).then((data: Array<{ typeOfMetrics: string }>) => {
+ if (!data.length) {
+ return;
+ }
+ if (data.length > 1) {
+ const length = data.filter((d: { typeOfMetrics: string }) => d.typeOfMetrics !== MetricsType.REGULAR_VALUE)
+ .length;
+ if (length) {
+ this.$emit('updateStatus', 'metricType', MetricsType.UNKNOWN);
+ return;
+ }
+ }
+ const { typeOfMetrics } = data[0];
+ this.$emit('updateStatus', 'metricType', typeOfMetrics);
+ this.queryMetricTypesList = QueryMetricTypes[typeOfMetrics] || [];
+ this.itemConfig.queryMetricType = this.queryMetricTypesList[0] && this.queryMetricTypesList[0].value;
+ this.isChartType = ['readMetricsValues', 'readLabeledMetricsValues'].includes(this.itemConfig.queryMetricType);
+ this.isLabel = typeOfMetrics === MetricsType.LABELED_VALUE ? true : false;
+ const values = {
+ metricType: typeOfMetrics,
+ queryMetricType: this.itemConfig.queryMetricType,
+ chartType: MetricChartType[this.itemConfig.queryMetricType],
+ metricName: params.value,
+ };
if (this.type === this.pageTypes[0]) {
this.EDIT_TOPO_ENDPOINT_CONFIG({
index: this.index,
- values: { [params.type]: this.itemConfig[params.type] },
+ values,
});
} else if (this.type === this.pageTypes[1]) {
this.EDIT_TOPO_INSTANCE_CONFIG({
index: this.index,
- values: { [params.type]: this.itemConfig[params.type] },
+ values,
});
} else {
- this.EDIT_COMP_CONFIG({ index: this.index, values: { [params.type]: this.itemConfig[params.type] } });
+ this.EDIT_COMP_CONFIG({
+ index: this.index,
+ values,
+ });
}
-
- return;
- }
- if (params.type === 'aggregation' && ['milliseconds', 'seconds'].includes(this.itemConfig.aggregation)) {
- const values = {
- aggregationNum: 'YYYY-MM-DD HH:mm:ss',
- [params.type]: params.value,
- };
this.itemConfig = {
...this.itemConfig,
...values,
};
- this.EDIT_COMP_CONFIG({
- index: this.index,
- values,
- });
- return;
- }
+ });
+ }
+
+ private updateAggregation(params: { type: string; value: string }) {
+ const values = {
+ aggregationNum: 'YYYY-MM-DD HH:mm:ss',
+ [params.type]: params.value,
+ };
+ this.itemConfig = {
+ ...this.itemConfig,
+ ...values,
+ };
+ this.EDIT_COMP_CONFIG({
+ index: this.index,
+ values,
+ });
+ }
+
+ private updateQueryMetricType(params: { type: string; value: string }) {
+ const values = {
+ chartType: MetricChartType[params.value],
+ [params.type]: params.value,
+ };
if (this.type === this.pageTypes[0]) {
this.EDIT_TOPO_ENDPOINT_CONFIG({
index: this.index,
- values: { [params.type]: params.value },
+ values,
});
} else if (this.type === this.pageTypes[1]) {
this.EDIT_TOPO_INSTANCE_CONFIG({
index: this.index,
- values: { [params.type]: params.value },
+ values,
});
} else {
- this.EDIT_COMP_CONFIG({ index: this.index, values: { [params.type]: params.value } });
+ this.EDIT_COMP_CONFIG({
+ index: this.index,
+ values,
+ });
}
+ this.itemConfig = {
+ ...this.itemConfig,
+ ...values,
+ };
+ this.isChartType = ['readMetricsValues', 'readLabeledMetricsValues'].includes(this.itemConfig.queryMetricType);
}
private setItemServices(update: boolean = false) {
diff --git a/src/views/components/dashboard/charts/chart-table.vue b/src/views/components/dashboard/charts/chart-table.vue
index f7bc4de..856880b 100644
--- a/src/views/components/dashboard/charts/chart-table.vue
+++ b/src/views/components/dashboard/charts/chart-table.vue
@@ -15,16 +15,21 @@ limitations under the License. -->
<template>
<div class="rk-chart-table">
- <table>
- <tr>
- <th>{{ $t('name') }}</th>
- <th>{{ $t('value') }}</th>
- </tr>
- <tr v-for="key in dataKeys" :key="key">
- <td>{{ key }}</td>
- <td>{{ data[key][dataLength(data[key])] }}</td>
- </tr>
- </table>
+ <div ref="chartTable">
+ <div class="row flex-h" :style="`width: ${nameWidth + initWidth}px`">
+ <div class="name" :style="`width: ${nameWidth}px`">
+ {{ item.tableHeaderCol1 || $t('name') }}
+ <i class="r cp" ref="draggerName"><rk-icon icon="settings_ethernet"/></i>
+ </div>
+ <div class="value-col" v-if="showTableValues">
+ {{ item.tableHeaderCol2 || $t('value') }}
+ </div>
+ </div>
+ <div class="row flex-h" v-for="key in dataKeys" :key="key" :style="`width: ${nameWidth + initWidth}px`">
+ <div :style="`width: ${nameWidth}px`">{{ key }}</div>
+ <div class="value-col" v-if="showTableValues">{{ data[key][dataLength(data[key])] }}</div>
+ </div>
+ </div>
</div>
</template>
@@ -35,34 +40,77 @@ limitations under the License. -->
@Component
export default class ChartTable extends Vue {
@Prop() private data!: any;
+ @Prop() private item: any;
+
+ private nameWidth: number = 0;
+ private initWidth: number = 0;
private get dataKeys() {
const keys = Object.keys(this.data || {}).filter((i: any) => Array.isArray(this.data[i]) && this.data[i].length);
return keys;
}
- private dataLength(param: any[]) {
+ private get showTableValues() {
+ return this.item.showTableValues === 'true' || this.item.showTableValues === true ? true : false;
+ }
+
+ private mounted() {
+ const chartTable: any = this.$refs.chartTable;
+ const width = this.showTableValues ? chartTable.offsetWidth / 2 : chartTable.offsetWidth;
+ this.initWidth = this.showTableValues ? chartTable.offsetWidth / 2 : 0;
+ this.nameWidth = width - 5;
+ const drag: any = this.$refs.draggerName;
+ drag.onmousedown = (event: MouseEvent) => {
+ const diffX = event.clientX;
+ const copy = this.nameWidth;
+ document.onmousemove = (documentEvent) => {
+ const moveX = documentEvent.clientX - diffX;
+ this.nameWidth = copy + moveX;
+ };
+ document.onmouseup = () => {
+ document.onmousemove = null;
+ document.onmouseup = null;
+ };
+ };
+ }
+
+ private dataLength(param: number[]) {
return param.length - 1 || 0;
}
}
</script>
<style lang="scss" scoped>
.rk-chart-table {
- table {
- width: 100%;
- border-top: 1px solid #ccc;
- border-right: 1px solid #ccc;
- }
- tr {
- width: 100%;
- border: 1px solid #ccc;
+ height: 100%;
+ width: 100%;
+ overflow: auto;
+ .name {
+ padding-left: 15px;
}
- th,
- td {
+ .row {
border-left: 1px solid #ccc;
- border-bottom: 1px solid #ccc;
+ height: 20px;
+ div {
+ border-right: 1px solid #ccc;
+ text-align: center;
+ height: 20px;
+ line-height: 20px;
+ display: inline-block;
+ }
+ div:last-child {
+ border-bottom: 1px solid #ccc;
+ }
+ div:nth-last-child(2) {
+ border-bottom: 1px solid #ccc;
+ }
+ }
+ .row:first-child {
+ div {
+ border-top: 1px solid #ccc;
+ }
+ }
+ .value-col {
width: 50%;
- text-align: center;
}
}
</style>
diff --git a/src/views/components/dashboard/dashboard-comp.vue b/src/views/components/dashboard/dashboard-comp.vue
index ec697cf..d03d57d 100644
--- a/src/views/components/dashboard/dashboard-comp.vue
+++ b/src/views/components/dashboard/dashboard-comp.vue
@@ -51,8 +51,8 @@ limitations under the License. -->
</template>
<script lang="ts">
- import { Vue, Component, Watch, Prop } from 'vue-property-decorator';
- import { State, Mutation } from 'vuex-class';
+ import { Vue, Component, Prop } from 'vue-property-decorator';
+ import { Mutation } from 'vuex-class';
import copy from '@/utils/copy';
@Component
diff --git a/src/views/components/dashboard/dashboard-item.vue b/src/views/components/dashboard/dashboard-item.vue
index b9730ef..8df84fc 100644
--- a/src/views/components/dashboard/dashboard-item.vue
+++ b/src/views/components/dashboard/dashboard-item.vue
@@ -26,9 +26,12 @@ limitations under the License. -->
<use xlink:href="#lock"></use>
</svg>
</span>
+ <span v-show="!rocketGlobal.edit && itemConfig.chartType === 'ChartTable'" @click="copyTable">
+ <rk-icon class="r cp" icon="review-list" />
+ </span>
</div>
<div class="rk-dashboard-item-body">
- <div style="height:100%;">
+ <div style="height:100%; width:100%">
<component
:is="rocketGlobal.edit ? 'ChartEdit' : itemConfig.chartType"
ref="chart"
@@ -72,6 +75,7 @@ limitations under the License. -->
import { CalculationType } from './charts/constant';
import { State as globalState } from '@/store/modules/global';
import { State as optionState } from '@/store/modules/global/selectors';
+ import copy from '@/utils/copy';
@Component({
components: { ...charts },
@@ -313,6 +317,18 @@ limitations under the License. -->
}
}
+ private copyTable() {
+ const data: any = {};
+ const keys = Object.keys(this.chartSource || {}).filter(
+ (i: any) => Array.isArray(this.chartSource[i]) && this.chartSource[i].length,
+ );
+ for (const key of keys) {
+ const index = this.chartSource[key].length - 1 || 0;
+ data[key] = this.chartSource[key][index];
+ }
+ copy(JSON.stringify(data));
+ }
+
private deleteItem(index: number) {
if (this.type === this.pageTypes[0]) {
this.DELETE_TOPO_ENDPOINT(index);