Skip to content
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

[Global pins] Load saved pins in the localStorage #6821

Merged
merged 6 commits into from
Apr 4, 2024

Conversation

roseayeon
Copy link
Contributor

Motivation for features / changes

Following #6819 [Global pins] To extend pinned card info available globally , this PR load saved pins in the localStorage.

Technical description of changes

  • 3e5b052 Introduced new action calledmetricsUnresolvedPinnedCardsAdded.

    • When metricsUnresolvedPinnedCardsAdded is dispatched, the reducer adds the provided card info to the state. unresolvedImportedPinnedCards.
  • aae9be4 Added loadSavedPins$ effect in the metrics/effects/index.ts

    • When coreActions.pluginsListingLoaded is triggered, it loads saved scalar pins in the localStorage and dispatch metricsUnresolvedPinnedCardsAdded with saved pinned cards.
  • Added getShouldPersistSettings() checking logic (metioned in [Global pins] Saving pins to localStorage #6819 (comment))

    • 2dc49aa To use selector globally, added persistent_settings_selectors to the webapp/selectors.
    • Add checking getShouldPersistSettings in the loadSavedPins$ and addOrRemovePin$.

Screenshots of UI changes (or N/A)

N/A

Detailed steps to verify changes work correctly (as executed by you)

  • Unit test pass & TAP presubmit pass

Alternate designs / implementations considered (or N/A)

N.A

);

private readonly loadSavedPins$ = this.actions$.pipe(
ofType(initAction, coreActions.pluginsListingLoaded),
Copy link
Contributor Author

Choose a reason for hiding this comment

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

QQ. I would like to call loadSavedPin$ when the metrics effect initializes. However, I discovered that initAction is primarily used for testing purposes. Is there a coreActions (or anything else) that is suitable for my use case?

Copy link
Contributor

Choose a reason for hiding this comment

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

I think initAction is good enough. You might not even need to observe coreActions.pluginsListingLoaded.

(It's not generally intended for initAction to be for testing purposes only, even if it may appear that way).

Copy link
Member

Choose a reason for hiding this comment

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

The requirement is to dispatch metricsUnresolvedPinnedCardsAdded before stateRehydratedFromUrl, right? pluginsListingLoaded doesn't actually guarantee this and is unsafe to use here (we can also verify this with dev console logs).

The metrics effect initAction will be safe to use as all effect initialization will happen in an earlier event loop iteration than stateRehydratedFromUrl because of the delay placed before it (btw this file also shows examples of initAction usage). For the current purposes, it might be most appropriate to listen to the App Routing initAction.

Copy link
Contributor Author

@roseayeon roseayeon Apr 4, 2024

Choose a reason for hiding this comment

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

Thanks for comments! I thought of listening to App Routing initAction, but I thought that considering other initActions might be more confusing for maintenance. I think the init action of the metrics effect and leaving a comment that it should be dispatched before stateRehydratedFromUrl will be sufficient for now. WDYT?

@roseayeon roseayeon requested review from hoonji and bmd3k April 3, 2024 18:43
Copy link
Contributor

@bmd3k bmd3k left a comment

Choose a reason for hiding this comment

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

I patched and tested it and gave a quick review. Code is clear and the feature seems to work as expected.

I would recommend having someone from your team take a more thorough look, though.

);

private readonly loadSavedPins$ = this.actions$.pipe(
ofType(initAction, coreActions.pluginsListingLoaded),
Copy link
Contributor

Choose a reason for hiding this comment

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

I think initAction is good enough. You might not even need to observe coreActions.pluginsListingLoaded.

(It's not generally intended for initAction to be for testing purposes only, even if it may appear that way).

@@ -271,5 +272,10 @@ export const metricsHideEmptyCardsToggled = createAction(
'[Metrics] Hide Empty Cards Changed'
);

export const metricsUnresolvedPinnedCardsAdded = createAction(
Copy link
Contributor

Choose a reason for hiding this comment

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

I think it would be worth mentioning in the action name and descrxiption that this is meant specifically for pinned cards loaded from local storage.

Maybe: metricsUnresolvedPinnedCardsFromLocalStorageAdded

([, enableGlobalPins, shouldPersistSettings]) =>
enableGlobalPins && shouldPersistSettings
),
map(() => {
Copy link
Contributor

Choose a reason for hiding this comment

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

map() might not be the appropriate operation since you're not actually returning anything used later. Maybe tap()? It doesn't matter very much, though.

Same for addOrRemovePin$.

Copy link
Member

Choose a reason for hiding this comment

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

+1. I think tap makes it much clearer that our intent is to produce side effect, not use the value. It's also what ngrx docs uses and I think there are benefits to aligning with the docs if possible.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Applied!

Copy link
Member

@hoonji hoonji left a comment

Choose a reason for hiding this comment

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

Looks great for the most part!

);

private readonly loadSavedPins$ = this.actions$.pipe(
ofType(initAction, coreActions.pluginsListingLoaded),
Copy link
Member

Choose a reason for hiding this comment

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

The requirement is to dispatch metricsUnresolvedPinnedCardsAdded before stateRehydratedFromUrl, right? pluginsListingLoaded doesn't actually guarantee this and is unsafe to use here (we can also verify this with dev console logs).

The metrics effect initAction will be safe to use as all effect initialization will happen in an earlier event loop iteration than stateRehydratedFromUrl because of the delay placed before it (btw this file also shows examples of initAction usage). For the current purposes, it might be most appropriate to listen to the App Routing initAction.

([, enableGlobalPins, shouldPersistSettings]) =>
enableGlobalPins && shouldPersistSettings
),
map(() => {
Copy link
Member

Choose a reason for hiding this comment

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

+1. I think tap makes it much clearer that our intent is to produce side effect, not use the value. It's also what ngrx docs uses and I think there are benefits to aligning with the docs if possible.

this.addOrRemovePin$
this.addOrRemovePin$,
/**
* Subscribes to: dashboard shown.
Copy link
Member

Choose a reason for hiding this comment

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

Reminder to edit this if we change the loadSavedPins$ trigger

@@ -4471,5 +4471,20 @@ describe('metrics reducers', () => {
expect(state3.isSlideoutMenuOpen).toBe(false);
});
});

describe('#metricsUnresolvedPinnedCardsAdded', () => {
it('add unresolved pinned card to unresolvedImportedPinnedCards', () => {
Copy link
Member

Choose a reason for hiding this comment

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

nit: it "adds" unresolved pinned card...

Copy link
Contributor Author

@roseayeon roseayeon 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 the review! Applied

@roseayeon roseayeon requested a review from hoonji April 4, 2024 08:39
@roseayeon roseayeon merged commit 9424314 into tensorflow:master Apr 4, 2024
13 checks passed
@roseayeon roseayeon deleted the global-pin-2 branch April 5, 2024 04:52
roseayeon added a commit that referenced this pull request Apr 16, 2024
## Motivation for features / changes
Following #6821 As pin data is accumulated, unwanted pins can easily
crowd the dashboard. Therefore, this PR adds a button that allows users
to conveniently clear all pins at once.

## Technical description of changes
* 57c6a47 Introduced new action called `metricsClearAllPinnedCards`
* When `metricsClearAllPinnedCards` is dispatched, the reducer removed
all pinned cards in the state.

* a04c2d7 Added `clear all pins` button in the pinned view container.
  * The button will be shown if there's at least one pinned card.

* f0c3a54 Implemented `removeAllScalarPins` method in the saved pins
data source.
  * This method removes stored pins from local storage.

* e97b110 Added `removeAllPins` effect in the `metrics/effects/index.ts`
* When `metricsClearAllPinnedCards` action is called, this effect will
call `removeAllScalarPins` method defined in the saved pin data source.

* c0edd37 guarded UI feature (button) with feature flag and added
related tests.

## Screenshots of UI changes (or N/A)
### Light mode

![image](https://github.com/tensorflow/tensorboard/assets/24772412/a0793e8b-7fea-45f0-b2d8-4e742ca40918)


### Dark mode

![image](https://github.com/tensorflow/tensorboard/assets/24772412/581468a1-1a9c-4ab4-b70a-13c5a5b168f6)

## Detailed steps to verify changes work correctly (as executed by you)
Unit test pass  & cl TAP presubmit pass
## Alternate designs / implementations considered (or N/A)
I also considered a feature to select a pinned card and remove the
selected pinned card, but I thought that this would be the same as
pressing the 'unpin' button individually from the user's perspective. So
I implemented a 'clear all pins' button that removes all pinned cards.
Any feedback is appreciated!
AnuarTB pushed a commit to AnuarTB/tensorboard that referenced this pull request May 3, 2024
## Motivation for features / changes
Following tensorflow#6819 [Global pins] To extend pinned card info available
globally , this PR load saved pins in the localStorage.
## Technical description of changes
* 3e5b052 Introduced new action
called`metricsUnresolvedPinnedCardsAdded`.
* When `metricsUnresolvedPinnedCardsAdded` is dispatched, the reducer
adds the provided card info to the `state.
unresolvedImportedPinnedCards`.

* aae9be4 Added `loadSavedPins$` effect in the
`metrics/effects/index.ts`
* When `coreActions.pluginsListingLoaded` is triggered, it loads saved
scalar pins in the localStorage and dispatch
`metricsUnresolvedPinnedCardsAdded` with saved pinned cards.
  
* Added `getShouldPersistSettings()` checking logic (metioned in
tensorflow#6819 (comment))
* 2dc49aa To use selector globally, added
`persistent_settings_selectors` to the `webapp/selectors`.
* Add checking `getShouldPersistSettings` in the `loadSavedPins$` and
`addOrRemovePin$`.
 
## Screenshots of UI changes (or N/A)
N/A
## Detailed steps to verify changes work correctly (as executed by you)
* Unit test pass & TAP presubmit pass 
## Alternate designs / implementations considered (or N/A)
N.A
AnuarTB pushed a commit to AnuarTB/tensorboard that referenced this pull request May 3, 2024
## Motivation for features / changes
Following tensorflow#6821 As pin data is accumulated, unwanted pins can easily
crowd the dashboard. Therefore, this PR adds a button that allows users
to conveniently clear all pins at once.

## Technical description of changes
* 57c6a47 Introduced new action called `metricsClearAllPinnedCards`
* When `metricsClearAllPinnedCards` is dispatched, the reducer removed
all pinned cards in the state.

* a04c2d7 Added `clear all pins` button in the pinned view container.
  * The button will be shown if there's at least one pinned card.

* f0c3a54 Implemented `removeAllScalarPins` method in the saved pins
data source.
  * This method removes stored pins from local storage.

* e97b110 Added `removeAllPins` effect in the `metrics/effects/index.ts`
* When `metricsClearAllPinnedCards` action is called, this effect will
call `removeAllScalarPins` method defined in the saved pin data source.

* c0edd37 guarded UI feature (button) with feature flag and added
related tests.

## Screenshots of UI changes (or N/A)
### Light mode

![image](https://github.com/tensorflow/tensorboard/assets/24772412/a0793e8b-7fea-45f0-b2d8-4e742ca40918)


### Dark mode

![image](https://github.com/tensorflow/tensorboard/assets/24772412/581468a1-1a9c-4ab4-b70a-13c5a5b168f6)

## Detailed steps to verify changes work correctly (as executed by you)
Unit test pass  & cl TAP presubmit pass
## Alternate designs / implementations considered (or N/A)
I also considered a feature to select a pinned card and remove the
selected pinned card, but I thought that this would be the same as
pressing the 'unpin' button individually from the user's perspective. So
I implemented a 'clear all pins' button that removes all pinned cards.
Any feedback is appreciated!
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants