mirror of
https://github.com/openobserve/openobserve.git
synced 2026-11-04 16:09:05 +00:00
fix: histogram no data availavble fix (#13020)
This commit is contained in:
@@ -16,6 +16,7 @@ import { computed, ref } from "vue";
|
||||
|
||||
// Canonical keys for every pinnable item in the logs More menu.
|
||||
export type ToolbarPinKey =
|
||||
| "histogram"
|
||||
| "sqlMode"
|
||||
| "quickMode"
|
||||
| "functionEditor"
|
||||
@@ -25,6 +26,7 @@ export type ToolbarPinKey =
|
||||
// Fixed left-to-right render order for pinned controls. Pinning never changes an
|
||||
// item's position — it only toggles whether the item is shown outside the menu.
|
||||
export const TOOLBAR_PIN_ORDER: ToolbarPinKey[] = [
|
||||
"histogram",
|
||||
"sqlMode",
|
||||
"quickMode",
|
||||
"functionEditor",
|
||||
@@ -34,18 +36,32 @@ export const TOOLBAR_PIN_ORDER: ToolbarPinKey[] = [
|
||||
|
||||
const STORAGE_KEY = "logs_toolbar_pinned_items";
|
||||
|
||||
// Histogram was a fixed toolbar control before it became pinnable, so it is
|
||||
// pinned by default. Its absence from STORAGE_KEY (including arrays persisted
|
||||
// before histogram existed as a pin key) means "never decided", not "unpinned" —
|
||||
// this flag records the user's first explicit pin/unpin of histogram, after
|
||||
// which STORAGE_KEY alone is authoritative.
|
||||
const HISTOGRAM_PIN_DECIDED_KEY = "logs_toolbar_histogram_pin_decided";
|
||||
|
||||
const isValidKey = (key: string): key is ToolbarPinKey =>
|
||||
(TOOLBAR_PIN_ORDER as string[]).includes(key);
|
||||
|
||||
const readInitial = (): ToolbarPinKey[] => {
|
||||
try {
|
||||
const raw = window.localStorage.getItem(STORAGE_KEY);
|
||||
if (!raw) return [];
|
||||
const parsed = JSON.parse(raw);
|
||||
if (!Array.isArray(parsed)) return [];
|
||||
return parsed.filter((k): k is ToolbarPinKey => typeof k === "string" && isValidKey(k));
|
||||
const parsed = raw ? JSON.parse(raw) : [];
|
||||
const pins: ToolbarPinKey[] = Array.isArray(parsed)
|
||||
? parsed.filter(
|
||||
(k): k is ToolbarPinKey => typeof k === "string" && isValidKey(k),
|
||||
)
|
||||
: [];
|
||||
const histogramDecided =
|
||||
window.localStorage.getItem(HISTOGRAM_PIN_DECIDED_KEY) === "true";
|
||||
if (!histogramDecided && !pins.includes("histogram"))
|
||||
pins.push("histogram");
|
||||
return pins;
|
||||
} catch {
|
||||
return [];
|
||||
return ["histogram"];
|
||||
}
|
||||
};
|
||||
|
||||
@@ -72,6 +88,13 @@ export function useToolbarPins() {
|
||||
if (next.has(key)) next.delete(key);
|
||||
else next.add(key);
|
||||
pinnedSet.value = next;
|
||||
if (key === "histogram") {
|
||||
try {
|
||||
window.localStorage.setItem(HISTOGRAM_PIN_DECIDED_KEY, "true");
|
||||
} catch {
|
||||
// localStorage may be unavailable — the default-pinned fallback reapplies next session.
|
||||
}
|
||||
}
|
||||
persist();
|
||||
};
|
||||
|
||||
|
||||
@@ -126,9 +126,14 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
<OTooltip :content="t('search.resetFilters')" />
|
||||
</OButton>
|
||||
|
||||
<!-- Histogram toggle — moves into More menu below 328px available width -->
|
||||
<!-- ── Pinned toolbar controls ──────────────────────────────────
|
||||
Items pinned out of the More menu render here in fixed order.
|
||||
They collapse back into the menu on narrow widths (see
|
||||
showPinned*/pin* computeds). -->
|
||||
|
||||
<!-- Histogram (pinned by default — see useToolbarPins) -->
|
||||
<OButton
|
||||
v-if="!shouldMoveButtonsToMenu"
|
||||
v-if="showPinnedHistogram"
|
||||
data-test="logs-search-bar-histogram-btn"
|
||||
size="xs"
|
||||
variant="outline"
|
||||
@@ -144,11 +149,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
<OTooltip :content="searchObj.meta.showHistogram ? t('search.hideHistogram') : t('search.showHistogramLabel')" shortcut-id="logsToggleHistogram" />
|
||||
</OButton>
|
||||
|
||||
<!-- ── Pinned toolbar controls ──────────────────────────────────
|
||||
Items pinned out of the More menu render here in fixed order.
|
||||
They collapse back into the menu on narrow widths (see
|
||||
showPinned*/pin* computeds). -->
|
||||
|
||||
<!-- SQL Mode (pinned) -->
|
||||
<OButton
|
||||
v-if="showPinnedSqlMode"
|
||||
@@ -291,9 +291,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
{{ t("search.resetFilters") }}
|
||||
</ODropdownItem>
|
||||
|
||||
<!-- Histogram (shown here only when toolbar is too narrow for inline button) -->
|
||||
<!-- Histogram — pinned copy renders on the toolbar -->
|
||||
<ODropdownItem
|
||||
v-if="shouldMoveButtonsToMenu"
|
||||
data-test="logs-search-bar-menu-histogram-btn"
|
||||
@select.prevent="searchObj.meta.showHistogram = !searchObj.meta.showHistogram"
|
||||
>
|
||||
@@ -304,13 +303,23 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
</template>
|
||||
{{ t("search.showHistogramLabel") }}
|
||||
<template #icon-right>
|
||||
<OSwitch
|
||||
v-model="searchObj.meta.showHistogram"
|
||||
size="md"
|
||||
data-test="logs-search-bar-show-histogram-toggle-btn"
|
||||
class="tw:ml-auto"
|
||||
@click.stop
|
||||
/>
|
||||
<span class="tw:ml-auto tw:flex tw:items-center tw:gap-1">
|
||||
<OSwitch
|
||||
v-model="searchObj.meta.showHistogram"
|
||||
size="md"
|
||||
data-test="logs-search-bar-show-histogram-toggle-btn"
|
||||
@click.stop
|
||||
/>
|
||||
<OButton
|
||||
data-test="logs-search-bar-menu-pin-histogram-btn"
|
||||
variant="ghost-neutral"
|
||||
size="icon-sm"
|
||||
:title="isPinned('histogram') ? t('search.unpinFromToolbar') : t('search.pinToToolbar')"
|
||||
@click.stop="togglePin('histogram')"
|
||||
>
|
||||
<OIcon :name="isPinned('histogram') ? 'keep' : 'keep-outline'" size="sm" />
|
||||
</OButton>
|
||||
</span>
|
||||
</template>
|
||||
</ODropdownItem>
|
||||
|
||||
@@ -2404,35 +2413,33 @@ export default defineComponent({
|
||||
// Each threshold has a small buffer (+16px) so collapse fires before clipping.
|
||||
const shouldHideToolbarButtonText = computed(() => availableLeftWidth.value < 720);
|
||||
const toolbarToggleIconOnly = computed(() => availableLeftWidth.value < 568);
|
||||
const shouldMoveButtonsToMenu = computed(() => availableLeftWidth.value < 328);
|
||||
const toolbarMoveResetToMenu = computed(() => availableLeftWidth.value < 248);
|
||||
const toolbarToggleAsDropdown = computed(() => availableLeftWidth.value < 176);
|
||||
|
||||
// ── Pinned toolbar items ──────────────────────────────────────────────
|
||||
// Items pinned out of the "More" menu render as fixed-position toolbar
|
||||
// controls. They share the left section with the toggle group / reset /
|
||||
// histogram, so we allocate the leftover width to pinned items with a running
|
||||
// budget: the More button is always reserved, then pinned items are kept in
|
||||
// priority order (sql mode kept longest, syntax guide dropped first).
|
||||
// controls. They share the left section with the toggle group / reset, so we
|
||||
// allocate the leftover width to pinned items with a running budget: the More
|
||||
// button is always reserved, then pinned items are kept in priority order
|
||||
// (histogram kept longest, syntax guide dropped first).
|
||||
const { isPinned, togglePin } = useToolbarPins();
|
||||
|
||||
// Approximate rendered widths (px) of each pinned control and of the fixed
|
||||
// left-section content, used only to decide how many pinned items fit before
|
||||
// they would clip. Hidden pinned items stay reachable inside the More menu.
|
||||
const PIN_ITEM_WIDTH = { sqlMode: 46, quickMode: 46, savedViews: 62 };
|
||||
const PIN_ITEM_WIDTH = { histogram: 46, sqlMode: 46, quickMode: 46, savedViews: 62 };
|
||||
const SYNTAX_GUIDE_LABEL_WIDTH = 108;
|
||||
const SYNTAX_GUIDE_ICON_WIDTH = 40;
|
||||
const PIN_ITEM_GAP = 4;
|
||||
|
||||
// Width consumed by the always-present left content (toggle group in its
|
||||
// current collapse state, reset, histogram) plus the reserved More button.
|
||||
// current collapse state, reset) plus the reserved More button.
|
||||
const baseReservedWidth = computed(() => {
|
||||
let w = 0;
|
||||
if (toolbarToggleAsDropdown.value) w += 120;
|
||||
else if (toolbarToggleIconOnly.value) w += 190;
|
||||
else w += 350;
|
||||
if (!toolbarMoveResetToMenu.value) w += shouldHideToolbarButtonText.value ? 40 : 88;
|
||||
if (!shouldMoveButtonsToMenu.value) w += 64; // histogram button
|
||||
w += 92; // More button (always visible)
|
||||
w += 24; // inter-item gaps / padding buffer
|
||||
return w;
|
||||
@@ -2448,6 +2455,7 @@ export default defineComponent({
|
||||
const budget = pinBudget.value;
|
||||
let used = 0;
|
||||
const res = {
|
||||
histogram: false,
|
||||
sqlMode: false,
|
||||
quickMode: false,
|
||||
savedViews: false,
|
||||
@@ -2462,6 +2470,7 @@ export default defineComponent({
|
||||
}
|
||||
return false;
|
||||
};
|
||||
if (isPinned("histogram")) res.histogram = tryFit(PIN_ITEM_WIDTH.histogram);
|
||||
if (isPinned("sqlMode")) res.sqlMode = tryFit(PIN_ITEM_WIDTH.sqlMode);
|
||||
if (isPinned("quickMode")) res.quickMode = tryFit(PIN_ITEM_WIDTH.quickMode);
|
||||
if (isPinned("savedViews")) res.savedViews = tryFit(PIN_ITEM_WIDTH.savedViews);
|
||||
@@ -2478,6 +2487,7 @@ export default defineComponent({
|
||||
|
||||
// Function editor lives on the right toolbar (next to the date picker), so it
|
||||
// is not part of the left-section budget.
|
||||
const showPinnedHistogram = computed(() => pinnedVisibility.value.histogram);
|
||||
const showPinnedSqlMode = computed(() => pinnedVisibility.value.sqlMode);
|
||||
const showPinnedQuickMode = computed(() => pinnedVisibility.value.quickMode);
|
||||
const showPinnedFunctionEditor = computed(() => isPinned("functionEditor"));
|
||||
@@ -5217,12 +5227,12 @@ export default defineComponent({
|
||||
toolbarRightRef,
|
||||
shouldHideToolbarButtonText,
|
||||
toolbarToggleIconOnly,
|
||||
shouldMoveButtonsToMenu,
|
||||
toolbarMoveResetToMenu,
|
||||
toolbarToggleAsDropdown,
|
||||
isPinned,
|
||||
togglePin,
|
||||
pinSyntaxGuideIconOnly,
|
||||
showPinnedHistogram,
|
||||
showPinnedSqlMode,
|
||||
showPinnedQuickMode,
|
||||
showPinnedFunctionEditor,
|
||||
|
||||
@@ -349,22 +349,21 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="histogram-empty"
|
||||
data-test="logs-search-no-data-histogram"
|
||||
<!-- Same no-data treatment as dashboard panels (PanelSchemaRenderer);
|
||||
inline min-height/padding overridden to fit the 6.25rem strip. -->
|
||||
<OEmptyState
|
||||
v-else-if="
|
||||
searchObj.meta.showHistogram &&
|
||||
!searchObj.loadingHistogram &&
|
||||
!searchObj.loading
|
||||
"
|
||||
>
|
||||
<h6 class="tw:text-center">
|
||||
<span class="histogram-empty__message">
|
||||
<OIcon name="warning" size="xs"></OIcon> No
|
||||
data found for histogram.</span
|
||||
>
|
||||
</h6>
|
||||
</div>
|
||||
size="inline"
|
||||
icon="bar-chart"
|
||||
title="No Data"
|
||||
:backdrop="false"
|
||||
data-test="logs-search-no-data-histogram"
|
||||
class="histogram-empty tw:!min-h-0 tw:!p-2"
|
||||
/>
|
||||
|
||||
<div
|
||||
class="histogram-empty"
|
||||
@@ -710,6 +709,7 @@ import OPagination from "@/lib/navigation/Pagination/OPagination.vue";
|
||||
import ODropdown from "@/lib/overlay/Dropdown/ODropdown.vue";
|
||||
import ODropdownItem from "@/lib/overlay/Dropdown/ODropdownItem.vue";
|
||||
import OTag from "@/lib/core/Badge/OTag.vue";
|
||||
import OEmptyState from "@/lib/core/EmptyState/OEmptyState.vue";
|
||||
import LoadingProgress from "@/components/common/LoadingProgress.vue";
|
||||
import { toast } from "@/lib/feedback/Toast/useToast";
|
||||
|
||||
@@ -723,6 +723,7 @@ export default defineComponent({
|
||||
OTooltip,
|
||||
OSelect,
|
||||
OPagination,
|
||||
OEmptyState,
|
||||
LoadingProgress,
|
||||
DetailTable: defineAsyncComponent(() => import("./DetailTable.vue")),
|
||||
ChartRenderer: defineAsyncComponent(
|
||||
|
||||
Reference in New Issue
Block a user