-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Update ngrx store for pinned cards from storage #4220
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
1af823e to
13c76e5
Compare
|
As per offline discussion, added comments to hopefully explain things, and renamed: Ready for review |
| /** | ||
| * The normal representation of a card, for storage layers. | ||
| */ | ||
| export interface CardInStorage { | ||
| tag: string; | ||
| runId?: string; | ||
| sample?: number; | ||
| } | ||
|
|
||
| /** | ||
| * The state after deserializing a URL for hydration. | ||
| */ | ||
| export interface URLDeserializedState { | ||
| metrics: { | ||
| pinnedCards: CardInStorage[]; | ||
| }; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These verbiage is very confusing to me. What is the storage referring to?
The state after deserializing a URL for hydration
What does this mean? You serialize a state into URL safe string and that is called "dehydrating" in some vernacular but the sentence does not make sense whichever way I read it:
- "The state ... for hydration" <- state is not for hydration? Object from hydration may make sense
- "The state ... a URL for hydration" <- URL is not for hydration...
What am I missing?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reworded.
The original intent was to be parsed as:
[
[the state]
[after]
[
[deserializing a url]
[for hydration]
]
]
which I realize is awkward :)
| * Returns an identifier useful for comparing a card in storage with a real card | ||
| * with loaded metadata. | ||
| */ | ||
| function hashCardInStorage( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
serializedCard instead please? Also, specify the return type.
hashCard does not make much sense and word storage is not that descriptive.
From the usage, it looks like the word "hash" is referring to unique identifier. Can we just say identifier then?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added return types.
How about serializeCardUniqueInfo ?
| * Returns an identifier useful for comparing a card in storage with a real card | ||
| * with loaded metadata. | ||
| */ | ||
| function hashCardUniqueInfo( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
word hash can be a verb but it confused me at first. Maybe getCardUniqueInfoHash?
| tag: string, | ||
| runId?: string | null, | ||
| sample?: number | ||
| ) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
specify the return type of these pure utils.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
| ]); | ||
| }); | ||
|
|
||
| it('does not populate pre-pinned store with already pinned cards', () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/pre-pinned/unresolvedImported
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, I missed all these 'pre-pinned' sites
| routeKind: RouteKind.EXPERIMENT, | ||
| partialState: { | ||
| metrics: { | ||
| pinnedCards: [{tag: 'accuracy'}], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
also test a case where pinnedCards are just duplicates.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good one, done
| ); | ||
| }); | ||
|
|
||
| it('automatically pins cards from pre-pinned storage', () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
add a case where the unresolvedImportedPinnedCards are inconsistent with the cardMetadata.
for instance, missing step/runId for image based tag.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
081ab94 to
648c89b
Compare
| // We need to include previous unresolved imported pins, because the new | ||
| // hydrated state might not include them. For example, navigating from | ||
| // experiment A (with pins) --> B --> A, we want to ensure that rehydration | ||
| // does not drop the old pins on A. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
old pins -> old unresolved pins.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
| const nextCardList = newCardIds.length | ||
| ? [...state.cardList, ...newCardIds] | ||
| : state.cardList; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can't you spread zero length array? const nextCardList = [...state.cardList, ...newCardIds] should suffice?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
Ah, the intent was to do a small optimization and avoid returning a different reference in case there are no new cards. However, I see that cardMetadataMap will get a new reference anyways, so perhaps we ought to do a full optimization later if needed.
| ); | ||
| expect(nextState.cardToPinnedCopy).toEqual( | ||
| new Map([['card1', pinnedCopyId]]) | ||
| ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
assert that unresolvedImportedPinnedCards is empty.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not a big comment person but let's codified in the comment that the contract is not to sanitize/clip/validate unresolved cards.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
psybuzz
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for reviewing!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
AppRoutingEffects recently added logic to preserve URL hash upon the initial 'navigated' action (see [1]). While this fixed cases where the URL needs to be read upon initial page load, it does not address an upcoming case needed for deeplinking pins in Time Series. Flow: pin a card, DeepLinkProvider serializes `?pinnedCards=` in the URL which drops `#timeseries`, reload the tab, the selected dashboard is no longer Time Series. Expected: Time Series remains selected upon tab reload. This change overcomes this issue the DeepLinkProvider by preserving the hash upon same-RouteId navigations. Manually checked internal TB embedders that navigating to a different route id still clears the hash. Googlers, see sync cl/335688801 Followup: #4220 [1] #4213
cdead2f to
ebe623b
Compare
Diffbase: #4220 When cards are pinned/un-pinned in Time Series, their state is now reflected in the URL, while the user is on a route of kind EXPERIMENT or COMPARE_EXPERIMENTS. Pinned cards will persist across tab reloads. This behavior can be configured per-route via updating the use of CoreDeepLinkProvider.
Diffbase: #4219
Followup: #4221
Adds ngrx reducer logic and types to support storing
pinned cards that originate from URL storage. Before
'tagMetadataLoaded' creates real cards, TensorBoard is now
able to keep track of pinned cards from the URL, in the ngrx
store.
A followup will implement the actual deeplink provider.
Googlers, see test sync cl/335717460