diff --git a/web-common/src/components/CellInspector.svelte b/web-common/src/components/CellInspector.svelte index 2431ccfd5c7..03e2e1d3b61 100644 --- a/web-common/src/components/CellInspector.svelte +++ b/web-common/src/components/CellInspector.svelte @@ -21,7 +21,8 @@ // Subscribe to the cellInspectorStore to keep the component in sync const unsubscribe = cellInspectorStore.subscribe((state) => { isOpen = state.isOpen; - if (state.value && state.isOpen && !isLocked) { + // Update value when open and not locked, and a value has been set via hover + if (state.isOpen && !isLocked && state.hasValue) { value = state.value; } }); @@ -175,7 +176,9 @@ class:items-center={!isJson} > {#if value === null} - No value + null + {:else if value === ""} + (empty string) {:else} diff --git a/web-common/src/components/virtualized-table/core/Cell.svelte b/web-common/src/components/virtualized-table/core/Cell.svelte index baaf4df4498..19f0df7c7d4 100644 --- a/web-common/src/components/virtualized-table/core/Cell.svelte +++ b/web-common/src/components/virtualized-table/core/Cell.svelte @@ -48,10 +48,7 @@ function onFocus() { onInspect(row.index); cellActive = true; - // Update the cell inspector store with the cell value - if (value !== undefined && value !== null) { - cellInspectorStore.updateValue(value.toString()); - } + cellInspectorStore.updateValue(value); } function onSelect(e: MouseEvent) { diff --git a/web-common/src/features/canvas/components/kpi/KPI.svelte b/web-common/src/features/canvas/components/kpi/KPI.svelte index de6165f9186..dbc1a637b14 100644 --- a/web-common/src/features/canvas/components/kpi/KPI.svelte +++ b/web-common/src/features/canvas/components/kpi/KPI.svelte @@ -89,29 +89,21 @@ function handleBigNumberMouseOver() { const displayValue = hoveredPoints?.[0]?.value != null ? currentValue : primaryTotal; - if (displayValue !== undefined && displayValue !== null) { - cellInspectorStore.updateValue(displayValue.toString()); - } + cellInspectorStore.updateValue(displayValue); } function handleBigNumberFocus() { const displayValue = hoveredPoints?.[0]?.value != null ? currentValue : primaryTotal; - if (displayValue !== undefined && displayValue !== null) { - cellInspectorStore.updateValue(displayValue.toString()); - } + cellInspectorStore.updateValue(displayValue); } function handleComparisonMouseOver() { - if (comparisonVal !== undefined && comparisonVal !== null) { - cellInspectorStore.updateValue(comparisonVal.toString()); - } + cellInspectorStore.updateValue(comparisonVal); } function handleComparisonFocus() { - if (comparisonVal !== undefined && comparisonVal !== null) { - cellInspectorStore.updateValue(comparisonVal.toString()); - } + cellInspectorStore.updateValue(comparisonVal); } diff --git a/web-common/src/features/dashboards/big-number/MeasureBigNumber.svelte b/web-common/src/features/dashboards/big-number/MeasureBigNumber.svelte index 7af8e36a4cb..68e2aa85964 100644 --- a/web-common/src/features/dashboards/big-number/MeasureBigNumber.svelte +++ b/web-common/src/features/dashboards/big-number/MeasureBigNumber.svelte @@ -94,17 +94,11 @@ $: useDiv = isMeasureExpanded || !withTimeseries; function handleMouseOver() { - if (value !== undefined && value !== null) { - // Always update the value in the store, but don't change visibility - cellInspectorStore.updateValue(value.toString()); - } + cellInspectorStore.updateValue(value); } function handleFocus() { - if (value !== undefined && value !== null) { - // Always update the value in the store, but don't change visibility - cellInspectorStore.updateValue(value.toString()); - } + cellInspectorStore.updateValue(value); } diff --git a/web-common/src/features/dashboards/leaderboard/LeaderboardCell.svelte b/web-common/src/features/dashboards/leaderboard/LeaderboardCell.svelte index d6d4b0db72f..f2af9dde6ad 100644 --- a/web-common/src/features/dashboards/leaderboard/LeaderboardCell.svelte +++ b/web-common/src/features/dashboards/leaderboard/LeaderboardCell.svelte @@ -77,18 +77,8 @@ on:click={modified({ shift: () => shiftClickHandler(value), })} - on:pointerover={() => { - if (value?.toString) { - // Always update the value in the store, but don't change visibility - cellInspectorStore.updateValue(value.toString()); - } - }} - on:focus={() => { - if (value?.toString) { - // Always update the value in the store, but don't change visibility - cellInspectorStore.updateValue(value.toString()); - } - }} + on:pointerover={() => cellInspectorStore.updateValue(value)} + on:focus={() => cellInspectorStore.updateValue(value)} on:mouseleave={() => (tooltipActive = false)} style:background class="{cellType}-cell {className}" diff --git a/web-common/src/features/dashboards/pivot/FlatTable.svelte b/web-common/src/features/dashboards/pivot/FlatTable.svelte index 865a70c6958..1de73d28a60 100644 --- a/web-common/src/features/dashboards/pivot/FlatTable.svelte +++ b/web-common/src/features/dashboards/pivot/FlatTable.svelte @@ -202,20 +202,8 @@ data-value={cell.getValue()} data-rowid={cell.row.id} data-columnid={cell.column.id} - on:mouseover={() => { - const value = cell.getValue(); - if (value !== undefined && value !== null) { - // Always update the value in the store, but don't change visibility - cellInspectorStore.updateValue(String(value)); - } - }} - on:focus={() => { - const value = cell.getValue(); - if (value !== undefined && value !== null) { - // Always update the value in the store, but don't change visibility - cellInspectorStore.updateValue(String(value)); - } - }} + on:mouseover={() => cellInspectorStore.updateValue(cell.getValue())} + on:focus={() => cellInspectorStore.updateValue(cell.getValue())} > {#if result?.component && result?.props} 0 && i <= measureCount} - on:mouseover={() => { - const value = cell.getValue(); - if (value !== undefined && value !== null) { - // Always update the value in the store, but don't change visibility - cellInspectorStore.updateValue(String(value)); - } - }} - on:focus={() => { - const value = cell.getValue(); - if (value !== undefined && value !== null) { - // Always update the value in the store, but don't change visibility - cellInspectorStore.updateValue(String(value)); - } - }} + on:mouseover={() => cellInspectorStore.updateValue(cell.getValue())} + on:focus={() => cellInspectorStore.updateValue(cell.getValue())} > {#if result?.component && result?.props} { - if (value?.value !== undefined && value?.value !== null) { - // Always update the value in the store, but don't change visibility - cellInspectorStore.updateValue(String(value.value)); - } - }; - - // Add focus event to update the value in the store without changing visibility - th.onfocus = () => { - if (value?.value !== undefined && value?.value !== null) { - // Always update the value in the store, but don't change visibility - cellInspectorStore.updateValue(String(value.value)); - } - }; + th.onmouseover = () => cellInspectorStore.updateValue(value?.value); + th.onfocus = () => cellInspectorStore.updateValue(value?.value); const maybeWidth = getRowHeaderWidth(x); if (maybeWidth) { th.style.width = `${maybeWidth}px`; @@ -161,20 +148,8 @@ td.setAttribute("__col", String(x)); td.setAttribute("__row", String(y)); - // Add mouseover event to update the value in the store without changing visibility - td.onmouseover = () => { - if (value !== undefined && value !== null) { - // Always update the value in the store, but don't change visibility - cellInspectorStore.updateValue(String(value)); - } - }; - - td.onfocus = () => { - if (value !== undefined && value !== null) { - // Always update the value in the store, but don't change visibility - cellInspectorStore.updateValue(String(value)); - } - }; + td.onmouseover = () => cellInspectorStore.updateValue(value); + td.onfocus = () => cellInspectorStore.updateValue(value); const maybeWidth = getColumnWidth(x); if (maybeWidth) { diff --git a/web-common/src/features/dashboards/stores/cell-inspector-store.ts b/web-common/src/features/dashboards/stores/cell-inspector-store.ts index b75979bdc1e..5f3c78c9991 100644 --- a/web-common/src/features/dashboards/stores/cell-inspector-store.ts +++ b/web-common/src/features/dashboards/stores/cell-inspector-store.ts @@ -2,21 +2,35 @@ import { writable } from "svelte/store"; interface CellInspectorState { isOpen: boolean; - value: string; + hasValue: boolean; + value: string | null; +} + +/** + * Converts a raw cell value to the format expected by the store. + * Returns null for null/undefined values, string for everything else. + */ +function normalizeValue(value: unknown): string | null { + if (value === null || value === undefined) { + return null; + } + return String(value); } function createCellInspectorStore() { const { subscribe, update } = writable({ isOpen: false, - value: "", + hasValue: false, + value: null, }); return { subscribe, - open: (value: string) => + open: (value: string | null) => update((state) => ({ ...state, isOpen: true, + hasValue: true, value, })), close: () => @@ -24,17 +38,28 @@ function createCellInspectorStore() { ...state, isOpen: false, })), - // Update the value without changing visibility - updateValue: (value: string) => + /** + * Update the value without changing visibility. + * Accepts any value type and normalizes it internally. + */ + updateValue: (value: unknown) => update((state) => ({ ...state, - value, + hasValue: true, + value: normalizeValue(value), })), - toggle: (value: string) => + toggle: (value: string | null) => update((state) => ({ ...state, isOpen: !state.isOpen, - value: state.isOpen ? state.value : value, + // When opening: prefer store's existing value (from hover) if set, fall back to passed value + // When closing: keep the current value + ...(state.isOpen + ? {} + : { + hasValue: true, + value: state.hasValue ? state.value : value, + }), })), }; }