diff --git a/src/hooks/useExpressionsProcessor.ts b/src/hooks/useExpressionsProcessor.ts index 786184f7..448549d0 100644 --- a/src/hooks/useExpressionsProcessor.ts +++ b/src/hooks/useExpressionsProcessor.ts @@ -23,122 +23,136 @@ 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( 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/metric/Index.vue b/src/views/dashboard/configuration/widget/metric/Index.vue index 59cc5636..a129fa9d 100644 --- a/src/views/dashboard/configuration/widget/metric/Index.vue +++ b/src/views/dashboard/configuration/widget/metric/Index.vue @@ -127,12 +127,12 @@ 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"]); const dashboardStore = useDashboardStore(); @@ -396,26 +396,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) { @@ -551,23 +545,22 @@ limitations under the License. --> } async function changeExpression(event: any, index: number) { const params = (event.target.textContent || "").replace(/\s+/g, ""); - console.log(params); if (params) { - const resp = await dashboardStore.getTypeOfMQE(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 || ""; + // 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.metricTypes[index] = ""; + // states.tips[index] = ""; } dashboardStore.selectWidget({ ...dashboardStore.selectedGrid, expressions: states.metrics, - typesOfMQE: states.metricTypes, + // typesOfMQE: states.metricTypes, }); if (params) { await queryMetrics(); 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() {