mirror of
https://github.com/openobserve/openobserve.git
synced 2026-11-06 00:09:22 +00:00
fix: dashboard no data issue (#11840)
This commit is contained in:
@@ -1333,117 +1333,68 @@ export default defineComponent({
|
||||
}
|
||||
};
|
||||
|
||||
const handleNoData = (panelType: any) => {
|
||||
const xAlias = panelSchema.value.queries[0].fields.x.map(
|
||||
(it: any) => it.alias || [],
|
||||
);
|
||||
const yAlias = panelSchema.value.queries[0].fields.y.map(
|
||||
(it: any) => it.alias || [],
|
||||
);
|
||||
const zAlias = panelSchema.value.queries[0].fields.z.map(
|
||||
(it: any) => it.alias || [],
|
||||
);
|
||||
|
||||
const firstRow = data.value[0]?.[0];
|
||||
|
||||
switch (panelType) {
|
||||
case "area":
|
||||
case "area-stacked":
|
||||
case "bar":
|
||||
case "h-bar":
|
||||
case "stacked":
|
||||
case "h-stacked":
|
||||
case "line":
|
||||
case "scatter":
|
||||
case "gauge": {
|
||||
return (
|
||||
data.value[0]?.length > 1 ||
|
||||
(xAlias.every((x: any) => getDataValue(firstRow, x) != null) &&
|
||||
yAlias.every((y: any) => getDataValue(firstRow, y) != null))
|
||||
);
|
||||
}
|
||||
case "table": {
|
||||
// For tables, simply check if there's any data in the array
|
||||
return (
|
||||
data.value[0]?.length > 1 ||
|
||||
(data.value[0]?.length == 1 &&
|
||||
(xAlias.some((x: any) => getDataValue(firstRow, x) != null) ||
|
||||
yAlias.some((y: any) => getDataValue(firstRow, y) != null)))
|
||||
);
|
||||
}
|
||||
case "metric": {
|
||||
return (
|
||||
data.value[0]?.length > 1 ||
|
||||
yAlias.every((y: any) => getDataValue(firstRow, y) != null)
|
||||
);
|
||||
}
|
||||
case "heatmap": {
|
||||
return (
|
||||
data.value[0]?.length > 1 ||
|
||||
(xAlias.every((x: any) => getDataValue(firstRow, x) != null) &&
|
||||
yAlias.every((y: any) => getDataValue(firstRow, y) != null) &&
|
||||
zAlias.every((z: any) => getDataValue(firstRow, z) != null))
|
||||
);
|
||||
}
|
||||
case "pie":
|
||||
case "donut": {
|
||||
return (
|
||||
data.value[0]?.length > 1 ||
|
||||
yAlias.every((y: any) => getDataValue(firstRow, y) != null)
|
||||
);
|
||||
}
|
||||
case "maps":
|
||||
case "geomap": {
|
||||
return true;
|
||||
}
|
||||
case "sankey": {
|
||||
const source = panelSchema.value.queries[0].fields.source.alias;
|
||||
const target = panelSchema.value.queries[0].fields.target.alias;
|
||||
const value = panelSchema.value.queries[0].fields.value.alias;
|
||||
return (
|
||||
data.value[0]?.length > 1 ||
|
||||
source.every((s: any) => getDataValue(firstRow, s) != null) ||
|
||||
target.every((t: any) => getDataValue(firstRow, t) != null) ||
|
||||
value.every((v: any) => getDataValue(firstRow, v) != null)
|
||||
);
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
// Compute the value of the 'noData' variable
|
||||
// Compute the value of the 'noData' variable.
|
||||
// Instead of re-scanning raw rows, this checks the conversion output
|
||||
// (panelData) which the pipeline already computed — O(1) property access.
|
||||
const noData = computed(() => {
|
||||
// if panel type is 'html' or 'markdown', return an empty string
|
||||
if (
|
||||
panelSchema.value.type == "html" ||
|
||||
panelSchema.value.type == "markdown" ||
|
||||
panelSchema.value.type == "custom_chart"
|
||||
) {
|
||||
const type = panelSchema.value.type;
|
||||
|
||||
if (type === "html" || type === "markdown" || type === "custom_chart") {
|
||||
return "";
|
||||
}
|
||||
// Check if the queryType is 'promql'
|
||||
if (panelSchema.value?.queryType == "promql") {
|
||||
// Check if the 'filteredData' array has elements and every item has a non-empty 'result' array
|
||||
|
||||
if (panelSchema.value?.queryType === "promql") {
|
||||
return filteredData.value?.length &&
|
||||
filteredData.value.some((item: any) => item?.result?.length)
|
||||
? "" // Return an empty string if there is data
|
||||
: "No Data"; // Return "No Data" if there is no data
|
||||
? ""
|
||||
: "No Data";
|
||||
}
|
||||
|
||||
// A rendered chart is already on screen — suppress "No Data" even if
|
||||
// the raw data buffer is momentarily empty. This prevents a flicker on
|
||||
// refresh where the executor resets state.data = [] before loading
|
||||
// flips to true, transiently firing this computed with empty data.
|
||||
if (panelData.value?.options?.series?.length > 0) {
|
||||
const hasRawData = data.value?.length && data.value[0]?.length;
|
||||
|
||||
// During data buffer reset (executor clears state.data before reload),
|
||||
// suppress "No Data" only while still loading to avoid flicker.
|
||||
// Once loading completes with empty data, show "No Data".
|
||||
if (!hasRawData) {
|
||||
return loading.value && panelData.value?.chartType ? "" : "No Data";
|
||||
}
|
||||
|
||||
// Raw data exists but conversion hasn't produced output yet — wait.
|
||||
if (!panelData.value?.chartType) {
|
||||
return "";
|
||||
}
|
||||
// The queryType is not 'promql'
|
||||
return data.value.length &&
|
||||
data.value[0]?.length &&
|
||||
handleNoData(panelSchema.value.type)
|
||||
? ""
|
||||
: "No Data"; // Return "No Data" if the 'data' array is empty, otherwise return an empty string
|
||||
|
||||
// Table renders raw rows; the conversion returns { rows, columns }.
|
||||
if (type === "table") {
|
||||
return panelData.value?.rows?.length > 0 ? "" : "No Data";
|
||||
}
|
||||
|
||||
// Maps/geomap handle their own empty state.
|
||||
if (type === "geomap" || type === "maps") {
|
||||
return "";
|
||||
}
|
||||
|
||||
// Sankey returns { options: null } when data is invalid.
|
||||
if (type === "sankey") {
|
||||
return panelData.value?.options != null ? "" : "No Data";
|
||||
}
|
||||
|
||||
// Metric/gauge series are always created by the converter
|
||||
// (they use renderItem, not data arrays), so check the raw Y value.
|
||||
if (type === "metric" || type === "gauge") {
|
||||
const firstRow = data.value[0]?.[0];
|
||||
const yAlias = panelSchema.value.queries[0].fields.y.map(
|
||||
(it: any) => it.alias || [],
|
||||
);
|
||||
return yAlias.every((y: any) => getDataValue(firstRow, y) != null)
|
||||
? ""
|
||||
: "No Data";
|
||||
}
|
||||
|
||||
// For all other chart types (line, area, bar, scatter, heatmap, etc.),
|
||||
// the series filter in the conversion pipeline already excluded series
|
||||
// whose data is entirely null. Just check what survived.
|
||||
return panelData.value?.options?.series?.length > 0 ? "" : "No Data";
|
||||
});
|
||||
|
||||
// when the error changes, emit the error
|
||||
|
||||
Reference in New Issue
Block a user