-
Notifications
You must be signed in to change notification settings - Fork 24
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
Fix Toast Theme Support and other minor improvements #7751
Fix Toast Theme Support and other minor improvements #7751
Conversation
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.
@philippotto Could you please review these changes as I'd say that this PR changes quite heavily how the toast lib works under the hood. The API does not change but each toast now opens a new rendering context to match the desired theme.
Sadly, these changes introduce cyclic dependencies. Please see below.
…ow-toast-outside-renderin-context
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 fixing this 💯 I left some small comments.
Co-authored-by: Philipp Otto <[email protected]>
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 applied your feedback and tried to clarify why the destroy call needs to be deferred.
The theme looks correct now 👍 But the toast doesn't disappear on its own? The default delay is 6s. I debugged it briefly and notification.close is called, but it doesn't do anything? It works on wkorg, so it shouldn't be related to #7741 which was merged this week. |
…asts - and fix manual timeout of same repeated toast
…ow-toast-outside-renderin-context
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.
The theme looks correct now 👍 But the toast doesn't disappear on its own? The default delay is 6s. I debugged it briefly and notification.close is called, but it doesn't do anything? It works on wkorg, so it shouldn't be related to #7741 which was merged this week.
Thanks for noticing 💪. The problem was caused by the Toast.close
call of the manual timeout introduced. The close call was using the global notification instance and not the one spawed by the component spawned with renderIndependently
. To fix this, the toast lib would need to keep track of all rendered instances of ToastFunctionalComponentWrapper
, which would make the code unnecessary complicated.
Therefore, I came up with a whole new approach by always having only one permanent mounted component wrapping the context for a single notification api.
The single mounted Component containing the Notification-/ Toast-Context is rendered as a direct child to the GlobalThemeProvider
. Therefore I renamed the Wrapper Component to ToastContextMountRoot
. Once the component is rendered for the first time, the Toast Object caches the notification API created by the ToastContextMountRoot
and uses it for future toasts.
In case wk already triggered toasts before this component was rendered, the toast lib tracks pending toasts and shows them in bulk as soon as the notification API is available.
Moreover, I noticed two bugs with the new manual timeout approach to avoid hiding toasts during a tab not being visible (see #7741):
- In case the same toast has a key and is not sticky, triggering the toast over and over 7 seconds, causes the toast to be rendered and close correctly after 6 seconds. But, the subsequent reopening toasts are closed immediately due to excessive pending close calls of the manual timeout functionality. To reproduce this behaviour just repeatedly click the "copy current position" from the position view and observe the subsequent toasts being closed immediately.
- I fixed this by caching the first async close call for the toast and ignoring future async close calls
- In case a toast call doesn't a key but a manual timeout time, the toast duration would be set to
0 -> infinite / sticky
and no manual timeout would be created. I fixed this. Please find my comment highlighting the fix below.
const timeOutInSeconds = timeout / 1000; | ||
const useManualTimeout = !sticky && key != null; | ||
let toastConfig = { | ||
icon: undefined, | ||
key, | ||
duration: 0, | ||
duration: useManualTimeout || sticky ? 0 : timeOutInSeconds, |
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.
Here I fixed the mentioned bug that toasts with no key but a timeout would be sticky automatically, because below a manual timeout was only created if (!sticky && key != null) {....
A toast having no key might occur for a toast call with a component as a message and not a string itself where no key is set manually by the user.
frontend/javascripts/libs/toast.tsx
Outdated
if (useManualTimeout && this.pendingTimeouts[key] == null) { | ||
const timeoutToastManually = async () => { | ||
const splitTimeout = timeout / 2; | ||
await animationFrame(); // ensure tab is active | ||
await sleep(splitTimeout); | ||
await animationFrame(); | ||
// If the user has switched the tab, show the toast again so that the user doesn't just see the toast dissapear. | ||
await sleep(splitTimeout); | ||
this.close(key); | ||
delete this.pendingTimeouts[key]; | ||
}; | ||
this.pendingTimeouts[key] = timeoutToastManually(); |
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.
The manual timeout call is put into the pendingTimeouts object to avoid multiple timeouts leading to the buggy behaviour described above (where a repeatedly triggered to the same key closes subsequent toasts with the same key)
}} | ||
> | ||
{isMainProvider && <ToastContextMountRoot />} |
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.
Here the single global instance of ToastContextMountRoot
is rendered
Great! 💯 Could you update the PR description to reflect this? A short sentence would be enough (you could link to your newer comment).
Would it simplify things when we would simply call
Does this make sense? |
Sure 👍 I just edited the description mentioning that it might be important to only have one existing
Yes, a little imo. But the previous behaviour of the notification / toast API is the one I reproduced: In case a toast with some key already existed, the call was "ignored". The toast was not closed and its timeout also wasn't refreshed. I just investigated this further and it seems I am a little wrong: The timeout time and content of the toast is refreshed, but there is no close & open animation. See https://ant.design/components/notification#notification-demo-update for reference.
Exactly, that how the current version operates. However, in case the content of the toast changes, it should also update in my version. But the timeout is not refreshed.
Sure should I implement it exactly this way or should I leave out the closing and reopening animation? |
if it's easy, yes :) if not, let's keep it as is. in the end, it's not super important. |
Yep, it was doable 👍 and should work now. But during testing chrome showed some weird flickering animation while opening a toast. This also appeared on older versions of the branch but not on wk.org. I couldn't track this down to a cause without a larger time investment. This flickering did not appear in Firefox as well and was also suddenly gone in the current version of the code Thus I deemed this to be a chrome hiccup or so. Could you please look out for such an animation bug during testing? I cannot reproduce it in the current version (testing locally) but I would still like to avoid weird-looking opening animations of toasts on wk.org 😅. Already thank you for testing in advance 🙏 🦜 |
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.
Excellent! Works well for me 👍 Thanks for taking the time to fix this!
* enable proper toast support outside of component context and other minor improvements * adjust toast lib to always render in correct theme * update cyclic dependencies detection * UNDO: fix cyclic deps script output formatting * fix import order in e2e tests * Apply suggestions from code review Co-authored-by: Philipp Otto <[email protected]> * Apply pr feedback * apply pr feedback * Change to a permanent toast context root point to reenable closing toasts - and fix manual timeout of same repeated toast * update comment * reopen toast upon repetitive open call with the same key * move canceling closing of pending toast binding second wait expression --------- Co-authored-by: Philipp Otto <[email protected]>
This PR modifies the toast lib to render the notifications in the user-set theme. Previously, the theme was always set to light and therefore the background of the toast messages in dark mode was white. The API of the toast lib doesn't change at all in this PR.
How it works: According to the antd toast docs antd automatically creates a new rendering hierarchy for each spawned toast. For rendering the toast in the configured theme, a hook needs to be used that returns a context holder and API to open the toasts from. This is now automatically done by the Toast lib by mounting a single functional component (FC) using this hook as a direct child of the
GlobalThemeProvider
. Once this FC is rendered for the first time, the theme-aware notification API is available to the toast lib and can be used to render some toasts. Note, that the FC with its notification API should be treated as a singleton and only mounted once as else an old notification API might be lost with references to e.g. some older toast that are sticky and still being displayed.URL of deployed dev instance (used for testing):
Steps to test:
Issues:
(Please delete unneeded items, merge only when none are left open)
[ ] Updated changelog