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, + 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 `expression${index}: execExpression(expression: $expression${index}, entity: $entity${index}, duration: $duration)${RespFields.execExpression}`; + }); + const queryStr = `query queryData(${variables}) {${fragment}}`; + + return { + queryStr, + conditions, }; - conditions[`entity${index}`] = entity; - - return `expression${index}: execExpression(expression: $expression${index}, entity: $entity${index}, duration: $duration)${RespFields.execExpression}`; - }); - const queryStr = `query queryData(${variables}) {${fragment}}`; - - return { - queryStr, - conditions, - }; -} - -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 {}; - } - 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: [] }; } - return source; + 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 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" />
{{ t("noData") }} @@ -54,7 +55,7 @@ limitations under the License. -->
- + @@ -102,6 +103,8 @@ limitations under the License. --> const dashboardStore = useDashboardStore(); const appStoreWithOut = useAppStoreWithOut(); const loading = ref(false); + const errors = ref([]); + const subErrors = ref([]); 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" />
- Summary - Detail + {{ t("summary") }} + {{ t("detail") }}
@@ -93,8 +93,12 @@ limitations under the License. --> /> -
{{ states.tips[index] }}
-
{{ states.tips[index] }}
+
+ {{ (errors || states.tips)[index] }} +
+
+ {{ (subErrors || states.tips)[index] }} +
{{ t("visualization") }}
@@ -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 }} @@ -112,6 +114,7 @@ limitations under the License. -->