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,
+ }),
})),
};
}