Skip to content

Hiding dashboard cards: generalize logic for storing preferences#20365

Merged
guarani merged 3 commits into
wordpress-mobile:trunkfrom
kean:feature/personalize-home-tab-persistence
Mar 27, 2023
Merged

Hiding dashboard cards: generalize logic for storing preferences#20365
guarani merged 3 commits into
wordpress-mobile:trunkfrom
kean:feature/personalize-home-tab-persistence

Conversation

@kean

@kean kean commented Mar 20, 2023

Copy link
Copy Markdown
Contributor

Related issue: #20296

Hey 👋. I'm working on adding an ability to hide any of the dashboard cards. It is the first PR in the series.

The PR contains the necessary groundwork for allowing any dashboard cards to be hidden. It introduces a new BlogDashboardPersonalizationService type to manage these preferences. The keys for the cards are generated dynamically. The format of the keys and the data matches the format previously used for Prompts and Blaze cards, ensuring the existing data is migrated automatically.

Testing Instructions

There are no functional changes. I performed the following tests to verify there are no regressions:

Test 1

  1. Open the Dashboard and hide the Prompts card by selecting "Turn off prompt" in the context menu (three dots)
  2. Verify that the Prompts card and the Prompts header in the "Create New" menu are both hidden
  3. Open Menu / Site Settings
  4. Verify that the "Show Prompts" toggle is off
  5. Turn the toggle on
  6. Open Dashboard and verify that the Prompts card is now visible again

Test 2

  1. Tap the context menu (three dots) on the Blaze card and select "Hide this"
  2. Verify that the Blaze card is still hidden

Test 3

  1. Install the previous version of the app (clean install)
  2. Tap the context menu (three dots) on the Prompts card and select "Turn off prompts"
  3. Update the app to the version from this PR
  4. Verify that the Prompts card is still hidden

Test 4

  1. Install the previous version of the app (clean install)
  2. Tap the context menu (three dots) on the Blaze card and select "Hide this"
  3. Update the app to the version from this PR
  4. Verify that the Blaze card is still hidden

Regression Notes

  1. Potential unintended areas of impact:
    The existing feature for managing card visibility ("Turn off prompts", "Hide this" on the Blaze card)
  2. What I did to test those areas of impact (or what existing automated tests I relied on):
    I tested the scenarios from the "Testing Instructions" that included installing the previous version of the app and performing the migration.
  3. What automated tests I added (or what prevented me from doing so)
    I added full test coverage for the new service for managing preferences and also tested its integration with the service responsible for parsing the cards and deciding which ones to display

PR submission checklist:

  • I have completed the Regression Notes.
  • I have considered adding unit tests for my changes.
  • I have considered adding accessibility improvements for my changes.
  • I have considered if this change warrants user-facing release notes and have added them to RELEASE-NOTES.txt if necessary.

@kean kean marked this pull request as ready for review March 20, 2023 23:03
@guarani guarani self-requested a review March 21, 2023 19:00
@guarani guarani added this to the 22.1 milestone Mar 21, 2023

@guarani guarani left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thank you for the PR!

It is the first MR in the series.

Just to double-check, is the "MR" here meant to be PR or does it stand for something else?

The keys for the cards are generated dynamically. The format of the keys and the data matches the format previously used for Prompts and Blaze cards, ensuring the existing data is migrated automatically.

I left a comment in the code about your approach which involves a new key for storing the Prompts key and thus migration. I'm eager to hear your thoughts.

Test 1

  1. Open the Dashboard and hide the Prompts card

In the case of the Prompts card, hiding corresponds to tapping "Turn off prompts", right? I noticed that the copy isn't consistent here because it's also called "Show Prompts" in site settings, but AFAIK they do the same thing. This would be an unrelated & separate UI issue though, so no need to address it.

Test 2

  1. Remove the Prompts card in the current version of the app
  2. Update the app to the version from this PR
  3. Verify that the Prompts card is still hidden

If we go with a different approach that doesn't involve changing the key names for prompts, I think this particular test would no longer be needed. For the current approach you've used, I think it's a valuable addition here to the regression tests 💯

Test 3

  1. Repeat tests for the Blaze card

I'm not sure the testing steps are very clear here. Only Test 1 seems applicable; however, the Blaze card (to my knowledge) doesn't have the option to turn it back on (although I'm not very familiar with the feature so might have missed something).
Test 2 doesn't seem applicable because the key for Blaze (blaze-card-enabled-site-settings) isn't changed by this PR. Could you make more explicit testing steps? This would help me understand how the change has been tested and provides me with more straightforward testing scenarios to follow myself.

PR submission checklist:

  • I have completed the Regression Notes.

When filling out the release notes, please try to answer them as best you can and if they're not applicable, answer with a sentence or two explaining why. Thanks!

Comment on lines +22 to +33
func setEnabled(_ isEnabled: Bool, for card: DashboardCard) {
var settings = getSettings(for: card)
settings[siteID] = isEnabled
repository.set(settings, forKey: makeKey(for: card))

NotificationCenter.default.post(name: .blogDashboardPersonalizationSettingsChanged, object: self)
}

private func getSettings(for card: DashboardCard) -> [String: Bool] {
repository.dictionary(forKey: makeKey(for: card)) as? [String: Bool] ?? [:]
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

If we go ahead with this change, keys for Blogging Prompts and Blaze will be dynamically generated. I see how this can help provide a direct mapping between DashboardCards and their persistence key without having to make that mapping explicit. However, I'm not aware of any other advantages.

The biggest disadvantage I see is that the raw key is no longer searchable in the codebase. This could come up when inspecting NSUserDefaults' content and figuring out where the keys found there are defined in the codebase. The other downside is that "key migration" logic is needed for the prompt key. There's no perfect time to remove this logic to clean up the code base, someone will have to figure out when few enough devices are using the old key that it's safe to clean this up.

What are you thoughts on these points?

@kean kean Mar 21, 2023

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I was also debating whether to keep the constants or generate the keys dynamically. The advantage of generating them dynamically is that there are fewer changes needed when new cards that require personalization are added. The disadvantage, as you pointed out, is that they keys are no longer visible in UPRUConstants.

The biggest disadvantage I see is that the raw key is no longer searchable in the codebase.

I can suggest two options how to address it:

  1. Add static keys (one per card) to UPRUConstants and create a DashboardCard → key mapping
  2. Move makeKey(for card: DashboardCard) method I added to UPRUConstants, so it's more visible

I'll be happy to change it to what you think is the best option. I think making these keys visible/searchable is a good idea, but there are dozens of UserDefaults keys defined outside of UPRUConstants, so I assumed these constants were only for the keys used in UserPersistentRepositoryUtility.

The other downside is that "key migration" logic is needed for the prompt key.

The data migration is not needed because I added .prompts as an exception:

private func makeKey(for card: DashboardCard) -> String {
    if card == .prompts {
        // This key was defined statically in the previous versions, and the
        // naming convention wasn't matching the other keys, so it had to be
        // special-cased to avoid losing data.
        return "prompts-enabled-site-settings"
    }
    return "\(card.rawValue)-card-enabled-site-settings"
}

I think we can keep it like this indefinitely: it's a small exception and is documented.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The disadvantage, as you pointed out, is that they keys are no longer visible in UPRUConstants.

I want to clarify that the disadvantage I pointed out above relates to seachability, not visibility. I don't think making the keys searchable requires them to be defined in the same place.

I think making these keys visible/searchable is a good idea, but there are dozens of UserDefaults keys defined outside of UPRUConstants, so I assumed these constants were only for the keys used in UserPersistentRepositoryUtility.

I don't have an issue with defining the keys for the Blaze, Prompts, etc. cards in a different place.

The data migration is not needed because I added .prompts as an exception:

Thanks, I misunderstood it the first time around. The prompt key remains unchanged, so no migration 👍

  1. Add static keys (one per card) to UPRUConstants and create a DashboardCard → key mapping

If you don't think the dynamic keys are required for this implementation, going with the above seems like a good option for now. Dynamic keys can always be revisited if it's clear they make adding cards significantly easier.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I think I got your point about searchable. I tried adding the keys to UPRUConstants, but there were private, which I didn't want to change. So I added the static strings directly to makeKey and retested the migration (or lack thereof) – looks good now. Commit with the change.

@kean

kean commented Mar 21, 2023

Copy link
Copy Markdown
Contributor Author

Just to double-check, is the "MR" here meant to be PR or does it stand for something else?

Yeah, MR (merge request) is a term that's more often used in GitLab, which is what I currently use at work.

In the case of the Prompts card, hiding corresponds to tapping "Turn off prompts", right?

Yes, there is a bit of inconsistency with the Site Settings and with other cards where we'll be adding "Hide this" action to the context menus. I also noticed it and asked Chris about it. For Site Settings, the decision is to remove the "Show prompts" toggle entirely and keep it only in the new "Personalize Home Tab" screen. As for the "Turn off prompts", the naming is different because turning off prompts does a bit more than just hide the dashboard card: it also removes the prompts from the FAB screen.

Could you make more explicit testing steps?

Updated. The goal was to make sure there are no functional changes introduced by this PR.

@kean kean requested a review from guarani March 22, 2023 01:30

@guarani guarani left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Yeah, MR (merge request) is a term that's more often used in GitLab, which is what I currently use at work.

Gotcha! I wasn't familiar with the term.

Yes, there is a bit of inconsistency with the Site Settings and with other cards where we'll be adding "Hide this" action to the context menus. I also noticed it and asked Chris about it. For Site Settings, the decision is to remove the "Show prompts" toggle entirely and keep it only in the new "Personalize Home Tab" screen. As for the "Turn off prompts", the naming is different because turning off prompts does a bit more than just hide the dashboard card: it also removes the prompts from the FAB screen.

I like this idea of only having it in the "Personalize Home Tab" screen" and no longer in the Site Settings. Makes sense 👍

Updated. The goal was to make sure there are no functional changes introduced by this PR.

Thanks! The updated tests look good. I'll hold off re-testing since I suggested a change.

Comment on lines +22 to +33
func setEnabled(_ isEnabled: Bool, for card: DashboardCard) {
var settings = getSettings(for: card)
settings[siteID] = isEnabled
repository.set(settings, forKey: makeKey(for: card))

NotificationCenter.default.post(name: .blogDashboardPersonalizationSettingsChanged, object: self)
}

private func getSettings(for card: DashboardCard) -> [String: Bool] {
repository.dictionary(forKey: makeKey(for: card)) as? [String: Bool] ?? [:]
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The disadvantage, as you pointed out, is that they keys are no longer visible in UPRUConstants.

I want to clarify that the disadvantage I pointed out above relates to seachability, not visibility. I don't think making the keys searchable requires them to be defined in the same place.

I think making these keys visible/searchable is a good idea, but there are dozens of UserDefaults keys defined outside of UPRUConstants, so I assumed these constants were only for the keys used in UserPersistentRepositoryUtility.

I don't have an issue with defining the keys for the Blaze, Prompts, etc. cards in a different place.

The data migration is not needed because I added .prompts as an exception:

Thanks, I misunderstood it the first time around. The prompt key remains unchanged, so no migration 👍

  1. Add static keys (one per card) to UPRUConstants and create a DashboardCard → key mapping

If you don't think the dynamic keys are required for this implementation, going with the above seems like a good option for now. Dynamic keys can always be revisited if it's clear they make adding cards significantly easier.

@guarani

guarani commented Mar 22, 2023

Copy link
Copy Markdown
Contributor

Regression Notes

  1. Potential unintended areas of impact:
    Make sure that if the user hid either Prompts or Blaze settings in the previous version of the app, the settings retained after the upgrade.

This section is meant for something like "this change could effect XYZ functionality". It's might be read by beta testers so it helps for us to list potential unintended areas of impact to help direct any testing efforts toward these.

  1. What I did to test those areas of impact (or what existing automated tests I relied on):
    I tested the scenarios from the "Testing Instructions" that included installing the previous version of the app and performing the migration.

Sounds good!

  1. What automated tests I added (or what prevented me from doing so): n/a

Here I'd encourage you to mention that you did add automated tests to this PR 💯

@guarani guarani left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The changes look solid, thanks for tackling this @kean!

  • Test 1
  • Test 2
  • Test 3
  • Test 4

@guarani

guarani commented Mar 24, 2023

Copy link
Copy Markdown
Contributor

The CI failure happens when working from a fork. I'll push your commits to a separate temporary PR to make CI go green here.

@kean

kean commented Mar 25, 2023

Copy link
Copy Markdown
Contributor Author

Thanks, @guarani. Looks like the checks have passed. I'm looking forward to getting my first PR merged 😊

@guarani

guarani commented Mar 27, 2023

Copy link
Copy Markdown
Contributor

It seems GitHub is down: https://www.githubstatus.com/
The "Confirm merge" button isn't working. Will try again later 🤞 🚀

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.

3 participants