Cross-tab state sync#59
Merged
Demonstrandum merged 15 commits intoFeb 20, 2026
Merged
Conversation
The superimposed cards grid had its column width hardcoded via a SCSS variable ($metrics-min-card-width: 335px) and never read the dynamic cardMinWidth setting from the store. Regular card grids (CardGridComponent) receive cardMinWidth as an input and apply it via [style.grid-template-columns], which overrides the SCSS default. Superimposed cards were missing this entirely. Changes: - SuperimposedCardsViewContainer: select getMetricsCardMinWidth from the store and pass it as [cardMinWidth] to the presentation component. - SuperimposedCardsViewComponent: accept cardMinWidth input, compute gridTemplateColumn in ngOnChanges (same logic as CardGridComponent), and bind it via [style.grid-template-columns] on the grid div. Fixes #55 Co-authored-by: Samuel <samuel@knutsen.co>
Smoothing was still being written to the URL query string whenever the user changed the setting, causing unwanted URL pollution. Remove the smoothing serialization from DashboardDeepLinkProvider's serializeStateToQueryParams. Smoothing is already persisted in localStorage, so it does not need to live in the URL. Deserialization is kept for backwards compatibility with old bookmarked URLs that may contain a smoothing parameter. Fixes #54 Co-authored-by: Samuel <samuel@knutsen.co>
…ter-b9fd Smoothing URL parameter
When a line chart has disableUpdate=true (card not yet visible via intersection observer), the container may be resized by persistResize restoring a saved height, or by a full-width class being applied asynchronously from the store. The ResizeDetectorDirective's skip(1) can batch this resize with the initial ResizeObserver event, causing the only notification to be swallowed. The chart then holds stale dimensions from ngAfterViewInit, so the renderer draws curves at one scale while the interactive overlay positions tooltip dots at another. Fix: when disableUpdate transitions from true to false, re-read the DOM dimensions and resize the chart renderer so both the canvas and the coordinate mapping match the current layout. Co-authored-by: Samuel <samuel@knutsen.co>
Co-authored-by: Samuel <samuel@knutsen.co>
…card-width-9016 Super-imposed plots card width
…tence-348f Run selection persistence
The syncPolymerRunColorMap$ effect (added in PR #58) uses getRunColorMap which transitively depends on the settings feature selector via getColorPalette. In the karma bundle test, when the settings feature state is not registered in a particular test's MockStore, selectSettingsState returns undefined, causing 'TypeError: Cannot read property settings of undefined' in the memoized selector chain. Fix 1 - settings_selectors.ts: Wrap the bare createFeatureSelector with a createSelector that falls back to initialState when the feature state is undefined. This prevents crashes in any test that evaluates settings-dependent selectors without registering the settings feature. Fix 2 - colorScale.ts: The readColorMap() function threw when window.__tbRunColorMap was not set. During tests and before the first NgRx effect fires, this map is absent. Changed to return null gracefully, skip domain population when the map is absent, and return a neutral fallback color (#808080) from getColor instead of throwing when a run is not in the domain. Co-authored-by: Samuel <samuel@knutsen.co>
Revert the overly-defensive approach. When window.__tbRunColorMap is not yet seeded (race between runsStore listener and the NgRx effect), fall back to the original static palette assignment so the domain is always fully populated and getColor throws for actual programming errors. When the shared color map IS available but a run is missing, log console.error so the problem is visible. Co-authored-by: Samuel <samuel@knutsen.co>
|
Cursor Agent can help with this pull request. Just |
When the shared color map exists but is missing a specific run, fall back to the palette color for that entry (and log the error). Previously the identifier was set to undefined, which would cause getColor to return undefined instead of a hex string. Co-authored-by: Samuel <samuel@knutsen.co>
Preview Deployment
Details
|
Co-authored-by: Samuel <samuel@knutsen.co>
Master CI failure
Co-authored-by: Samuel <samuel@knutsen.co>
Co-authored-by: Samuel <samuel@knutsen.co>
f84be53 to
262ba4d
Compare
Co-authored-by: Samuel <samuel@knutsen.co>
9859579
into
cursor/run-selection-persistence-348f
13 checks passed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Motivation for features / changes
This PR addresses several long-standing issues related to state synchronization and persistence across different dashboards (time-series vs. legacy Polymer plugins like Scalars, Images, Text):
The core motivation is to establish a single source of truth for these settings, ensuring consistency and persistence across the entire application, and to eliminate silent failures and duplicated logic.
Technical description of changes
This PR refactors state management for run selection, colors, axis scales, and panel expansion to use a single, shared source of truth (localStorage keys and
window.__tbRunColorMapfor colors) directly, eliminating intermediate formats and synchronization issues.tf-runs-selector(Polymer) now directly reads from and writes tolocalStorage['_tb_run_selection.v1'], the same key used by NgRx.tb-run-selection-changedcustom events from Polymer components and dispatchesrunSelectionStateLoadedto keep the NgRx store in sync.ColorScale(Polymer) now primarily reads fromwindow.__tbRunColorMap, which is kept live-updated by an NgRx subscription togetRunColorMap.persistRunColorSettings$effect now exports colors scoped to active route experiments to prevent cross-experiment conflicts.window.__tbRunColorMapis missing or a run's color is not found, the application will crash (no more silent fallbacks).ColorScale.setDomain()now returns early for empty domains to prevent crashes during initial module startup.tf-scalar-card(Polymer) now reads from and writes tolocalStorage['_tb_axis_scales.v1']directly._tagChangedobserver to ensurethis.tagis defined when reading stored scales.tf-category-paginated-view(Polymer) now reads from and writes tolocalStorage['_tb_tag_group_expansion.v1']directly.tb-run-selection-changed,tb-tag-group-expansion-changed,tb-run-color-map-changed) are dispatched on state changes and listened for by other Polymer instances to trigger immediate re-reads and UI updates.tf-line-chart-data-loadernow uses aResizeObserverto monitor its container's dimensions. It enqueues a chart redraw when the container size becomes valid after being hidden or having zero size, preventing charts from rendering squashed.Screenshots of UI changes (or N/A)
N/A. This PR focuses on fixing existing behavior and consistency, not introducing new UI elements.
Detailed steps to verify changes work correctly (as executed by you)
Alternate designs / implementations considered (or N/A)
Previous attempts involved maintaining separate localStorage keys or duplicating color computation logic, leading to synchronization issues and inconsistent behavior. This PR explicitly rejects those approaches in favor of a single source of truth for all shared state, with strict erroring to prevent silent failures.