diff --git a/src/assets/icons/circle.svg b/src/assets/icons/circle.svg new file mode 100644 index 00000000..f2584fff --- /dev/null +++ b/src/assets/icons/circle.svg @@ -0,0 +1,15 @@ + + \ No newline at end of file diff --git a/src/components/Graph.vue b/src/components/Graph.vue index 5bc8974e..4a6523e9 100644 --- a/src/components/Graph.vue +++ b/src/components/Graph.vue @@ -215,6 +215,7 @@ onBeforeUnmount(() => { .chart { overflow: hidden; + flex: 1; } .menus { diff --git a/src/hooks/useLegendProcessor.ts b/src/hooks/useLegendProcessor.ts new file mode 100644 index 00000000..ba6413d5 --- /dev/null +++ b/src/hooks/useLegendProcessor.ts @@ -0,0 +1,142 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { LegendOptions } from "@/types/dashboard"; +import { isDef } from "@/utils/is"; + +export default function useLegendProcess(legend?: LegendOptions) { + let isRight = false; + if (legend && legend.toTheRight) { + isRight = true; + } + function showEchartsLegend(keys: string[]) { + if (legend && isDef(legend.show)) { + if (legend.asTable && legend.show) { + return false; + } + return legend.show; + } + if (keys.length === 1) { + return false; + } + if (legend && legend.asTable) { + return false; + } + return true; + } + function aggregations( + data: { [key: string]: number[] }, + intervalTime: string[] + ) { + const source: { [key: string]: unknown }[] = []; + const keys = Object.keys(data || {}).filter( + (i: any) => Array.isArray(data[i]) && data[i].length + ); + const headers = []; + + for (const [key, value] of keys.entries()) { + const arr = JSON.parse(JSON.stringify(data[value])); + const item: { [key: string]: unknown } = { + name: value, + topN: arr + .map((d: number, index: number) => { + return { + key: intervalTime[index], + value: d, + }; + }) + .sort( + ( + a: { key: string; value: number }, + b: { key: string; value: number } + ) => b.value - a.value + ) + .filter((_: unknown, index: number) => index < 10), + }; + if (legend) { + if (legend.min) { + item.min = Math.min(...data[value]).toFixed(2); + if (key === 0) { + headers.push({ value: "min", label: "Min" }); + } + } + if (legend.max) { + item.max = Math.max(...data[value]).toFixed(2); + if (key === 0) { + headers.push({ value: "max", label: "Max" }); + } + } + if (legend.mean) { + const total = data[value].reduce((prev: number, next: number) => { + prev += Number(next); + return prev; + }, 0); + item.mean = (total / data[value].length).toFixed(4); + if (key === 0) { + headers.push({ value: "mean", label: "Mean" }); + } + } + if (legend.total) { + item.total = data[value] + .reduce((prev: number, next: number) => { + prev += Number(next); + return prev; + }, 0) + .toFixed(2); + if (key === 0) { + headers.push({ value: "total", label: "Total" }); + } + } + } + source.push(item); + } + + return { source, headers }; + } + function chartColors(keys: string[]) { + let color: string[] = []; + switch (keys.length) { + case 2: + color = ["#FF6A84", "#a0b1e6"]; + break; + case 1: + color = ["#3f96e3"]; + break; + default: + color = [ + "#30A4EB", + "#45BFC0", + "#FFCC55", + "#FF6A84", + "#a0a7e6", + "#c23531", + "#2f4554", + "#61a0a8", + "#d48265", + "#91c7ae", + "#749f83", + "#ca8622", + "#bda29a", + "#6e7074", + "#546570", + "#c4ccd3", + ]; + break; + } + return color; + } + return { showEchartsLegend, isRight, aggregations, chartColors }; +} diff --git a/src/hooks/useProcessor.ts b/src/hooks/useMetricsProcessor.ts similarity index 99% rename from src/hooks/useProcessor.ts rename to src/hooks/useMetricsProcessor.ts index 97b22e4d..54dc3a19 100644 --- a/src/hooks/useProcessor.ts +++ b/src/hooks/useMetricsProcessor.ts @@ -184,7 +184,7 @@ export function useSourceProcessor( const c = (config.metricConfig && config.metricConfig[index]) || {}; if (type === MetricQueryTypes.ReadMetricsValues) { - source[m] = + source[c.label || m] = (resp.data[keys[index]] && calculateExp(resp.data[keys[index]].values.values, c)) || []; diff --git a/src/locales/lang/en.ts b/src/locales/lang/en.ts index 0171ef0f..7609aa06 100644 --- a/src/locales/lang/en.ts +++ b/src/locales/lang/en.ts @@ -52,17 +52,19 @@ const msg = { instance: "Instance", create: "Create", loading: "Loading", - selectVisualization: "Visualize your metrics", + selectVisualization: "Visualize Metrics", visualization: "Visualization", - graphStyles: "Graph styles", - widgetOptions: "Widget options", - standardOptions: "Standard options", + graphStyles: "Graph Styles", + widgetOptions: "Widget Options", + standardOptions: "Standard Options", max: "Max", min: "Min", plus: "Plus", + mean: "Mean", minus: "Minus", multiply: "Multiply", divide: "Divide", + total: "Total", convertToMilliseconds: "Convert Unix Timestamp(milliseconds)", convertToSeconds: "Convert Unix Timestamp(seconds)", smooth: "Smooth", @@ -167,6 +169,11 @@ const msg = { enableRelatedTrace: "Enable Related Trace", maxTraceDuration: "Maximum Duration", minTraceDuration: "Minimum Duration", + legendOptions: "Legend Options", + showLegend: "Show Legend", + asTable: "As Table", + toTheRight: "To The Right", + legendValues: "Legend Values", seconds: "Seconds", hourTip: "Select Hour", minuteTip: "Select Minute", @@ -259,7 +266,7 @@ const msg = { entityType: "Entity Type", maxItemNum: "Max number of Item", unknownMetrics: "Unknown Metrics", - labels: "Labels", + labels: "Label", aggregation: "Calculation", unit: "Unit", labelsIndex: "Label Subscript", @@ -320,6 +327,7 @@ const msg = { eventsParameters: "Event Parameters", eventDetail: "Event Detail", value: "Value", + key: "Key", show: "Show", hide: "Hide", statistics: "Statistics", diff --git a/src/locales/lang/es.ts b/src/locales/lang/es.ts index 66fb5617..cb743e6e 100644 --- a/src/locales/lang/es.ts +++ b/src/locales/lang/es.ts @@ -59,9 +59,11 @@ const msg = { standardOptions: "Opciones estandar", max: "Máx", min: "Mín", + mean: "Promedio", plus: "Más", minus: "Menoss", multiply: "Multiplcar", + total: "Todo", divide: "Dividir", convertToMilliseconds: "Convertir Unix Timestamp(milisegundos)", convertToSeconds: "Convertir Unix Timestamp(segundos)", @@ -160,6 +162,7 @@ const msg = { queryOrder: "Orden de consulta", latency: "Retraso", metricValues: "Valor métrico", + legendValues: "Valor de la leyenda", seconds: "Segundos", hourTip: "Seleccione Hora", minuteTip: "Seleccione Minuto", @@ -171,6 +174,10 @@ const msg = { queryConditions: "Condiciones de consulta", maxTraceDuration: "Duración máxima", minTraceDuration: "Duración mínima", + legendOptions: "Opciones de leyenda", + showLegend: "Mostrar leyenda", + asTable: "Como tabla", + toTheRight: "Derecha", second: "s", yearSuffix: "Año", monthsHead: "Ene_Feb_Mar_Abr_May_Jun_Jul_Ago_Set_Oct_Nov_Dic", @@ -320,6 +327,7 @@ const msg = { eventsParameters: "Parámetro del Evento", eventDetail: "Detalle del Evento", value: "Valor", + key: "Clave", show: "Mostrar", hide: "Oculatr", statistics: "Estadísticas", diff --git a/src/locales/lang/zh.ts b/src/locales/lang/zh.ts index 141e60d4..aacde22f 100644 --- a/src/locales/lang/zh.ts +++ b/src/locales/lang/zh.ts @@ -56,10 +56,12 @@ const msg = { standardOptions: "标准选项", max: "最大值", min: "最小值", + mean: "平均值", plus: "加法", minus: "减法", multiply: "乘法", divide: "除法", + total: "总计", convertToMilliseconds: "转换Unix时间戳(毫秒)", convertToSeconds: "转换Unix时间戳(秒)", smooth: "光滑的", @@ -164,6 +166,11 @@ const msg = { queryConditions: "查询条件", maxTraceDuration: "最大持续时间", minTraceDuration: "最小持续时间", + legendOptions: "图例选项", + showLegend: "显示图例", + asTable: "作为表格", + toTheRight: "在右边", + legendValues: "图例值", seconds: "秒", hourTip: "选择小时", minuteTip: "选择分钟", @@ -318,6 +325,7 @@ const msg = { eventsParameters: "事件参数", eventDetail: "事件详情", value: "数值", + key: "Key", tableHeader: "表头名称", tableValues: "表值", show: "展示", diff --git a/src/store/modules/topology.ts b/src/store/modules/topology.ts index c72a452d..8b2205e3 100644 --- a/src/store/modules/topology.ts +++ b/src/store/modules/topology.ts @@ -23,7 +23,7 @@ import { useSelectorStore } from "@/store/modules/selectors"; import { useAppStoreWithOut } from "@/store/modules/app"; import { AxiosResponse } from "axios"; import query from "@/graphql/fetch"; -import { useQueryTopologyMetrics } from "@/hooks/useProcessor"; +import { useQueryTopologyMetrics } from "@/hooks/useMetricsProcessor"; import { ElMessage } from "element-plus"; interface MetricVal { diff --git a/src/styles/lib.scss b/src/styles/lib.scss index 1d2a5084..f991ab46 100644 --- a/src/styles/lib.scss +++ b/src/styles/lib.scss @@ -173,7 +173,7 @@ } .scroll_bar_style::-webkit-scrollbar { - width: 9px; + width: 4px; height: 4px; background-color: #eee; } diff --git a/src/styles/reset.scss b/src/styles/reset.scss index 06af9cec..41ef2836 100644 --- a/src/styles/reset.scss +++ b/src/styles/reset.scss @@ -153,6 +153,10 @@ pre { margin-left: 5px; } +.el-switch__label * { + font-size: 12px; +} + .el-drawer__header { margin-bottom: 0; } diff --git a/src/types/dashboard.d.ts b/src/types/dashboard.d.ts index ceabab34..a74d0819 100644 --- a/src/types/dashboard.d.ts +++ b/src/types/dashboard.d.ts @@ -95,6 +95,7 @@ export type GraphConfig = export interface BarConfig { type?: string; showBackground?: boolean; + legend?: LegendOptions; } export interface LineConfig extends AreaConfig { type?: string; @@ -110,6 +111,7 @@ export interface LineConfig extends AreaConfig { export interface AreaConfig { type?: string; opacity?: number; + legend?: LegendOptions; } export interface CardConfig { @@ -180,3 +182,13 @@ export type EventParams = { value: number | number[]; color: string; }; +export type LegendOptions = { + show: boolean; + total: boolean; + min: boolean; + max: boolean; + mean: boolean; + asTable: boolean; + toTheRight: boolean; + width: number; +}; diff --git a/src/views/dashboard/configuration/Widget.vue b/src/views/dashboard/configuration/Widget.vue index 4582b702..c09a4c40 100644 --- a/src/views/dashboard/configuration/Widget.vue +++ b/src/views/dashboard/configuration/Widget.vue @@ -32,6 +32,7 @@ limitations under the License. --> :data="states.source" :config="{ ...graph, + legend: (dashboardStore.selectedGrid.graph || {}).legend, i: dashboardStore.selectedGrid.i, metrics: dashboardStore.selectedGrid.metrics, metricTypes: dashboardStore.selectedGrid.metricTypes, diff --git a/src/views/dashboard/configuration/widget/graph-styles/Area.vue b/src/views/dashboard/configuration/widget/graph-styles/Area.vue index 9c4b3e0b..620c803b 100644 --- a/src/views/dashboard/configuration/widget/graph-styles/Area.vue +++ b/src/views/dashboard/configuration/widget/graph-styles/Area.vue @@ -13,6 +13,7 @@ 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. -->