Skip to content

Commit 96abe22

Browse files
progress
1 parent cc45e47 commit 96abe22

26 files changed

+1545
-661
lines changed

runtime/parser/parse_explore.go

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,15 @@ var exploreComparisonModes = map[string]runtimev1.ExploreComparisonMode{
121121
"dimension": runtimev1.ExploreComparisonMode_EXPLORE_COMPARISON_MODE_DIMENSION,
122122
}
123123

124+
var validRillComparisonOptions = map[string]bool{
125+
"rill-PP": true, "rill-PD": true, "rill-PW": true,
126+
"rill-PM": true, "rill-PQ": true, "rill-PY": true,
127+
}
128+
129+
func isRillComparisonOption(s string) bool {
130+
return validRillComparisonOptions[s]
131+
}
132+
124133
func (p *Parser) parseExplore(node *Node) error {
125134
// Parse YAML
126135
tmp := &ExploreYAML{}
@@ -218,11 +227,17 @@ func (p *Parser) parseExplore(node *Node) error {
218227
}
219228

220229
mode := runtimev1.ExploreComparisonMode_EXPLORE_COMPARISON_MODE_NONE
230+
var compareTimeRange *string
221231
if tmp.Defaults.ComparisonMode != "" {
222232
var ok bool
223233
mode, ok = exploreComparisonModes[tmp.Defaults.ComparisonMode]
224234
if !ok {
225-
return fmt.Errorf("invalid comparison mode %q (options: %s)", tmp.Defaults.ComparisonMode, strings.Join(maps.Keys(exploreComparisonModes), ", "))
235+
if isRillComparisonOption(tmp.Defaults.ComparisonMode) {
236+
mode = runtimev1.ExploreComparisonMode_EXPLORE_COMPARISON_MODE_TIME
237+
compareTimeRange = &tmp.Defaults.ComparisonMode
238+
} else {
239+
return fmt.Errorf("invalid comparison mode %q (options: %s)", tmp.Defaults.ComparisonMode, strings.Join(maps.Keys(exploreComparisonModes), ", "))
240+
}
226241
}
227242
}
228243

@@ -277,6 +292,7 @@ func (p *Parser) parseExplore(node *Node) error {
277292
MeasuresSelector: presetMeasuresSelector,
278293
TimeRange: tr,
279294
ComparisonMode: mode,
295+
CompareTimeRange: compareTimeRange,
280296
ComparisonDimension: compareDim,
281297
Filter: filter,
282298
Pinned: pinnedMeasuresOrDimensions,

runtime/parser/schema/project.schema.yaml

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2302,12 +2302,18 @@ definitions:
23022302
description: Refers to the default time range shown when a user initially loads the dashboard. The value must be either a valid [ISO 8601 duration](https://en.wikipedia.org/wiki/ISO_8601#Durations) (for example, PT12H for 12 hours, P1M for 1 month, or P26W for 26 weeks) or one of the [Rill ISO 8601 extensions](https://docs.rilldata.com/reference/rill-iso-extensions#extensions)
23032303
type: string
23042304
comparison_mode:
2305-
description: 'Controls how to compare current data with historical or categorical baselines. Options: `none` (no comparison), `time` (compares with past based on default_time_range), `dimension` (compares based on comparison_dimension values)'
2305+
description: 'Controls how to compare current data. Options: `none`, `time` (alias for `rill-PP`), `dimension`, or a specific comparison offset: `rill-PP` (previous period), `rill-PD` (previous day), `rill-PW` (previous week), `rill-PM` (previous month), `rill-PQ` (previous quarter), `rill-PY` (previous year)'
23062306
type: string
23072307
enum:
23082308
- none
23092309
- time
23102310
- dimension
2311+
- rill-PP
2312+
- rill-PD
2313+
- rill-PW
2314+
- rill-PM
2315+
- rill-PQ
2316+
- rill-PY
23112317
comparison_dimension:
23122318
description: 'for dimension mode, specify the comparison dimension by name'
23132319
type: string
@@ -2519,12 +2525,18 @@ definitions:
25192525
description: Refers to the default time range shown when a user initially loads the dashboard. The value must be either a valid [ISO 8601 duration](https://en.wikipedia.org/wiki/ISO_8601#Durations) (for example, PT12H for 12 hours, P1M for 1 month, or P26W for 26 weeks) or one of the [Rill ISO 8601 extensions](https://docs.rilldata.com/reference/rill-iso-extensions#extensions)
25202526
type: string
25212527
comparison_mode:
2522-
description: 'Controls how to compare current data with historical or categorical baselines. Options: `none` (no comparison), `time` (compares with past based on default_time_range), `dimension` (compares based on comparison_dimension values)'
2528+
description: 'Controls how to compare current data. Options: `none`, `time` (alias for `rill-PP`), `dimension`, or a specific comparison offset: `rill-PP` (previous period), `rill-PD` (previous day), `rill-PW` (previous week), `rill-PM` (previous month), `rill-PQ` (previous quarter), `rill-PY` (previous year)'
25232529
type: string
25242530
enum:
25252531
- none
25262532
- time
25272533
- dimension
2534+
- rill-PP
2535+
- rill-PD
2536+
- rill-PW
2537+
- rill-PM
2538+
- rill-PQ
2539+
- rill-PY
25282540
comparison_dimension:
25292541
description: 'for dimension mode, specify the comparison dimension by name'
25302542
type: string
@@ -3648,7 +3660,17 @@ definitions:
36483660
description: Default time range to display when the explore view loads.
36493661
comparison_mode:
36503662
type: string
3651-
description: Default comparison mode for metrics (none, time, or dimension).
3663+
description: 'Controls how to compare current data. Options: `none`, `time` (alias for `rill-PP`), `dimension`, or a specific comparison offset: `rill-PP` (previous period), `rill-PD` (previous day), `rill-PW` (previous week), `rill-PM` (previous month), `rill-PQ` (previous quarter), `rill-PY` (previous year)'
3664+
enum:
3665+
- none
3666+
- time
3667+
- dimension
3668+
- rill-PP
3669+
- rill-PD
3670+
- rill-PW
3671+
- rill-PM
3672+
- rill-PQ
3673+
- rill-PY
36523674
comparison_dimension:
36533675
type: string
36543676
description: Default dimension to use for comparison when comparison_mode is 'dimension'.

web-admin/src/features/bookmarks/HomeBookmarkButton.svelte

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
import HomeBookmark from "@rilldata/web-common/components/icons/HomeBookmark.svelte";
1414
import HomeBookmarkPlus from "@rilldata/web-common/components/icons/HomeBookmarkPlus.svelte";
1515
import * as Tooltip from "@rilldata/web-common/components/tooltip-v2";
16-
import { clearExploreSessionStore } from "@rilldata/web-common/features/dashboards/state-managers/loaders/explore-web-view-store.ts";
16+
import { clearExploreViewState } from "@rilldata/web-common/features/dashboards/state-managers/loaders/explore-web-view-store.ts";
1717
import { ResourceKind } from "@rilldata/web-common/features/entity-management/resource-selectors.ts";
1818
1919
export let organization: string;
@@ -39,7 +39,7 @@
3939
function goToDashboardHome() {
4040
if (resourceKind === ResourceKind.Explore) {
4141
// Without clearing sessions empty, DashboardStateDataLoader will load from session for explore view
42-
clearExploreSessionStore(resourceName, `${organization}__${project}__`);
42+
clearExploreViewState(resourceName, `${organization}__${project}__`);
4343
}
4444
}
4545

web-admin/src/routes/-/embed/explore/[name]/+page.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
import { EmbedStorageNamespacePrefix } from "@rilldata/web-admin/features/embeds/constants.ts";
2-
import { clearExploreSessionStore } from "@rilldata/web-common/features/dashboards/state-managers/loaders/explore-web-view-store.ts";
2+
import { clearExploreViewState } from "@rilldata/web-common/features/dashboards/state-managers/loaders/explore-web-view-store.ts";
33

44
export const load = async ({ params, parent }) => {
55
const exploreName = params.name;
66
const { visibleExplores } = await parent();
77

88
// Check visibleExplores for more details
99
if (!visibleExplores.has(exploreName)) {
10-
clearExploreSessionStore(exploreName, EmbedStorageNamespacePrefix);
10+
clearExploreViewState(exploreName, EmbedStorageNamespacePrefix);
1111
visibleExplores.add(exploreName);
1212
}
1313

web-common/src/features/canvas/inspector/CanvasTabs.svelte

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
];
1616
</script>
1717

18-
<div class="mr-4 bg-surac">
18+
<div class="mr-4 bg-surface-background">
1919
<div class="flex gap-x-2">
2020
{#each tabs as { tab, label } (tab)}
2121
{@const selected = tab === currentTab}

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

Lines changed: 33 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@ import {
44
getCompoundQuery,
55
} from "@rilldata/web-common/features/compound-query-result";
66
import { cascadingExploreStateMerge } from "@rilldata/web-common/features/dashboards/state-managers/cascading-explore-state-merge";
7-
import { getPartialExploreStateFromSessionStorage } from "@rilldata/web-common/features/dashboards/state-managers/loaders/explore-web-view-store";
8-
import { getMostRecentPartialExploreState } from "@rilldata/web-common/features/dashboards/state-managers/loaders/most-recent-explore-state";
7+
import { getPartialExploreStateFromViewState } from "@rilldata/web-common/features/dashboards/state-managers/loaders/explore-web-view-store";
8+
import { getLastVisitedState } from "@rilldata/web-common/features/dashboards/state-managers/loaders/last-visited-state";
9+
import { validateAndCleanExploreState } from "@rilldata/web-common/features/dashboards/stores/validate-and-clean-explore-state";
910
import { getExploreStateFromYAMLConfig } from "@rilldata/web-common/features/dashboards/stores/get-explore-state-from-yaml-config";
1011
import { getRillDefaultExploreState } from "@rilldata/web-common/features/dashboards/stores/get-rill-default-explore-state";
1112
import type { ExploreState } from "@rilldata/web-common/features/dashboards/stores/explore-state";
@@ -187,6 +188,7 @@ export class DashboardStateDataLoader {
187188
exploreStateFromYAMLConfig,
188189
rillDefaultExploreState,
189190
backButtonUsed,
191+
skipLastVisitedState: true,
190192
});
191193
}
192194

@@ -288,6 +290,7 @@ export class DashboardStateDataLoader {
288290
exploreStateFromYAMLConfig,
289291
rillDefaultExploreState,
290292
backButtonUsed,
293+
skipLastVisitedState = false,
291294
}: {
292295
metricsViewSpec: V1MetricsViewSpec;
293296
exploreSpec: V1ExploreSpec;
@@ -296,13 +299,16 @@ export class DashboardStateDataLoader {
296299
exploreStateFromYAMLConfig: Partial<ExploreState>;
297300
rillDefaultExploreState: ExploreState;
298301
backButtonUsed: boolean;
302+
skipLastVisitedState?: boolean;
299303
}) {
300304
urlSearchParams = cleanEmbedUrlParams(urlSearchParams);
301305

302-
const skipSessionStorage = backButtonUsed;
303-
const exploreStateFromSessionStorage = skipSessionStorage
306+
// Per-view state: restores full state when switching views (explore ↔ TDD ↔ pivot).
307+
// Skipped on back button to avoid restoring stale state.
308+
const skipViewState = backButtonUsed;
309+
const exploreStateFromViewState = skipViewState
304310
? null
305-
: getPartialExploreStateFromSessionStorage(
311+
: getPartialExploreStateFromViewState(
306312
this.exploreName,
307313
this.storageNamespacePrefix,
308314
urlSearchParams,
@@ -318,27 +324,35 @@ export class DashboardStateDataLoader {
318324
{},
319325
);
320326

321-
const { mostRecentPartialExploreState } = getMostRecentPartialExploreState(
322-
this.exploreName,
323-
this.storageNamespacePrefix,
324-
metricsViewSpec,
325-
exploreSpec,
326-
);
327+
// Check in-memory last visited state
328+
let mostRecentPartialExploreState: Partial<ExploreState> | undefined;
329+
const lastVisitedJson = getLastVisitedState(this.exploreName);
330+
if (lastVisitedJson) {
331+
try {
332+
const parsed = JSON.parse(lastVisitedJson) as Partial<ExploreState>;
333+
validateAndCleanExploreState(metricsViewSpec, exploreSpec, parsed);
334+
mostRecentPartialExploreState = parsed;
335+
} catch {
336+
// Invalid state, ignore
337+
}
338+
}
327339

328340
const shouldSkipOtherSources =
329-
// If the url has some params that do not map to session storage then we need to only use state from url back-filled with rill defaults.
330-
(urlSearchParams.size > 0 && !exploreStateFromSessionStorage) ||
341+
// If the url has params that don't map to per-view state, only use url + rill defaults.
342+
(urlSearchParams.size > 0 && !exploreStateFromViewState) ||
331343
// The exception to this is when back button is pressed and the user landed on empty url.
332344
backButtonUsed;
333345

334346
const exploreStateOrder = [
335-
// 1st priority is the state from url params. For certain params the state is from session storage.
336-
// We need the state from session storage to make sure any state is not cleared while the user is still on the page but came back from a different dashboard.
337-
// TODO: move all this logic based on url params to a "fromURL" method. Will replace convertURLSearchParamsToExploreState
338-
exploreStateFromSessionStorage ??
347+
// 1st priority: per-view state (when switching views) or URL params.
348+
exploreStateFromViewState ??
339349
(urlSearchParams.size > 0 ? partialExploreStateFromUrl : null),
340-
// Next priority is the most recent state user had visited. This is a small subset of the full state.
341-
shouldSkipOtherSources || this.disableMostRecentDashboardState
350+
// Next priority is the most recent in-memory state user had visited (sort/visibility preferences).
351+
// Only used during init (navigating between dashboards within the same session).
352+
// Skipped during URL-driven updates so that clearing URL params resets to defaults.
353+
shouldSkipOtherSources ||
354+
this.disableMostRecentDashboardState ||
355+
skipLastVisitedState
342356
? null
343357
: mostRecentPartialExploreState,
344358
// Next priority is one of the other source defined.

0 commit comments

Comments
 (0)