{#if isNull}
no data
{:else}
diff --git a/web-common/src/features/dashboards/leaderboard/ContextColumnValue.svelte b/web-common/src/features/dashboards/leaderboard/ContextColumnValue.svelte
index 7e6ee866344..0b3f6ad9474 100644
--- a/web-common/src/features/dashboards/leaderboard/ContextColumnValue.svelte
+++ b/web-common/src/features/dashboards/leaderboard/ContextColumnValue.svelte
@@ -11,6 +11,7 @@
const {
selectors: {
contextColumn: {
+ contextColumn,
widthPx,
isDeltaAbsolute,
isDeltaPercent,
@@ -19,36 +20,59 @@
},
numberFormat: { activeMeasureFormatter },
},
+ actions: {
+ contextCol: { observeContextColumnWidth },
+ },
} = getStateManagers();
$: negativeChange = itemData.deltaAbs !== null && itemData.deltaAbs < 0;
$: noChangeData = itemData.deltaRel === null;
+
+ let element: HTMLElement;
+
+ $: {
+ // Re-observe the width when the context column changes,
+ // but after a short delay to allow the DOM to update.
+ if (element && $contextColumn) {
+ setTimeout(() => {
+ // the element may be gone by the time we get here,
+ // if so, don't try to observe it
+ if (!element) return;
+ observeContextColumnWidth(
+ $contextColumn,
+ element.getBoundingClientRect().width
+ );
+ }, 17);
+ }
+ }
{#if !$isHidden}
-
- {#if $isPercentOfTotal}
-
- {:else if noChangeData}
-
no data
- {:else if $isDeltaPercent}
-
- {:else if $isDeltaAbsolute}
-
- {/if}
+
+
+ {#if $isPercentOfTotal}
+
+ {:else if noChangeData}
+
no data
+ {:else if $isDeltaPercent}
+
+ {:else if $isDeltaAbsolute}
+
+ {/if}
+
{/if}
diff --git a/web-common/src/features/dashboards/leaderboard/LeaderboardContextColumnMenu.svelte b/web-common/src/features/dashboards/leaderboard/LeaderboardContextColumnMenu.svelte
index 823cbf5da67..b9bcf5a657f 100644
--- a/web-common/src/features/dashboards/leaderboard/LeaderboardContextColumnMenu.svelte
+++ b/web-common/src/features/dashboards/leaderboard/LeaderboardContextColumnMenu.svelte
@@ -1,17 +1,21 @@
diff --git a/web-common/src/features/dashboards/leaderboard/LeaderboardControls.svelte b/web-common/src/features/dashboards/leaderboard/LeaderboardControls.svelte
index 748b63d5561..70d1c308fef 100644
--- a/web-common/src/features/dashboards/leaderboard/LeaderboardControls.svelte
+++ b/web-common/src/features/dashboards/leaderboard/LeaderboardControls.svelte
@@ -13,9 +13,17 @@
import { metricsExplorerStore } from "web-common/src/features/dashboards/stores/dashboard-stores";
import { useMetaQuery } from "../selectors";
import LeaderboardContextColumnMenu from "./LeaderboardContextColumnMenu.svelte";
+ import { getStateManagers } from "../state-managers/state-managers";
export let metricViewName;
+ const {
+ actions: {
+ contextCol: { setContextColumn },
+ setLeaderboardMeasureName,
+ },
+ } = getStateManagers();
+
$: metaQuery = useMetaQuery($runtime.instanceId, metricViewName);
$: measures = $metaQuery.data?.measures;
@@ -24,10 +32,7 @@
$: metricsExplorer = $metricsExplorerStore.entities[metricViewName];
function handleMeasureUpdate(event: CustomEvent) {
- metricsExplorerStore.setLeaderboardMeasureName(
- metricViewName,
- event.detail.key
- );
+ setLeaderboardMeasureName(event.detail.key);
}
function measureKeyAndMain(measure: MetricsViewSpecMeasureV2) {
@@ -93,10 +98,7 @@
metricsExplorer?.leaderboardContextColumn ===
LeaderboardContextColumn.PERCENT
) {
- metricsExplorerStore.setContextColumn(
- metricViewName,
- LeaderboardContextColumn.HIDDEN
- );
+ setContextColumn(LeaderboardContextColumn.HIDDEN);
}
$: showHideDimensions = createShowHideDimensionsStore(
@@ -145,7 +147,7 @@
on:select={handleMeasureUpdate}
/>
-
+
{:else}
{
+ for (const contextColumn in contextColumnWidths) {
+ contextColumnWidths[contextColumn as LeaderboardContextColumn] =
+ contextColWidthDefaults[contextColumn as LeaderboardContextColumn];
+ }
+};
+
+/**
+ * Observe this width value, updating the overall width of
+ * the context column if the given width is larger than the
+ * current width.
+ */
+export const observeContextColumnWidth = (
+ { dashboard }: DashboardMutables,
+ contextColumn: LeaderboardContextColumn,
+ width: number
+) => {
+ dashboard.contextColumnWidths[contextColumn] = Math.min(
+ Math.max(width, dashboard.contextColumnWidths[contextColumn]),
+ CONTEXT_COL_MAX_WIDTH
+ );
+};
+
export const contextColActions = {
/**
* Updates the dashboard to use the context column of the given type,
* as well as updating to sort by that context column.
*/
setContextColumn,
+
+ /**
+ * Observe this width value, updating the overall width of
+ * the context column if the given width is larger than the
+ * current width.
+ */
+ observeContextColumnWidth,
};
diff --git a/web-common/src/features/dashboards/state-managers/actions/core-actions.ts b/web-common/src/features/dashboards/state-managers/actions/core-actions.ts
index cc57838ddac..acf421281b5 100644
--- a/web-common/src/features/dashboards/state-managers/actions/core-actions.ts
+++ b/web-common/src/features/dashboards/state-managers/actions/core-actions.ts
@@ -1,3 +1,4 @@
+import { resetAllContextColumnWidths } from "./context-columns";
import type { DashboardMutables } from "./types";
export const setLeaderboardMeasureName = (
@@ -5,4 +6,7 @@ export const setLeaderboardMeasureName = (
name: string
) => {
dashboard.leaderboardMeasureName = name;
+
+ // reset column widths when changing the leaderboard measure
+ resetAllContextColumnWidths(dashboard.contextColumnWidths);
};
diff --git a/web-common/src/features/dashboards/state-managers/selectors/context-column.ts b/web-common/src/features/dashboards/state-managers/selectors/context-column.ts
index 5326760dc9e..fe492b28430 100644
--- a/web-common/src/features/dashboards/state-managers/selectors/context-column.ts
+++ b/web-common/src/features/dashboards/state-managers/selectors/context-column.ts
@@ -1,18 +1,13 @@
import { LeaderboardContextColumn } from "../../leaderboard-context-column";
import type { DashboardDataSources } from "./types";
-const contextColumnWidth = (contextType: LeaderboardContextColumn): string => {
- switch (contextType) {
- case LeaderboardContextColumn.DELTA_ABSOLUTE:
- case LeaderboardContextColumn.DELTA_PERCENT:
- return "56px";
- case LeaderboardContextColumn.PERCENT:
- return "44px";
- case LeaderboardContextColumn.HIDDEN:
- return "0px";
- default:
- throw new Error("Invalid context column, all cases must be handled");
+const contextColumnWidth = ({ dashboard }: DashboardDataSources): string => {
+ const contextType = dashboard.leaderboardContextColumn;
+ const width = dashboard.contextColumnWidths[contextType];
+ if (typeof width === "number") {
+ return width + "px";
}
+ return "0px";
};
export const contextColSelectors = {
@@ -61,6 +56,5 @@ export const contextColSelectors = {
* returns a css style string specifying the width of the context
* column in the leaderboards.
*/
- widthPx: ({ dashboard }: DashboardDataSources) =>
- contextColumnWidth(dashboard.leaderboardContextColumn),
+ widthPx: contextColumnWidth,
};
diff --git a/web-common/src/features/dashboards/stores/dashboard-store-defaults.ts b/web-common/src/features/dashboards/stores/dashboard-store-defaults.ts
index aa185b1edfe..e2aa2a24a13 100644
--- a/web-common/src/features/dashboards/stores/dashboard-store-defaults.ts
+++ b/web-common/src/features/dashboards/stores/dashboard-store-defaults.ts
@@ -3,7 +3,10 @@ import {
SortDirection,
SortType,
} from "@rilldata/web-common/features/dashboards/proto-state/derived-types";
-import type { MetricsExplorerEntity } from "@rilldata/web-common/features/dashboards/stores/metrics-explorer-entity";
+import {
+ contextColWidthDefaults,
+ type MetricsExplorerEntity,
+} from "@rilldata/web-common/features/dashboards/stores/metrics-explorer-entity";
import { getLocalUserPreferences } from "@rilldata/web-common/features/dashboards/user-preferences";
import { getTimeComparisonParametersForComponent } from "@rilldata/web-common/lib/time/comparisons";
import { DEFAULT_TIME_RANGES } from "@rilldata/web-common/lib/time/config";
@@ -106,19 +109,27 @@ export function getDefaultMetricsExplorerEntity(
name: string,
metricsView: V1MetricsViewSpec,
fullTimeRange: V1ColumnTimeRangeResponse | undefined
-) {
+): MetricsExplorerEntity {
+ // CAST SAFETY: safe b/c (1) measure.name is a string if defined,
+ // and (2) we filter out undefined values
+ const defaultMeasureNames = (metricsView?.measures
+ ?.map((measure) => measure?.name)
+ .filter((name) => name !== undefined) ?? []) as string[];
+
+ // CAST SAFETY: safe b/c (1) measure.name is a string if defined,
+ // and (2) we filter out undefined values
+ const defaultDimNames = (metricsView?.dimensions
+ ?.map((dim) => dim.name)
+ .filter((name) => name !== undefined) ?? []) as string[];
+
const metricsExplorer: MetricsExplorerEntity = {
name,
-
- visibleMeasureKeys: new Set(
- metricsView.measures.map((measure) => measure.name)
- ),
+ selectedMeasureNames: [...defaultMeasureNames],
+ visibleMeasureKeys: new Set(defaultMeasureNames),
allMeasuresVisible: true,
- visibleDimensionKeys: new Set(
- metricsView.dimensions.map((dim) => dim.name)
- ),
+ visibleDimensionKeys: new Set(defaultDimNames),
allDimensionsVisible: true,
- leaderboardMeasureName: metricsView.measures[0]?.name,
+ leaderboardMeasureName: defaultMeasureNames[0],
filters: {
include: [],
exclude: [],
@@ -131,6 +142,7 @@ export function getDefaultMetricsExplorerEntity(
showTimeComparison: false,
dimensionSearchText: "",
pinIndex: -1,
+ contextColumnWidths: { ...contextColWidthDefaults },
};
// set time range related stuff
setDefaultTimeRange(metricsView, metricsExplorer, fullTimeRange);
diff --git a/web-common/src/features/dashboards/stores/dashboard-stores.ts b/web-common/src/features/dashboards/stores/dashboard-stores.ts
index e9bd0a5a5d0..62427221cb2 100644
--- a/web-common/src/features/dashboards/stores/dashboard-stores.ts
+++ b/web-common/src/features/dashboards/stores/dashboard-stores.ts
@@ -206,7 +206,18 @@ const metricViewReducers = {
});
},
+ /**
+ * DEPRECATED!!!
+ * use setLeaderboardMeasureName via:
+ * getStateManagers().actions.setLeaderboardMeasureName
+ *
+ * Still used in tests, so we can't remove it yet, but don't use
+ * it in production code.
+ */
setLeaderboardMeasureName(name: string, measureName: string) {
+ console.warn(
+ "setLeaderboardMeasureName is deprecated. Use setLeaderboardMeasureName via `getStateManagers().actions.setLeaderboardMeasureName`. Still used in tests, so we can't remove it yet, but don't use it in production code."
+ );
updateMetricsExplorerByName(name, (metricsExplorer) => {
metricsExplorer.leaderboardMeasureName = measureName;
});
diff --git a/web-common/src/features/dashboards/stores/metrics-explorer-entity.ts b/web-common/src/features/dashboards/stores/metrics-explorer-entity.ts
index c1923d2b4ca..df56eaa1395 100644
--- a/web-common/src/features/dashboards/stores/metrics-explorer-entity.ts
+++ b/web-common/src/features/dashboards/stores/metrics-explorer-entity.ts
@@ -1,4 +1,4 @@
-import type { LeaderboardContextColumn } from "@rilldata/web-common/features/dashboards/leaderboard-context-column";
+import { LeaderboardContextColumn } from "@rilldata/web-common/features/dashboards/leaderboard-context-column";
import type {
SortDirection,
SortType,
@@ -125,6 +125,13 @@ export interface MetricsExplorerEntity {
*/
leaderboardContextColumn: LeaderboardContextColumn;
+ /**
+ * Width of each context column. Needs to be reset to default
+ * when changing context column or switching between leaderboard
+ * and dimension detail table
+ */
+ contextColumnWidths: ContextColWidths;
+
/**
* The name of the dimension that is currently shown in the dimension
* detail table. If this is undefined, then the dimension detail table
@@ -134,3 +141,15 @@ export interface MetricsExplorerEntity {
proto?: string;
}
+
+export type ContextColWidths = {
+ [LeaderboardContextColumn.DELTA_ABSOLUTE]: number;
+ [LeaderboardContextColumn.DELTA_PERCENT]: number;
+ [LeaderboardContextColumn.PERCENT]: number;
+};
+
+export const contextColWidthDefaults: ContextColWidths = {
+ [LeaderboardContextColumn.DELTA_ABSOLUTE]: 56,
+ [LeaderboardContextColumn.DELTA_PERCENT]: 44,
+ [LeaderboardContextColumn.PERCENT]: 44,
+};