This is an automated email from the ASF dual-hosted git repository.

wusheng pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/skywalking-booster-ui.git


The following commit(s) were added to refs/heads/main by this push:
     new 54997794 feat: remove `returnTypeOfMQE` and add detail label (#277)
54997794 is described below

commit 54997794b49b0b25d4f1d4bdb73884d66bd24ae0
Author: Fine0830 <[email protected]>
AuthorDate: Thu Jun 8 20:52:44 2023 +0800

    feat: remove `returnTypeOfMQE` and add detail label (#277)
---
 src/graphql/fragments/dashboard.ts                 |   9 -
 src/graphql/query/dashboard.ts                     |   3 -
 src/hooks/useExpressionsProcessor.ts               | 239 +++++++++++----------
 src/locales/lang/en.ts                             |   3 +
 src/locales/lang/es.ts                             |   3 +
 src/locales/lang/zh.ts                             |   3 +
 src/types/dashboard.d.ts                           |   1 +
 src/views/dashboard/Widget.vue                     |  24 ++-
 src/views/dashboard/configuration/Widget.vue       |  13 +-
 .../configuration/widget/metric/Index.vue          |  83 +++----
 .../configuration/widget/metric/Standard.vue       |  29 ++-
 src/views/dashboard/controls/Widget.vue            |  28 +--
 src/views/dashboard/graphs/EndpointList.vue        |   8 +-
 src/views/dashboard/graphs/InstanceList.vue        |   9 +-
 src/views/dashboard/graphs/ServiceList.vue         |   8 +-
 .../dashboard/graphs/components/ColumnGraph.vue    |  14 +-
 16 files changed, 260 insertions(+), 217 deletions(-)

diff --git a/src/graphql/fragments/dashboard.ts 
b/src/graphql/fragments/dashboard.ts
index 9b673b08..f453f3d8 100644
--- a/src/graphql/fragments/dashboard.ts
+++ b/src/graphql/fragments/dashboard.ts
@@ -68,12 +68,3 @@ export const deleteTemplate = {
         message
     }`,
 };
-export const TypeOfMQE = {
-  variable: "$expression: String!",
-  query: `
-  metricType: returnTypeOfMQE(expression: $expression) {
-    type
-    error
-  }
-  `,
-};
diff --git a/src/graphql/query/dashboard.ts b/src/graphql/query/dashboard.ts
index a60a464e..738fafa8 100644
--- a/src/graphql/query/dashboard.ts
+++ b/src/graphql/query/dashboard.ts
@@ -21,7 +21,6 @@ import {
   addTemplate,
   changeTemplate,
   deleteTemplate,
-  TypeOfMQE,
 } from "../fragments/dashboard";
 
 export const queryTypeOfMetrics = `query 
typeOfMetrics(${TypeOfMetrics.variable}) {${TypeOfMetrics.query}}`;
@@ -35,5 +34,3 @@ export const updateTemplate = `mutation 
template(${changeTemplate.variable}) {${
 export const removeTemplate = `mutation template(${deleteTemplate.variable}) 
{${deleteTemplate.query}}`;
 
 export const getTemplates = `query templates {${getAllTemplates.query}}`;
-
-export const getTypeOfMQE = `query returnTypeOfMQE(${TypeOfMQE.variable}) 
{${TypeOfMQE.query}}`;
diff --git a/src/hooks/useExpressionsProcessor.ts 
b/src/hooks/useExpressionsProcessor.ts
index 786184f7..94ca8378 100644
--- a/src/hooks/useExpressionsProcessor.ts
+++ b/src/hooks/useExpressionsProcessor.ts
@@ -23,129 +23,142 @@ import { useAppStoreWithOut } from "@/store/modules/app";
 import type { MetricConfigOpt } from "@/types/dashboard";
 import type { Instance, Endpoint, Service } from "@/types/selector";
 
-export function useExpressionsQueryProcessor(config: Indexable) {
-  if (!(config.metrics && config.metrics[0])) {
-    return;
-  }
-  if (!(config.metricTypes && config.metricTypes[0])) {
-    return;
-  }
-  const appStore = useAppStoreWithOut();
-  const dashboardStore = useDashboardStore();
-  const selectorStore = useSelectorStore();
+export async function useExpressionsQueryProcessor(config: Indexable) {
+  function expressionsGraphqlPods() {
+    if (!(config.metrics && config.metrics[0])) {
+      return;
+    }
+    const appStore = useAppStoreWithOut();
+    const dashboardStore = useDashboardStore();
+    const selectorStore = useSelectorStore();
 
-  if (!selectorStore.currentService && dashboardStore.entity !== "All") {
-    return;
-  }
-  const conditions: Recordable = {
-    duration: appStore.durationTime,
-  };
-  const variables: string[] = [`$duration: Duration!`];
-  const isRelation = ["ServiceRelation", "ServiceInstanceRelation", 
"EndpointRelation", "ProcessRelation"].includes(
-    dashboardStore.entity,
-  );
-  if (isRelation && !selectorStore.currentDestService) {
-    return;
-  }
-  const fragment = config.metrics.map((name: string, index: number) => {
-    variables.push(`$expression${index}: String!`, `$entity${index}: Entity!`);
-    conditions[`expression${index}`] = name;
-    const entity = {
-      serviceName: dashboardStore.entity === "All" ? undefined : 
selectorStore.currentService.value,
-      normal: dashboardStore.entity === "All" ? undefined : 
selectorStore.currentService.normal,
-      serviceInstanceName: ["ServiceInstance", "ServiceInstanceRelation", 
"ProcessRelation"].includes(
-        dashboardStore.entity,
-      )
-        ? selectorStore.currentPod && selectorStore.currentPod.value
-        : undefined,
-      endpointName: dashboardStore.entity.includes("Endpoint")
-        ? selectorStore.currentPod && selectorStore.currentPod.value
-        : undefined,
-      processName: dashboardStore.entity.includes("Process")
-        ? selectorStore.currentProcess && selectorStore.currentProcess.value
-        : undefined,
-      destNormal: isRelation ? selectorStore.currentDestService.normal : 
undefined,
-      destServiceName: isRelation ? selectorStore.currentDestService.value : 
undefined,
-      destServiceInstanceName: ["ServiceInstanceRelation", 
"ProcessRelation"].includes(dashboardStore.entity)
-        ? selectorStore.currentDestPod && selectorStore.currentDestPod.value
-        : undefined,
-      destEndpointName:
-        dashboardStore.entity === "EndpointRelation"
+    if (!selectorStore.currentService && dashboardStore.entity !== "All") {
+      return;
+    }
+    const conditions: Recordable = {
+      duration: appStore.durationTime,
+    };
+    const variables: string[] = [`$duration: Duration!`];
+    const isRelation = ["ServiceRelation", "ServiceInstanceRelation", 
"EndpointRelation", "ProcessRelation"].includes(
+      dashboardStore.entity,
+    );
+    if (isRelation && !selectorStore.currentDestService) {
+      return;
+    }
+    const fragment = config.metrics.map((name: string, index: number) => {
+      variables.push(`$expression${index}: String!`, `$entity${index}: 
Entity!`);
+      conditions[`expression${index}`] = name;
+      const entity = {
+        serviceName: dashboardStore.entity === "All" ? undefined : 
selectorStore.currentService.value,
+        normal: dashboardStore.entity === "All" ? undefined : 
selectorStore.currentService.normal,
+        serviceInstanceName: ["ServiceInstance", "ServiceInstanceRelation", 
"ProcessRelation"].includes(
+          dashboardStore.entity,
+        )
+          ? selectorStore.currentPod && selectorStore.currentPod.value
+          : undefined,
+        endpointName: dashboardStore.entity.includes("Endpoint")
+          ? selectorStore.currentPod && selectorStore.currentPod.value
+          : undefined,
+        processName: dashboardStore.entity.includes("Process")
+          ? selectorStore.currentProcess && selectorStore.currentProcess.value
+          : undefined,
+        destNormal: isRelation ? selectorStore.currentDestService.normal : 
undefined,
+        destServiceName: isRelation ? selectorStore.currentDestService.value : 
undefined,
+        destServiceInstanceName: ["ServiceInstanceRelation", 
"ProcessRelation"].includes(dashboardStore.entity)
           ? selectorStore.currentDestPod && selectorStore.currentDestPod.value
           : undefined,
-      destProcessName: dashboardStore.entity.includes("ProcessRelation")
-        ? selectorStore.currentDestProcess && 
selectorStore.currentDestProcess.value
-        : undefined,
-    };
-    conditions[`entity${index}`] = entity;
-
-    return `expression${index}: execExpression(expression: 
$expression${index}, entity: $entity${index}, duration: 
$duration)${RespFields.execExpression}`;
-  });
-  const queryStr = `query queryData(${variables}) {${fragment}}`;
+        destEndpointName:
+          dashboardStore.entity === "EndpointRelation"
+            ? selectorStore.currentDestPod && 
selectorStore.currentDestPod.value
+            : undefined,
+        destProcessName: dashboardStore.entity.includes("ProcessRelation")
+          ? selectorStore.currentDestProcess && 
selectorStore.currentDestProcess.value
+          : undefined,
+      };
+      conditions[`entity${index}`] = entity;
 
-  return {
-    queryStr,
-    conditions,
-  };
-}
+      return `expression${index}: execExpression(expression: 
$expression${index}, entity: $entity${index}, duration: 
$duration)${RespFields.execExpression}`;
+    });
+    const queryStr = `query queryData(${variables}) {${fragment}}`;
 
-export function useExpressionsSourceProcessor(
-  resp: { errors: string; data: Indexable },
-  config: {
-    metrics: string[];
-    metricTypes: string[];
-    metricConfig: MetricConfigOpt[];
-  },
-) {
-  if (resp.errors) {
-    ElMessage.error(resp.errors);
-    return {};
-  }
-  if (!resp.data) {
-    ElMessage.error("The query is wrong");
-    return {};
+    return {
+      queryStr,
+      conditions,
+    };
   }
-  const source: { [key: string]: unknown } = {};
-  const keys = Object.keys(resp.data);
-  for (let i = 0; i < config.metrics.length; i++) {
-    const type = config.metricTypes[i];
-    const c: MetricConfigOpt = (config.metricConfig && config.metricConfig[i]) 
|| {};
-    const results = (resp.data[keys[i]] && resp.data[keys[i]].results) || [];
-    const name = config.metrics[i];
 
-    if (type === ExpressionResultType.TIME_SERIES_VALUES) {
-      if (results.length === 1) {
-        source[c.label || name] = results[0].values.map((d: { value: unknown 
}) => d.value) || [];
-      } else {
-        const labels = (c.label || "").split(",").map((item: string) => 
item.replace(/^\s*|\s*$/g, ""));
-        for (const item of results) {
-          const values = item.values.map((d: { value: unknown }) => d.value) 
|| [];
-          const index = item.metric.labels[0].value;
-          const indexNum = labels.findIndex((_, i: number) => i === 
Number(index));
-          if (labels[indexNum] && indexNum > -1) {
-            source[labels[indexNum]] = values;
+  function expressionsSource(resp: { errors: string; data: Indexable }) {
+    if (resp.errors) {
+      ElMessage.error(resp.errors);
+      return { source: {}, tips: [], typesOfMQE: [] };
+    }
+    if (!resp.data) {
+      ElMessage.error("The query is wrong");
+      return { source: {}, tips: [], typesOfMQE: [] };
+    }
+    const tips: string[] = [];
+    const source: { [key: string]: unknown } = {};
+    const keys = Object.keys(resp.data);
+    const typesOfMQE: string[] = [];
+
+    for (let i = 0; i < config.metrics.length; i++) {
+      const c: MetricConfigOpt = (config.metricConfig && 
config.metricConfig[i]) || {};
+      const obj = resp.data[keys[i]] || {};
+      const results = obj.results || [];
+      const name = config.metrics[i];
+      const type = obj.type;
+
+      tips.push(obj.error);
+      typesOfMQE.push(type);
+      if (!obj.error) {
+        if (type === ExpressionResultType.TIME_SERIES_VALUES) {
+          if (results.length === 1) {
+            source[c.label || name] = results[0].values.map((d: { value: 
unknown }) => d.value) || [];
           } else {
-            source[index] = values;
+            const labels = (c.label || "").split(",").map((item: string) => 
item.replace(/^\s*|\s*$/g, ""));
+            for (const item of results) {
+              const values = item.values.map((d: { value: unknown }) => 
d.value) || [];
+              const index = item.metric.labels[0].value;
+              const indexNum = labels.findIndex((_, i: number) => i === 
Number(index));
+              if (labels[indexNum] && indexNum > -1) {
+                source[labels[indexNum]] = values;
+              } else {
+                source[index] = values;
+              }
+            }
           }
         }
+        if (type === ExpressionResultType.SINGLE_VALUE) {
+          source[c.label || name] = results[0].values[0].value;
+        }
+        if (([ExpressionResultType.RECORD_LIST, 
ExpressionResultType.SORTED_LIST] as string[]).includes(type)) {
+          source[name] = results[0].values;
+        }
       }
     }
-    if (type === ExpressionResultType.SINGLE_VALUE) {
-      source[c.label || name] = results[0].values[0].value;
-    }
-    if (([ExpressionResultType.RECORD_LIST, ExpressionResultType.SORTED_LIST] 
as string[]).includes(type)) {
-      source[name] = results[0].values;
-    }
+
+    return { source, tips, typesOfMQE };
+  }
+  const params = await expressionsGraphqlPods();
+  if (!params) {
+    return { source: {}, tips: [], typesOfMQE: [] };
+  }
+
+  const dashboardStore = useDashboardStore();
+  const json = await dashboardStore.fetchMetricValue(params);
+  if (json.errors) {
+    ElMessage.error(json.errors);
+    return { source: {}, tips: [], typesOfMQE: [] };
   }
+  const data = expressionsSource(json);
 
-  return source;
+  return data;
 }
 
 export async function useExpressionsQueryPodsMetrics(
   pods: Array<(Instance | Endpoint | Service) & Indexable>,
   config: {
     expressions: string[];
-    typesOfMQE: string[];
     subExpressions: string[];
     metricConfig: MetricConfigOpt[];
   },
@@ -154,16 +167,13 @@ export async function useExpressionsQueryPodsMetrics(
   function expressionsGraphqlPods() {
     const metrics: string[] = [];
     const subMetrics: string[] = [];
-    const metricTypes: string[] = [];
     config.expressions = config.expressions || [];
     config.subExpressions = config.subExpressions || [];
-    config.typesOfMQE = config.typesOfMQE || [];
 
     for (let i = 0; i < config.expressions.length; i++) {
       if (config.expressions[i]) {
         metrics.push(config.expressions[i]);
         subMetrics.push(config.subExpressions[i]);
-        metricTypes.push(config.typesOfMQE[i]);
       }
     }
     if (!metrics.length) {
@@ -217,14 +227,21 @@ export async function useExpressionsQueryPodsMetrics(
     const subNames: string[] = [];
     const metricConfigArr: MetricConfigOpt[] = [];
     const metricTypesArr: string[] = [];
+    const expressionsTips: string[] = [];
+    const subExpressionsTips: string[] = [];
     const data = pods.map((d: any, idx: number) => {
       for (let index = 0; index < config.expressions.length; index++) {
         const c: MetricConfigOpt = (config.metricConfig && 
config.metricConfig[index]) || {};
         const k = "expression" + idx + index;
         const sub = "subexpression" + idx + index;
-        const results = (resp.data[k] && resp.data[k].results) || [];
-        const subResults = (resp.data[sub] && resp.data[sub].results) || [];
+        const obj = resp.data[k] || {};
+        const results = obj.results || [];
+        const typesOfMQE = obj.type || "";
+        const subObj = resp.data[sub] || {};
+        const subResults = subObj.results || [];
 
+        expressionsTips.push(obj.error);
+        subExpressionsTips.push(subObj.error);
         if (results.length > 1) {
           const labels = (c.label || "").split(",").map((item: string) => 
item.replace(/^\s*|\s*$/g, ""));
           const labelsIdx = (c.labelsIndex || "").split(",").map((item: 
string) => item.replace(/^\s*|\s*$/g, ""));
@@ -249,7 +266,7 @@ export async function useExpressionsQueryPodsMetrics(
             if (!j) {
               names.push(name);
               metricConfigArr.push({ ...c, index: i });
-              metricTypesArr.push(config.typesOfMQE[index]);
+              metricTypesArr.push(typesOfMQE);
             }
           }
         } else {
@@ -273,14 +290,14 @@ export async function useExpressionsQueryPodsMetrics(
             names.push(name);
             subNames.push(subName);
             metricConfigArr.push(c);
-            metricTypesArr.push(config.typesOfMQE[index]);
+            metricTypesArr.push(typesOfMQE);
           }
         }
       }
       return d;
     });
 
-    return { data, names, subNames, metricConfigArr, metricTypesArr };
+    return { data, names, subNames, metricConfigArr, metricTypesArr, 
expressionsTips, subExpressionsTips };
   }
   const dashboardStore = useDashboardStore();
   const params = await expressionsGraphqlPods();
diff --git a/src/locales/lang/en.ts b/src/locales/lang/en.ts
index a39c34fb..494853dc 100644
--- a/src/locales/lang/en.ts
+++ b/src/locales/lang/en.ts
@@ -388,5 +388,8 @@ const msg = {
   elasticsearch: "Elasticsearch",
   mq: "MQ",
   rabbitMQ: "RabbitMQ",
+  detailLabel: "Detail Label",
+  summary: "Summary",
+  detail: "Detail",
 };
 export default msg;
diff --git a/src/locales/lang/es.ts b/src/locales/lang/es.ts
index 41259234..26740948 100644
--- a/src/locales/lang/es.ts
+++ b/src/locales/lang/es.ts
@@ -387,5 +387,8 @@ const msg = {
   elasticsearch: "Elasticsearch",
   mq: "MQ",
   rabbitMQ: "RabbitMQ",
+  detailLabel: "Detail Label",
+  summary: "Summary",
+  detail: "Detail",
 };
 export default msg;
diff --git a/src/locales/lang/zh.ts b/src/locales/lang/zh.ts
index b592abdf..53d64576 100644
--- a/src/locales/lang/zh.ts
+++ b/src/locales/lang/zh.ts
@@ -385,5 +385,8 @@ const msg = {
   elasticsearch: "Elasticsearch",
   mq: "消息队列",
   rabbitMQ: "RabbitMQ",
+  detailLabel: "详细标签",
+  summary: "概括",
+  detail: "详细",
 };
 export default msg;
diff --git a/src/types/dashboard.d.ts b/src/types/dashboard.d.ts
index f93f4b26..8612c10e 100644
--- a/src/types/dashboard.d.ts
+++ b/src/types/dashboard.d.ts
@@ -79,6 +79,7 @@ export type MetricConfigOpt = {
   sortOrder?: string;
   topN?: number;
   index?: number;
+  detailLabel?: string;
 };
 
 export interface WidgetConfig {
diff --git a/src/views/dashboard/Widget.vue b/src/views/dashboard/Widget.vue
index b7a2c50e..ce3a337d 100644
--- a/src/views/dashboard/Widget.vue
+++ b/src/views/dashboard/Widget.vue
@@ -57,7 +57,7 @@ limitations under the License. -->
   import { useSelectorStore } from "@/store/modules/selectors";
   import { useDashboardStore } from "@/store/modules/dashboard";
   import { useQueryProcessor, useSourceProcessor } from 
"@/hooks/useMetricsProcessor";
-  import { useExpressionsQueryProcessor, useExpressionsSourceProcessor } from 
"@/hooks/useExpressionsProcessor";
+  import { useExpressionsQueryProcessor } from 
"@/hooks/useExpressionsProcessor";
   import graphs from "./graphs";
   import { EntityType } from "./data";
   import timeFormat from "@/utils/timeFormat";
@@ -130,11 +130,18 @@ limitations under the License. -->
       }
       async function queryMetrics() {
         const isExpression = config.value.metricMode === 
MetricModes.Expression;
-        const params = isExpression
-          ? await useExpressionsQueryProcessor({
-              ...config.value,
-            })
-          : await useQueryProcessor({ ...config.value });
+        if (isExpression) {
+          loading.value = true;
+          const params = await useExpressionsQueryProcessor({
+            metrics: config.value.expressions || [],
+            metricConfig: config.value.metricConfig || [],
+            subExpressions: config.value.subExpressions || [],
+          });
+          loading.value = false;
+          source.value = params.source || {};
+          return;
+        }
+        const params = await useQueryProcessor({ ...config.value });
         if (!params) {
           source.value = {};
           return;
@@ -149,9 +156,8 @@ limitations under the License. -->
           metrics: config.value.metrics || [],
           metricTypes: config.value.metricTypes || [],
           metricConfig: config.value.metricConfig || [],
-          subExpressions: config.value.subExpressions || [],
         };
-        source.value = isExpression ? await 
useExpressionsSourceProcessor(json, d) : await useSourceProcessor(json, d);
+        source.value = await useSourceProcessor(json, d);
       }
       watch(
         () => appStoreWithOut.durationTime,
@@ -181,7 +187,7 @@ limitations under the License. -->
 
   .widget-chart {
     background: #fff;
-    box-shadow: 0px 1px 4px 0px #00000029;
+    box-shadow: 0 1px 4px 0 #00000029;
     border-radius: 3px;
     padding: 5px;
     width: 100%;
diff --git a/src/views/dashboard/configuration/Widget.vue 
b/src/views/dashboard/configuration/Widget.vue
index 772f2f8d..63c3f4f3 100644
--- a/src/views/dashboard/configuration/Widget.vue
+++ b/src/views/dashboard/configuration/Widget.vue
@@ -45,6 +45,7 @@ limitations under the License. -->
             subTypesOfMQE: dashboardStore.selectedGrid.subTypesOfMQE || [],
           }"
           :needQuery="true"
+          @expressionTips="getErrors"
         />
         <div v-show="!graph.type" class="no-data">
           {{ t("noData") }}
@@ -54,7 +55,7 @@ limitations under the License. -->
     <div class="collapse" :style="{ height: configHeight + 'px' }">
       <el-collapse v-model="states.activeNames" :style="{ 
'--el-collapse-header-font-size': '15px' }">
         <el-collapse-item :title="t('selectVisualization')" name="1">
-          <MetricOptions @update="getSource" @loading="setLoading" />
+          <MetricOptions @update="getSource" @loading="setLoading" 
:errors="errors" :subErrors="subErrors" />
         </el-collapse-item>
         <el-collapse-item :title="t('graphStyles')" name="2">
           <component :is="`${graph.type}Config`" />
@@ -102,6 +103,8 @@ limitations under the License. -->
       const dashboardStore = useDashboardStore();
       const appStoreWithOut = useAppStoreWithOut();
       const loading = ref<boolean>(false);
+      const errors = ref<string[]>([]);
+      const subErrors = ref<string[]>([]);
       const states = reactive<{
         activeNames: string;
         source: unknown;
@@ -128,6 +131,11 @@ limitations under the License. -->
         states.source = source;
       }
 
+      function getErrors(params: { tips: string[]; subTips: string[] }) {
+        errors.value = params.tips;
+        subErrors.value = params.subTips;
+      }
+
       function setLoading(load: boolean) {
         loading.value = load;
       }
@@ -169,12 +177,15 @@ limitations under the License. -->
         applyConfig,
         cancelConfig,
         getSource,
+        getErrors,
         setLoading,
         widget,
         graph,
         title,
         tips,
         hasAssociate,
+        errors,
+        subErrors,
       };
     },
   });
diff --git a/src/views/dashboard/configuration/widget/metric/Index.vue 
b/src/views/dashboard/configuration/widget/metric/Index.vue
index 44a07d8f..b0c3b95a 100644
--- a/src/views/dashboard/configuration/widget/metric/Index.vue
+++ b/src/views/dashboard/configuration/widget/metric/Index.vue
@@ -35,8 +35,8 @@ limitations under the License. -->
     @change="changeMetricMode"
   />
   <div v-if="isExpression && states.isList">
-    <span class="title">Summary</span>
-    <span>Detail</span>
+    <span class="title">{{ t("summary") }}</span>
+    <span>{{ t("detail") }}</span>
   </div>
   <div v-for="(metric, index) in states.metrics" :key="index" class="mb-10">
     <span v-if="isExpression">
@@ -93,8 +93,12 @@ limitations under the License. -->
       />
       <Icon class="cp" iconName="remove_circle_outline" size="middle" 
@click="deleteMetric(index)" />
     </span>
-    <div v-if="states.tips[index] && isExpression" class="ml-10 red sm">{{ 
states.tips[index] }}</div>
-    <div v-if="states.tips[index] && isExpression" class="ml-10 red sm">{{ 
states.tips[index] }}</div>
+    <div v-if="(errors || states.tips)[index] && isExpression" class="ml-10 
red sm">
+      {{ (errors || states.tips)[index] }}
+    </div>
+    <div v-if="(subErrors || states.tips)[index] && isExpression" class="ml-10 
red sm">
+      {{ (subErrors || states.tips)[index] }}
+    </div>
   </div>
   <div>{{ t("visualization") }}</div>
   <div class="chart-types">
@@ -102,9 +106,7 @@ limitations under the License. -->
       v-for="(type, index) in setVisTypes"
       :key="index"
       @click="changeChartType(type)"
-      :class="{
-        active: type.value === graph.type,
-      }"
+      :class="{ active: type.value === graph.type }"
     >
       {{ type.label }}
     </span>
@@ -112,6 +114,7 @@ limitations under the License. -->
 </template>
 <script lang="ts" setup>
   import { reactive, ref, computed } from "vue";
+  import type { PropType } from "vue";
   import type { Option } from "@/types/app";
   import { useDashboardStore } from "@/store/modules/dashboard";
   import {
@@ -129,14 +132,23 @@ limitations under the License. -->
   import { ElMessage } from "element-plus";
   import Icon from "@/components/Icon.vue";
   import { useQueryProcessor, useSourceProcessor } from 
"@/hooks/useMetricsProcessor";
-  import { useExpressionsQueryProcessor, useExpressionsSourceProcessor } from 
"@/hooks/useExpressionsProcessor";
+  import { useExpressionsQueryProcessor } from 
"@/hooks/useExpressionsProcessor";
   import { useI18n } from "vue-i18n";
   import type { DashboardItem, MetricConfigOpt } from "@/types/dashboard";
   import Standard from "./Standard.vue";
 
-  /*global defineEmits */
+  /*global defineEmits, Indexable */
   const { t } = useI18n();
   const emit = defineEmits(["update", "loading"]);
+  /*global defineProps */
+  defineProps({
+    errors: {
+      type: Array as PropType<string[]>,
+    },
+    subErrors: {
+      type: Array as PropType<string[]>,
+    },
+  });
   const dashboardStore = useDashboardStore();
   const isExpression = ref<boolean>(dashboardStore.selectedGrid.metricMode === 
MetricModes.Expression ? true : false);
   const metrics = computed(
@@ -398,26 +410,20 @@ limitations under the License. -->
   }
 
   async function queryMetricsWithExpressions() {
-    const { metricConfig, typesOfMQE, expressions } = 
dashboardStore.selectedGrid;
-    if (!(expressions && expressions[0] && typesOfMQE && typesOfMQE[0])) {
+    const { expressions, metricConfig } = dashboardStore.selectedGrid;
+    if (!(expressions && expressions[0])) {
       return emit("update", {});
     }
 
-    const params = useExpressionsQueryProcessor({ ...states, metricConfig });
-    if (!params) {
-      emit("update", {});
-      return;
-    }
+    const params: Indexable = (await useExpressionsQueryProcessor({ ...states, 
metricConfig })) || {};
+    states.tips = params.tips || [];
+    states.metricTypes = params.typesOfMQE || [];
+    dashboardStore.selectWidget({
+      ...dashboardStore.selectedGrid,
+      typesOfMQE: states.metricTypes,
+    });
 
-    emit("loading", true);
-    const json = await dashboardStore.fetchMetricValue(params);
-    emit("loading", false);
-    if (json.errors) {
-      ElMessage.error(json.errors);
-      return;
-    }
-    const source = useExpressionsSourceProcessor(json, { ...states, 
metricConfig });
-    emit("update", source);
+    emit("update", params.source || {});
   }
 
   function changeDashboard(opt: any) {
@@ -554,21 +560,10 @@ limitations under the License. -->
   async function changeExpression(event: any, index: number) {
     const params = (event.target.textContent || "").replace(/\s+/g, "");
 
-    if (params) {
-      const resp = await dashboardStore.getTypeOfMQE(params);
-      states.metrics[index] = params;
-      states.metricTypes[index] = resp.data.metricType.type;
-      states.tips[index] = resp.data.metricType.error || "";
-    } else {
-      states.metrics[index] = params;
-      states.metricTypes[index] = "";
-      states.tips[index] = "";
-    }
-
+    states.metrics[index] = params;
     dashboardStore.selectWidget({
       ...dashboardStore.selectedGrid,
       expressions: states.metrics,
-      typesOfMQE: states.metricTypes,
     });
     if (params) {
       await queryMetrics();
@@ -577,17 +572,7 @@ limitations under the License. -->
   async function changeSubExpression(event: any, index: number) {
     const params = (event.target.textContent || "").replace(/\s+/g, "");
 
-    if (params) {
-      const resp = await dashboardStore.getTypeOfMQE(params);
-      states.subMetrics[index] = params;
-      states.subMetricTypes[index] = resp.data.metricType.type;
-      states.subTips[index] = resp.data.metricType.error || "";
-    } else {
-      states.subMetrics[index] = params;
-      states.subMetricTypes[index] = "";
-      states.subTips[index] = "";
-    }
-
+    states.subMetrics[index] = params;
     dashboardStore.selectWidget({
       ...dashboardStore.selectedGrid,
       subExpressions: states.subMetrics,
@@ -641,8 +626,8 @@ limitations under the License. -->
     border-radius: 3px;
     color: #606266;
     outline: none;
-    height: 26px;
     margin-right: 5px;
+    min-height: 26px;
 
     &:focus {
       border-color: #409eff;
diff --git a/src/views/dashboard/configuration/widget/metric/Standard.vue 
b/src/views/dashboard/configuration/widget/metric/Standard.vue
index 9e4f69a6..5026b972 100644
--- a/src/views/dashboard/configuration/widget/metric/Standard.vue
+++ b/src/views/dashboard/configuration/widget/metric/Standard.vue
@@ -34,7 +34,7 @@ limitations under the License. -->
         class="input"
         v-model="currentMetric.label"
         size="small"
-        placeholder="Please input a name"
+        placeholder="Please input a label"
         @change="
           updateConfig(index, {
             label: encodeURIComponent(currentMetric.label || ''),
@@ -42,13 +42,21 @@ limitations under the License. -->
         "
       />
     </div>
-    <div
-      class="item mb-10"
-      v-if="
-        [ProtocolTypes.ReadLabeledMetricsValues].includes(metricType) &&
-        dashboardStore.selectedGrid.metricMode === MetricModes.General
-      "
-    >
+    <div class="item mb-10" v-if="isList && isExpression">
+      <span class="label">{{ t("detailLabel") }}</span>
+      <el-input
+        class="input"
+        v-model="currentMetric.detailLabel"
+        size="small"
+        placeholder="Please input a label"
+        @change="
+          updateConfig(index, {
+            detailLabel: encodeURIComponent(currentMetric.detailLabel || ''),
+          })
+        "
+      />
+    </div>
+    <div class="item mb-10" 
v-if="[ProtocolTypes.ReadLabeledMetricsValues].includes(metricType) && 
!isExpression">
       <span class="label">{{ t("labelsIndex") }}</span>
       <el-input
         class="input"
@@ -136,6 +144,10 @@ limitations under the License. -->
       ].includes(metricType.value)
     );
   });
+  const isList = computed(() => {
+    const graph = dashboardStore.selectedGrid.graph || {};
+    return ListChartTypes.includes(graph.type);
+  });
   const isTopn = computed(() =>
     [ProtocolTypes.SortMetrics, ProtocolTypes.ReadSampledRecords, 
ProtocolTypes.ReadRecords].includes(
       metricTypes.value[props.index],
@@ -162,6 +174,7 @@ limitations under the License. -->
   watch(
     () => props.currentMetricConfig,
     () => {
+      isExpression.value = dashboardStore.selectedGrid.metricMode === 
MetricModes.Expression;
       currentMetric.value = {
         ...props.currentMetricConfig,
         topN: Number(props.currentMetricConfig.topN) || 10,
diff --git a/src/views/dashboard/controls/Widget.vue 
b/src/views/dashboard/controls/Widget.vue
index 0f36affd..423b9c51 100644
--- a/src/views/dashboard/controls/Widget.vue
+++ b/src/views/dashboard/controls/Widget.vue
@@ -82,7 +82,7 @@ limitations under the License. -->
   import graphs from "../graphs";
   import { useI18n } from "vue-i18n";
   import { useQueryProcessor, useSourceProcessor } from 
"@/hooks/useMetricsProcessor";
-  import { useExpressionsQueryProcessor, useExpressionsSourceProcessor } from 
"@/hooks/useExpressionsProcessor";
+  import { useExpressionsQueryProcessor } from 
"@/hooks/useExpressionsProcessor";
   import { EntityType, ListChartTypes } from "../data";
   import type { EventParams } from "@/types/dashboard";
   import getDashboard from "@/hooks/useDashboardsSession";
@@ -121,13 +121,18 @@ limitations under the License. -->
 
       async function queryMetrics() {
         const isExpression = props.data.metricMode === MetricModes.Expression;
-        const params = isExpression
-          ? await useExpressionsQueryProcessor({
-              metrics: props.data.expressions,
-              metricTypes: props.data.typesOfMQE,
-              metricConfig: props.data.metricConfig,
-            })
-          : await useQueryProcessor({ ...props.data });
+        if (isExpression) {
+          loading.value = true;
+          const e = {
+            metrics: props.data.expressions || [],
+            metricConfig: props.data.metricConfig || [],
+          };
+          const params = (await useExpressionsQueryProcessor(e)) || {};
+          loading.value = false;
+          state.source = params.source || {};
+          return;
+        }
+        const params = await useQueryProcessor({ ...props.data });
 
         if (!params) {
           state.source = {};
@@ -144,12 +149,7 @@ limitations under the License. -->
           metricTypes: props.data.metricTypes || [],
           metricConfig: props.data.metricConfig || [],
         };
-        const e = {
-          metrics: props.data.expressions || [],
-          metricTypes: props.data.typesOfMQE || [],
-          metricConfig: props.data.metricConfig || [],
-        };
-        state.source = isExpression ? await 
useExpressionsSourceProcessor(json, e) : await useSourceProcessor(json, d);
+        state.source = await useSourceProcessor(json, d);
       }
 
       function removeWidget() {
diff --git a/src/views/dashboard/graphs/EndpointList.vue 
b/src/views/dashboard/graphs/EndpointList.vue
index c3653dec..97f06a2a 100644
--- a/src/views/dashboard/graphs/EndpointList.vue
+++ b/src/views/dashboard/graphs/EndpointList.vue
@@ -96,6 +96,7 @@ limitations under the License. -->
     intervalTime: { type: Array as PropType<string[]>, default: () => [] },
   });
 
+  const emit = defineEmits(["expressionTips"]);
   const { t } = useI18n();
   const selectorStore = useSelectorStore();
   const dashboardStore = useDashboardStore();
@@ -168,13 +169,12 @@ limitations under the License. -->
   }
   async function queryEndpointExpressions(currentPods: Endpoint[]) {
     const expressions = props.config.expressions || [];
-    const typesOfMQE = props.config.typesOfMQE || [];
     const subExpressions = props.config.subExpressions || [];
 
-    if (expressions.length && expressions[0] && typesOfMQE.length && 
typesOfMQE[0]) {
+    if (expressions.length && expressions[0]) {
       const params = await useExpressionsQueryPodsMetrics(
         currentPods,
-        { ...props.config, metricConfig: metricConfig.value || [], typesOfMQE, 
expressions, subExpressions },
+        { metricConfig: metricConfig.value || [], expressions, subExpressions 
},
         EntityType[2].value,
       );
       endpoints.value = params.data;
@@ -182,6 +182,7 @@ limitations under the License. -->
       metricTypes.value = params.metricTypesArr;
       metricConfig.value = params.metricConfigArr;
       colSubMetrics.value = params.colSubMetrics;
+      emit("expressionTips", { tips: params.expressionsTips, subTips: 
params.subExpressionsTips });
 
       return;
     }
@@ -190,6 +191,7 @@ limitations under the License. -->
     colSubMetrics.value = [];
     metricTypes.value = [];
     metricConfig.value = [];
+    emit("expressionTips", [], []);
   }
   function clickEndpoint(scope: any) {
     const { dashboard } = getDashboard({
diff --git a/src/views/dashboard/graphs/InstanceList.vue 
b/src/views/dashboard/graphs/InstanceList.vue
index f3b32dca..4bf74e3f 100644
--- a/src/views/dashboard/graphs/InstanceList.vue
+++ b/src/views/dashboard/graphs/InstanceList.vue
@@ -122,6 +122,7 @@ limitations under the License. -->
     intervalTime: { type: Array as PropType<string[]>, default: () => [] },
     needQuery: { type: Boolean, default: false },
   });
+  const emit = defineEmits(["expressionTips"]);
   const { t } = useI18n();
   const selectorStore = useSelectorStore();
   const dashboardStore = useDashboardStore();
@@ -193,6 +194,7 @@ limitations under the License. -->
       colMetrics.value = names;
       metricTypes.value = metricTypesArr;
       metricConfig.value = metricConfigArr;
+
       return;
     }
     instances.value = currentInstances;
@@ -203,13 +205,12 @@ limitations under the License. -->
 
   async function queryInstanceExpressions(currentInstances: Instance[]) {
     const expressions = props.config.expressions || [];
-    const typesOfMQE = props.config.typesOfMQE || [];
     const subExpressions = props.config.subExpressions || [];
 
-    if (expressions.length && expressions[0] && typesOfMQE.length && 
typesOfMQE[0]) {
+    if (expressions.length && expressions[0]) {
       const params = await useExpressionsQueryPodsMetrics(
         currentInstances,
-        { ...props.config, metricConfig: metricConfig.value || [], typesOfMQE, 
expressions, subExpressions },
+        { metricConfig: metricConfig.value || [], expressions, subExpressions 
},
         EntityType[3].value,
       );
       instances.value = params.data;
@@ -217,6 +218,7 @@ limitations under the License. -->
       colSubMetrics.value = params.colSubMetrics;
       metricTypes.value = params.metricTypesArr;
       metricConfig.value = params.metricConfigArr;
+      emit("expressionTips", { tips: params.expressionsTips, subTips: 
params.subExpressionsTips });
 
       return;
     }
@@ -225,6 +227,7 @@ limitations under the License. -->
     colMetrics.value = [];
     metricTypes.value = [];
     metricConfig.value = [];
+    emit("expressionTips", [], []);
   }
 
   function clickInstance(scope: any) {
diff --git a/src/views/dashboard/graphs/ServiceList.vue 
b/src/views/dashboard/graphs/ServiceList.vue
index 83e27c70..787602f0 100644
--- a/src/views/dashboard/graphs/ServiceList.vue
+++ b/src/views/dashboard/graphs/ServiceList.vue
@@ -114,6 +114,7 @@ limitations under the License. -->
     intervalTime: { type: Array as PropType<string[]>, default: () => [] },
     isEdit: { type: Boolean, default: false },
   });
+  const emit = defineEmits(["expressionTips"]);
   const selectorStore = useSelectorStore();
   const dashboardStore = useDashboardStore();
   const appStore = useAppStoreWithOut();
@@ -251,13 +252,12 @@ limitations under the License. -->
   }
   async function queryServiceExpressions(currentServices: Service[]) {
     const expressions = props.config.expressions || [];
-    const typesOfMQE = props.config.typesOfMQE || [];
     const subExpressions = props.config.subExpressions || [];
 
-    if (expressions.length && expressions[0] && typesOfMQE.length && 
typesOfMQE[0]) {
+    if (expressions.length && expressions[0]) {
       const params = await useExpressionsQueryPodsMetrics(
         currentServices,
-        { ...props.config, metricConfig: metricConfig.value || [], typesOfMQE, 
expressions, subExpressions },
+        { metricConfig: metricConfig.value || [], expressions, subExpressions 
},
         EntityType[0].value,
       );
       services.value = params.data;
@@ -265,6 +265,7 @@ limitations under the License. -->
       colSubMetrics.value = params.subNames;
       metricTypes.value = params.metricTypesArr;
       metricConfig.value = params.metricConfigArr;
+      emit("expressionTips", { tips: params.expressionsTips, subTips: 
params.subExpressionsTips });
       return;
     }
     services.value = currentServices;
@@ -272,6 +273,7 @@ limitations under the License. -->
     colSubMetrics.value = [];
     metricTypes.value = [];
     metricConfig.value = [];
+    emit("expressionTips", [], []);
   }
   function objectSpanMethod(param: any): any {
     if (!props.config.showGroup) {
diff --git a/src/views/dashboard/graphs/components/ColumnGraph.vue 
b/src/views/dashboard/graphs/components/ColumnGraph.vue
index d3b8fe76..4eae8c89 100644
--- a/src/views/dashboard/graphs/components/ColumnGraph.vue
+++ b/src/views/dashboard/graphs/components/ColumnGraph.vue
@@ -48,7 +48,7 @@ limitations under the License. -->
             <div class="view-line">
               <Line
                 :data="{
-                  [colSubMetrics[index] || metric]:
+                  [decodeURIComponent(getLabel(colSubMetrics[index], index, 
true)) || metric]:
                     scope.row[colSubMetrics[index] || metric] && 
scope.row[colSubMetrics[index] || metric].values,
                 }"
                 :intervalTime="intervalTime"
@@ -109,9 +109,15 @@ limitations under the License. -->
     }
     return encodeURIComponent("");
   }
-  function getLabel(metric: string, index: number) {
+  function getLabel(metric: string, index: number, isDetail?: boolean) {
     const i = Number(index);
-    const label = props.config.metricConfig && props.config.metricConfig[i] && 
props.config.metricConfig[i].label;
+    let label = "";
+    if (isDetail) {
+      label =
+        (props.config.metricConfig && props.config.metricConfig[i] && 
props.config.metricConfig[i].detailLabel) || "";
+    } else {
+      label = (props.config.metricConfig && props.config.metricConfig[i] && 
props.config.metricConfig[i].label) || "";
+    }
     if (label) {
       if (
         (
@@ -129,7 +135,7 @@ limitations under the License. -->
       }
       return encodeURIComponent(label);
     }
-    return encodeURIComponent(metric);
+    return encodeURIComponent(metric || "");
   }
 </script>
 <style lang="scss" scoped>


Reply via email to