Skip to content

Conversation

@psybuzz
Copy link
Contributor

@psybuzz psybuzz commented Oct 6, 2020

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

@psybuzz
Copy link
Contributor Author

psybuzz commented Oct 8, 2020

As per offline discussion, added comments to hopefully explain things, and renamed:
CardInStorage --> CardUniqueInfo
PrePinnedCards --> UnresolvedImportedPinnedCards

Ready for review

Comment on lines 55 to 79
/**
* 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[];
};
}
Copy link
Contributor

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?

Copy link
Contributor Author

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(
Copy link
Contributor

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?

Copy link
Contributor Author

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(
Copy link
Contributor

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
) {
Copy link
Contributor

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.

Copy link
Contributor Author

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', () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/pre-pinned/unresolvedImported

Copy link
Contributor Author

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'}],
Copy link
Contributor

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.

Copy link
Contributor Author

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', () => {
Copy link
Contributor

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.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@psybuzz psybuzz requested a review from stephanwlee October 9, 2020 22:40
// 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.
Copy link
Contributor

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.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Comment on lines 403 to 405
const nextCardList = newCardIds.length
? [...state.cardList, ...newCardIds]
: state.cardList;
Copy link
Contributor

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?

Copy link
Contributor Author

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]])
);
Copy link
Contributor

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.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

@psybuzz psybuzz requested a review from stephanwlee October 12, 2020 23:00
Copy link
Contributor

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.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

Copy link
Contributor Author

@psybuzz psybuzz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for reviewing!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

Base automatically changed from psybuzz-urlpins to master October 12, 2020 23:30
psybuzz added a commit that referenced this pull request Oct 12, 2020
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
@psybuzz psybuzz merged commit 7da5f74 into master Oct 13, 2020
@psybuzz psybuzz deleted the psybuzz-urlpins2 branch October 13, 2020 00:54
psybuzz added a commit that referenced this pull request Oct 22, 2020
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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants