-
Notifications
You must be signed in to change notification settings - Fork 393
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
Case Dismissed: Forcibly show DAppConnectionInfoBar popover on first dApp connection #3464
Conversation
c7f12f3
to
d16131a
Compare
5529ecb
to
3940cf6
Compare
These are items that are displayed to the user either exactly once, or once until the user closes them. The default connection popover is supported, but not yet hooked up. This is designed to be a useful primitive for any new-feature banner, or first-time-use banner. Like many items in preferences, the current list of already-shown dismissable items is initialized when the extension starts, and then updated along the way based on UI actions.
The first connection after a version with the info bar enabled is used will show the popover, then future connections will not. Uses the dismissable item functionality in the preferences service.
The default toggle was being rendered with "Taho as default" being on the left. After some discussion, the fact that it was reversed compared to other toggles (where "on" is on the right) isn't ideal. This commit puts "Taho as default" on the right, and drops the `leftToRight` parameter added to `SharedToggleButton` to make that possible in the first place.
deb4865
to
4c3b7c1
Compare
Finally ready to go here I think. |
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.
Tested and looks good! Left a few comments
) | ||
|
||
this.preferenceService.emitter.on( | ||
"dismissableItemMarkedAsShown", |
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.
I think the benefit to this rather than doing it in the method below that calls markDismissableItemAsShown
is that within the preference service we can decide when we dispatch the event and thus update the store, hence we have more flexibility. Though this could turn quite verbose if we use it for everything.
* be used for tours, or for popups that can be retriggered but will not | ||
* auto-display more than once. | ||
*/ | ||
export type SingleShotItem = "default-connection-popover" |
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.
What do you think about OneTimeDismissableItem
?
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.
So the distinction I'm trying to draw here, and I think I've done a pretty poor job of it lol, is between items that are dismissed through a user's “please don't show this to me again”-type action, or a banner that needs to be explicitly closed but doesn't block content, and items that are dismissed automatically. I think SingleShotItem
is actually a decent name for the latter, but DismissableItem
as the umbrella type doesn't reflect that very well.
Maybe it's just AutomaticallyDismissableItem
as a counterpart to ManuallyDismissableItem
though? 🤔
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.
Ok then I think this is fine as it is 👍
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.
Happy to see/hear ideas for a better name here. Fortunately it's in the type, so it doesn't get persisted, so we can deliberate a little without blocking the merge.
@@ -24,7 +29,7 @@ function DefaultConnectionPopover({ close }: PopoverProps): ReactElement { | |||
return ( | |||
<div | |||
className={classNames("bg", { | |||
fadeIn: !isClosing, | |||
fade_in: !isClosing, |
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.
This will break the animation because we haven't made this change yet 👀
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.
Oiiiii how did it sneak innnnnn.
Since this is in the new stuff and I have these changes, how about we keep it and I open the follow-up PR that fixes the fade_in
?
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.
Went ahead and dropped this into #3485 .
] = useState(shouldImmediatelyShowPopover) | ||
|
||
const closeDefaultConnectionPopover = useCallback(() => { | ||
if (shouldImmediatelyShowPopover && isShowingDefaultConnectionPopover) { |
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.
I think we can remove the check for isShowingDefaultConnectionPopover
here. Is there a reason we're using useCallback
on these functions?
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.
I have to tell you that my radar for when useCallback
is the right move and when it's the wrong one is as broken as the tree that was used to make my desk.
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.
Sorry, I missed the first part of the note—why do you think that? It seems like the correct condition, no? If it's not showing and we're set to immediately show it, we shouldn't dispatch anything, because that means it's closing.
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.
Because this only runs when the popover is open right?
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.
I always assume propagation delays for stuff like this, not least because there are cases where we delay rendering changes to wait on animations, etc. We can always case by case those, but it's easier to just consistently get the condition right so reasoning is localized rather than requiring global knowledge of caller behavior.
@@ -203,6 +211,8 @@ export default class PreferenceService extends BaseService<Events> { | |||
) | |||
} | |||
|
|||
// FIXME This should not be publicly accessible, but triggered by observing | |||
// FIXME an event on the signer service. |
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.
👍
// FIXME Both of these should be done as observations of the preference | ||
// FIXME service event rather than being managed by `main`. |
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.
This pattern seems great but I reckon the logic is going to get a bit hard to follow 🤔. Do we want to only execute calls to other services on events emitted by services as reactions to mutations?
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.
Definitely yes for cross-service stuff. No reason Main should be deciding what the ProviderBridgeService should be doing with an event—that is the ProviderBridgeService's responsibility. The only such triggers from Main should be directly due to redux actions, and in any such action we should be asking “is the service reacting to the user's change, or is the service reacting to a system change”. In this case, the preferences service reacts to the user's change, and that system then becomes a system change that triggers other adjustments. This is just separation of responsibilities, but we haven't done a great job of following it everywhere.
The short articulation is: services are responsible for their own state and for reacting to the state of other services. This is another reason why Main really needs to be renamed to ReduxService; it's charged with mediating with redux, it is NOT some sort of superservice meant to mediate between many services, unless there's some redux-based thing that needs to intervene. Similarly, this is why settings need to make it into PreferencesService—that allows it to be the source of truth for settings, not the redux store, which should generally not be the source of truth for anything.
This opens up the possibility of further paring down the redux store by only storing “recent” things in it, and fetching async from the backend for less recent things (e.g. transactions). I think that's months away, and it won't make sense for everything, but it's what the overall architectural approach is rooted in.
this.version(17).stores({ | ||
preferences: "++id", | ||
signersSettings: "&id", | ||
shownDismissableItems: "&id,shown", |
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.
Boolean can't be indexed, so adding a shown
here does not make much sense.
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.
Bah, yeah. I'd rather not add a migration here but maybe it won't be necessary given we haven't shipped this yet.
## What's Changed * Repeater Connection: Forward requests to new default when default is switched off during dApp connection flow by @Shadowfiend in #3462 * Auto-Not-So-Matic: Fix two matic.network URLs to polygon.technology by @Shadowfiend in #3483 * v0.38.0 by @kkosiorowska in #3480 * Case Dismissed: Forcibly show DAppConnectionInfoBar popover on first dApp connection by @Shadowfiend in #3464 * Add Hardhat Fork Functionality by @0xDaedalus in #3247 * Faded Jeans: Rename fadeIn class to fade_in by @Shadowfiend in #3485 * Fix issue for discovery transaction hash by @kkosiorowska in #3458 * Full Sweep: Drop the USE_UPDATED_SIGNING_UI feature flag by @Shadowfiend in #3475 * Token Discovery - Remap redux asset balances by @hyphenized in #3195 * Make specific warnings for adding custom asset by @kkosiorowska in #3478 * Run NFTs e2e tests on a controlled wallet address by @michalinacienciala in #3487 * v0.38.1 by @jagodarybacka in #3484 **Full Changelog**: v0.38.1...v0.39.0 Latest build: [extension-builds-3496](https://github.com/tahowallet/extension/suites/13792957673/artifacts/764738599) (as of Thu, 22 Jun 2023 14:27:32 GMT).
Draft until #3451 lands.
Adds a
DismissableItem
concept and related functionality to thePreferencesService
and to the UI slice, providing a common patternfor things that should be shown to the user exactly once, e.g. new
feature banners and related functions.
This PR will complete the work on updated dApp connections.
Latest build: extension-builds-3464 (as of Fri, 16 Jun 2023 17:51:17 GMT).