-
Notifications
You must be signed in to change notification settings - Fork 745
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
New NotificationsRoot
component
#9128
Conversation
e0eec93
to
ff1c5f2
Compare
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.
Thank you, @sairina . The overall direction is looking great. I have two high-level suggestions for now that I think would be good to address.
For later reference, the NotificationsRoot
is visually responsible for the following four components which I'll call the messaging components
AuthMessage |
AppError |
GlobalSnackbar |
UpdateNotification |
---|---|---|---|
(1) Decoupling of unnecessary style and layout information (including deletion of related props)
I’d suggest removing all styles that are not directly related to the messaging components. That’s the majority of computed styles (e.g. mainWrapperStyles
, contentStyles
) as well as styles defined in <style>
block. It’d be fine to keep styles that are unnecessary to position these components on a page if there are some. This also applies to related props: fullScreen
, hasSidebar
,maxMainWidth
, and marginBottom
.
Reason
NotificationsRoot
is planned to be used in the following way from plugin index pages:
// LearnIndex
<template>
<NotificationsRoot>
<router-view />
</NotificationsRoot>
</template>
One of the points of CoreBase
refactor is to allow each page of the plugin that’s rendered in the <router-view />
to have full control over its layout, including margins, padding, etc. to gain more flexibility. That wouldn’t be fully possible if we kept unnecessary layout and style dependencies in the NotificationsRoot
.
(2) Decoupling loading state from the default slot
I’d suggest removing v-if="!loading"
from the whole wrapper div here and only using it directly on components that need it, that’s AuthMessage
and AppError
. For example
<KPageContainer v-if="!loading && notAuthorized">
<AuthMessage
:authorizedRole="authorizedRole"
:header="authorizationErrorHeader"
:details="authorizationErrorDetails"
/>
</KPageContainer>
Reason
Keeping v-if="!loading"
on the div that’s also wrapping the default slot has unhappy consequences. Consider the situation demonstrated in the following example when we’d try to set loading state from one of the pages of the Learn plugin:
// LearnIndex
<template>
<NotificationsRoot>
<router-view />
</NotificationsRoot>
</template>
// Library (rendered within the <router-view /> of LearnIndex)
<script>
export default {
created() {
state.loading = true
fetchData().then(() => state.loading = false)
}
}
</script>
At the moment we set state.loading = true
in the created
hook, the Library component would get destroyed (therefore state.loading = false
would never get called) if we kept v-if="!loading"
as is in the NotificationsRoot
. This would make all logic around the loading state rigid and difficult to refactor later (and debug - true story :) - for example, we wouldn't be able to use the global loading state at all in a way shown in the example above (and we actually already need to do this in some cases and use hacks to overcome the current limitation).
To sum it up, this means we’d only keep things that are absolutely unnecessary for notifications and messaging components in the NotificationsRoot
(and if we find out we need something more from it in the future, we can do that when a need arises while considering architecture and alternative options to solving that particular need).
I realize that there might be a need to re-use some of the logic that I’m suggesting for deletion from this particular component so here are some possible directions (posting here since it's closely related to what I'm suggesting, but final decisions and implementation are out of the scope of this PR):
|
Also, I know it’s quite an abstract task where we’re trying to switch to a different architecture mindset that's quite the opposite of what we’ve relied on so far in the old |
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 I did prior to the PR was remove |
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.
Thank you for the updates and your work, @sairina, the component is looking good to me.
But, given that there's no styling, I'm wondering if the tests for this component (which were passing and still are all currently passing) are sufficient for this NotificationsRoot
I think that these main scenarios are sufficient. In my opinion, it is better to focus on fewer reliable tests that can be easily maintained rather than plenty of tests just to have everything covered.
I left some comments regarding the implementation of some tests that I think would be good to address but don't see that as blocking.
}); | ||
|
||
it('if user is not authorized, AuthMessage component should be rendered', async () => { | ||
const { wrapper, store } = makeWrapper({ computed: { notAuthorized: () => true } }); |
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 test, as implemented right now, doesn't really test this scenario. Assume that over time we'd make a mistake in code of the notAuthorized
computed property , for example:
notAuthorized() {
if (
this.error &&
this.error.response &&
this.error.response.status &&
this.error.response.status == 403
) {
return false; // should be `return true`
}
return !this.authorized;
},
Even though AuthMessage
wouldn't get displayed after we got 403 response, this test would still pass because notAuthorized
is set to true
no matter of what due to how the test wrapper is created makeWrapper({ computed: { notAuthorized: () => true } })
, giving us the false impression that things work as expected.
I see this pattern in couple of other tests of this suite too. I'd suggest removing anything related to computed
from the whole test suite and mocking rather things that are coming from outside of the NotificationsRoot
(store state etc.) instead of mocking computed properties, similarly to how you did it on lines 57-58.
I wrote more generally about problems of reaching into internal implementation in tests in #9065 (review) if some more information would help.
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.
Everything looks great to me! If there are any issues they'll come out in the wash as we implement it elsewhere. Great work!
@sairina I think it's good to merge this in spite of the DMG build failing |
Yes, the DMG build failure was definitely not caused by any code in this PR! |
Summary
CoreBase
into newNotificationsRoot
componentAuthMessage
AppError
GlobalSnackbar
UpdateNotifications
NotificationsRoot
inapiSpec
References
Fixes #9102
Reviewer guidance
Check to see that the component is doing what is described in the issue (#9102) and check that the tests pass with the
yarn run test-jest
command.Testing checklist
PR process
Reviewer checklist
yarn
andpip
)