Skip to content

Commit 2b39a29

Browse files
reorg
1 parent 96abe22 commit 2b39a29

File tree

3 files changed

+71
-63
lines changed

3 files changed

+71
-63
lines changed

web-common/src/features/dashboards/state-managers/loaders/DashboardStateDataLoader.ts

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -326,12 +326,11 @@ export class DashboardStateDataLoader {
326326

327327
// Check in-memory last visited state
328328
let mostRecentPartialExploreState: Partial<ExploreState> | undefined;
329-
const lastVisitedJson = getLastVisitedState(this.exploreName);
330-
if (lastVisitedJson) {
329+
const lastVisited = getLastVisitedState(this.exploreName);
330+
if (lastVisited) {
331331
try {
332-
const parsed = JSON.parse(lastVisitedJson) as Partial<ExploreState>;
333-
validateAndCleanExploreState(metricsViewSpec, exploreSpec, parsed);
334-
mostRecentPartialExploreState = parsed;
332+
validateAndCleanExploreState(metricsViewSpec, exploreSpec, lastVisited);
333+
mostRecentPartialExploreState = lastVisited;
335334
} catch {
336335
// Invalid state, ignore
337336
}

web-common/src/features/dashboards/state-managers/loaders/DashboardStateManager.spec.ts

Lines changed: 33 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -206,20 +206,17 @@ describe("DashboardStateManager", () => {
206206
});
207207

208208
it("Should load most recent dashboard state", async () => {
209-
setLastVisitedStateRaw(
210-
AD_BIDS_EXPLORE_NAME,
211-
JSON.stringify({
212-
visibleMeasures: [AD_BIDS_BID_PRICE_MEASURE],
213-
allMeasuresVisible: false,
214-
visibleDimensions: [AD_BIDS_DOMAIN_DIMENSION],
215-
allDimensionsVisible: false,
216-
217-
leaderboardSortByMeasureName: AD_BIDS_BID_PRICE_MEASURE,
218-
leaderboardMeasureNames: [AD_BIDS_BID_PRICE_MEASURE],
219-
sortDirection: DashboardState_LeaderboardSortDirection.ASCENDING,
220-
dashboardSortType: DashboardState_LeaderboardSortType.VALUE,
221-
}),
222-
);
209+
setLastVisitedStateRaw(AD_BIDS_EXPLORE_NAME, {
210+
visibleMeasures: [AD_BIDS_BID_PRICE_MEASURE],
211+
allMeasuresVisible: false,
212+
visibleDimensions: [AD_BIDS_DOMAIN_DIMENSION],
213+
allDimensionsVisible: false,
214+
215+
leaderboardSortByMeasureName: AD_BIDS_BID_PRICE_MEASURE,
216+
leaderboardMeasureNames: [AD_BIDS_BID_PRICE_MEASURE],
217+
sortDirection: DashboardState_LeaderboardSortDirection.ASCENDING,
218+
dashboardSortType: DashboardState_LeaderboardSortType.VALUE,
219+
});
223220
renderDashboardStateManager(BookmarkSourceQueryResult);
224221
await waitFor(() => expect(screen.getByText("Dashboard loaded!")));
225222

@@ -319,20 +316,17 @@ describe("DashboardStateManager", () => {
319316
});
320317

321318
it("Should load most recent dashboard state", async () => {
322-
setLastVisitedStateRaw(
323-
AD_BIDS_EXPLORE_NAME,
324-
JSON.stringify({
325-
visibleMeasures: [AD_BIDS_BID_PRICE_MEASURE],
326-
allMeasuresVisible: false,
327-
visibleDimensions: [AD_BIDS_DOMAIN_DIMENSION],
328-
allDimensionsVisible: false,
329-
330-
leaderboardSortByMeasureName: AD_BIDS_BID_PRICE_MEASURE,
331-
leaderboardMeasureNames: [AD_BIDS_BID_PRICE_MEASURE],
332-
sortDirection: DashboardState_LeaderboardSortDirection.ASCENDING,
333-
dashboardSortType: DashboardState_LeaderboardSortType.VALUE,
334-
}),
335-
);
319+
setLastVisitedStateRaw(AD_BIDS_EXPLORE_NAME, {
320+
visibleMeasures: [AD_BIDS_BID_PRICE_MEASURE],
321+
allMeasuresVisible: false,
322+
visibleDimensions: [AD_BIDS_DOMAIN_DIMENSION],
323+
allDimensionsVisible: false,
324+
325+
leaderboardSortByMeasureName: AD_BIDS_BID_PRICE_MEASURE,
326+
leaderboardMeasureNames: [AD_BIDS_BID_PRICE_MEASURE],
327+
sortDirection: DashboardState_LeaderboardSortDirection.ASCENDING,
328+
dashboardSortType: DashboardState_LeaderboardSortType.VALUE,
329+
});
336330
renderDashboardStateManager();
337331
await waitFor(() => expect(screen.getByText("Dashboard loaded!")));
338332

@@ -362,20 +356,17 @@ describe("DashboardStateManager", () => {
362356
});
363357

364358
it("Should validate most recent dashboard state and correct invalid fields", async () => {
365-
setLastVisitedStateRaw(
366-
AD_BIDS_EXPLORE_NAME,
367-
JSON.stringify({
368-
visibleMeasures: [AD_BIDS_PUBLISHER_COUNT_MEASURE],
369-
allMeasuresVisible: false,
370-
visibleDimensions: [AD_BIDS_COUNTRY_DIMENSION],
371-
allDimensionsVisible: false,
372-
373-
leaderboardSortByMeasureName: AD_BIDS_PUBLISHER_COUNT_MEASURE,
374-
leaderboardMeasureNames: [AD_BIDS_PUBLISHER_COUNT_MEASURE],
375-
sortDirection: DashboardState_LeaderboardSortDirection.ASCENDING,
376-
dashboardSortType: DashboardState_LeaderboardSortType.VALUE,
377-
}),
378-
);
359+
setLastVisitedStateRaw(AD_BIDS_EXPLORE_NAME, {
360+
visibleMeasures: [AD_BIDS_PUBLISHER_COUNT_MEASURE],
361+
allMeasuresVisible: false,
362+
visibleDimensions: [AD_BIDS_COUNTRY_DIMENSION],
363+
allDimensionsVisible: false,
364+
365+
leaderboardSortByMeasureName: AD_BIDS_PUBLISHER_COUNT_MEASURE,
366+
leaderboardMeasureNames: [AD_BIDS_PUBLISHER_COUNT_MEASURE],
367+
sortDirection: DashboardState_LeaderboardSortDirection.ASCENDING,
368+
dashboardSortType: DashboardState_LeaderboardSortType.VALUE,
369+
});
379370
renderDashboardStateManager();
380371
await waitFor(() => expect(screen.getByText("Dashboard loaded!")));
381372

web-common/src/features/dashboards/state-managers/loaders/last-visited-state.ts

Lines changed: 34 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,27 +2,25 @@ import { DashboardState_ActivePage } from "@rilldata/web-common/proto/gen/rill/u
22
import type { ExploreState } from "@rilldata/web-common/features/dashboards/stores/explore-state";
33

44
/**
5-
* In-memory map: exploreName → partial ExploreState (JSON string).
5+
* In-memory map: exploreName → partial ExploreState snapshot.
66
*
77
* Replaces localStorage-based persistence for "most recent explore state."
88
* Within the same browser session, navigating away from and back to an explore
99
* will restore the last-visited state from this map.
1010
* On page refresh, the in-memory state is lost and YAML defaults apply.
11-
*
12-
* Only a curated subset of JSON-safe fields is saved — specifically sort/visibility
13-
* preferences. Filters, time ranges, and other stateful fields are NOT saved here;
14-
* they come from URL params, session storage, or YAML defaults.
1511
*/
16-
const lastVisitedState = new Map<string, string>();
12+
const lastVisitedState = new Map<string, Partial<ExploreState>>();
1713

18-
export function getLastVisitedState(exploreName: string): string | undefined {
14+
export function getLastVisitedState(
15+
exploreName: string,
16+
): Partial<ExploreState> | undefined {
1917
return lastVisitedState.get(exploreName);
2018
}
2119

2220
/**
23-
* Saves a curated subset of the explore state to in-memory storage.
24-
* Only saves sort/visibility preferences (all JSON-safe primitives).
25-
* Does NOT save filters, time ranges, or other complex objects (Set, Map, etc.).
21+
* Saves a snapshot of the explore state to in-memory storage.
22+
* Copies the fields we care about so that later mutations to the live
23+
* ExploreState don't affect the stored snapshot.
2624
*/
2725
export function setLastVisitedState(
2826
exploreName: string,
@@ -32,34 +30,54 @@ export function setLastVisitedState(
3230
exploreState.activePage !== DashboardState_ActivePage.DEFAULT &&
3331
exploreState.activePage !== DashboardState_ActivePage.DIMENSION_TABLE
3432
) {
35-
// We are not saving any state for non-explore pages
3633
return;
3734
}
3835

3936
const subset: Partial<ExploreState> = {
37+
// Filters
38+
whereFilter: exploreState.whereFilter,
39+
dimensionThresholdFilters: exploreState.dimensionThresholdFilters,
40+
dimensionsWithInlistFilter: exploreState.dimensionsWithInlistFilter,
41+
pinnedFilters: new Set(exploreState.pinnedFilters),
42+
dimensionFilterExcludeMode: new Map(
43+
exploreState.dimensionFilterExcludeMode,
44+
),
45+
46+
// Time
47+
selectedTimeRange: exploreState.selectedTimeRange,
48+
selectedComparisonTimeRange: exploreState.selectedComparisonTimeRange,
49+
showTimeComparison: exploreState.showTimeComparison,
50+
selectedComparisonDimension: exploreState.selectedComparisonDimension,
4051
selectedTimezone: exploreState.selectedTimezone,
4152

53+
// Sort / visibility
4254
visibleMeasures: exploreState.visibleMeasures,
4355
allMeasuresVisible: exploreState.allMeasuresVisible,
4456
visibleDimensions: exploreState.visibleDimensions,
4557
allDimensionsVisible: exploreState.allDimensionsVisible,
46-
4758
leaderboardSortByMeasureName: exploreState.leaderboardSortByMeasureName,
4859
leaderboardMeasureNames: exploreState.leaderboardMeasureNames,
4960
leaderboardShowContextForAllMeasures:
5061
exploreState.leaderboardShowContextForAllMeasures,
5162
sortDirection: exploreState.sortDirection,
5263
dashboardSortType: exploreState.dashboardSortType,
64+
65+
// View
66+
activePage: exploreState.activePage,
67+
selectedDimensionName: exploreState.selectedDimensionName,
5368
};
5469

55-
lastVisitedState.set(exploreName, JSON.stringify(subset));
70+
lastVisitedState.set(exploreName, subset);
5671
}
5772

5873
export function clearLastVisitedState(exploreName: string) {
5974
lastVisitedState.delete(exploreName);
6075
}
6176

62-
/** For testing only: directly set the raw JSON string in the map */
63-
export function setLastVisitedStateRaw(exploreName: string, rawJson: string) {
64-
lastVisitedState.set(exploreName, rawJson);
77+
/** For testing only: directly set a partial explore state in the map */
78+
export function setLastVisitedStateRaw(
79+
exploreName: string,
80+
state: Partial<ExploreState>,
81+
) {
82+
lastVisitedState.set(exploreName, state);
6583
}

0 commit comments

Comments
 (0)