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

feat: Notification Plugin Slots #1368

Merged
merged 8 commits into from
May 13, 2024
Merged

feat: Notification Plugin Slots #1368

merged 8 commits into from
May 13, 2024

Conversation

rijuma
Copy link
Member

@rijuma rijuma commented Apr 22, 2024

Description

This feature is part of the roadmap for the openedx/platform-roadmap#332 issue.

It adds three Plugin Slots wrapping the UpgradeNotifications component and one for the LockPaywall.

It also refactors the mocked PluginSlot to allow proper testing on rendering and wrapped content.

alangsto and others added 3 commits April 19, 2024 14:11
* chore: Updated PluginSlot mock to support children and test ids

* chore: Updated mocked PluginSlot

* chore: Added unit test for MockedPluginSlot

* fix: Updated slot name ids
Copy link

codecov bot commented Apr 22, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 88.73%. Comparing base (1c3610e) to head (71a23d2).

Additional details and impacted files
@@            Coverage Diff             @@
##           master    #1368      +/-   ##
==========================================
+ Coverage   88.72%   88.73%   +0.01%     
==========================================
  Files         302      303       +1     
  Lines        5217     5222       +5     
  Branches     1295     1296       +1     
==========================================
+ Hits         4629     4634       +5     
  Misses        572      572              
  Partials       16       16              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@rijuma rijuma marked this pull request as ready for review April 22, 2024 19:59
Copy link

@arbrandes arbrandes 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 this! However, as noted in individual comments, we should remove content from plugin slots that shouldn't be on by default. Furthermore, I'd like to try and make the slots more generic, if at all possible.

pluginProps={upgradeNotificationProps}
testId="outline-tab-slot"
>
<UpgradeNotification {...upgradeNotificationProps} />

Choose a reason for hiding this comment

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

A few things:

  • The UpgradeNotification component should not be present by default
  • If there are no other desirable uses of UpgradeNotification, the component itself should be removed from the codebase (and made into a plugin that lives elsewhere)
  • The props are too feature-specific for a generic plugin slot; we should find a way to generalize the API. Off the top of my head: we need a way to have a backend Django plugin insert data into the React context, and then either pass that down explicitly into the plugin as a prop, or have the plugin itself reach into the global context. Is the backend code for this feature already a plugin?

Copy link
Contributor

Choose a reason for hiding this comment

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

I'd agree the UpgradeNotification is likely not used by other sites but hard to know for sure. For points 1 and 2 would it make sense to separate the actual DEPR of this component from the additive change here? It seems to me we can separate these two initiatives.

There's probably an opportunity to narrow down or fully remove props passed into this. I'll have us take a look into that. Removing anything that isn't direct context of the parent location (OutlineTab) would help us keep this more generalized for the future. But, I'd hesitate to over architect how this slot is works, such as requiring a backend package for props, if we don't have any other use cases yet. For this case, our plugin is just small UX changes that don't require a backend.

Choose a reason for hiding this comment

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

On the DEPR front, there's some nuance here that we need to explore. From Open edX's point of view, the deprecation and removal process would ideally happen before the Redwood cutoff on May 9th. This is because 1) this code doesn't exist in Quince, and 2) if it becomes part of Redwood we'll have to support it for much longer, and I believe the consensus on the Axim engineering side is that we don't want the community to have to do that.

Also, to make sure we're on the same page, since this has been found not to be a part of the core Open edX product (as per the roadmap proposal: openedx/platform-roadmap#332 (comment)), it should leave no room for doubt whether it should stay in or not. It's just a matter of when.

Copy link

@arbrandes arbrandes Apr 26, 2024

Choose a reason for hiding this comment

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

For this case, our plugin is just small UX changes that don't require a backend.

My concern here is that by creating a PluginSlot, we're actually creating an API entrypoint. We want to strive to make it both generic and stable. If the plugin slot only works with a very specific component, then it's not much better than just having the component be there behind a configuration variable. And if we don´t make it stable, it doesn't make it very useful for people that don´t want to fork the codebase to introduce something here.

Hence, the effort to generalize this as much as we can. It might not be entirely possible given the short time-frame, but I believe we should at least give it our best shot.

I think there might be an example of a callback doing something about generalization in the AI Translation plugin implementation. Let me see if I can find it.

Copy link
Contributor

Choose a reason for hiding this comment

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

Thanks, I'm actually exploring the option that maybe we simply shouldn't be passing props at all to these slots. I suspect everything we're using can be gotten from redux on the plugin side. That seems like a much simpler and generic pattern to follow than trying to maintain an API that's likely to change despite our best efforts.

If that works is that a pattern we'd be okay with?

Choose a reason for hiding this comment

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

Found it:

https://github.com/openedx/frontend-app-learning/blob/master/src/generic/plugin-store/hooks.js#L4

@leangseu-edx came up with a way for plugins to register callback functions that can act on a plugin-store redux slice.

After you've checked which props are actually necessary, and if any feature-specific ones remain, I'd be interested in investigating if we could generalize them with methods such as the above.

Copy link
Contributor

Choose a reason for hiding this comment

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

This does not need a DEPR, it can just be removed. It's 2U specific and has not been released in an Open edX release so you can simply make the PR to remove it.

Copy link
Contributor

@Zacharis278 Zacharis278 Apr 29, 2024

Choose a reason for hiding this comment

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

Good to know we can remove this without DEPR. I'd still propose we make the additive change here that keeps the current learning MFE code as-is but pluggable and follow up with a separate PR that removes the upgrade notification and paywall components from this repo entirely. That is assuming the properties we're passing to the plugin are solved to be generic or removed entirely.

I don't think we could hit that Redwood cutoff if we must include the removal of the current components and any supporting code in this MFE. That work opens up some additional unsolved issues around where the translations go I'd rather not get into if we can help it.

Copy link
Contributor

Choose a reason for hiding this comment

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

@arbrandes I've put together a quick POC of removing 99% of these parameters here: #1379.

That is just the sidebar since that's the most complex bit. If this approach generally looks good we can do the same for everything and update this PR.

Choose a reason for hiding this comment

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

I think going with useModel() is a good direction to take, for now. It doesn't mean we're guaranteeing that the data structures will remain the same, but it will be a demonstration that you can technically do it if you're fine with bearing the risk as a plugin author.

In other words, it works for us if it works for you.

pluginProps={upgradeNotificationProps}
testId="notification-widget-slot"
>
<UpgradeNotification {...upgradeNotificationProps} />

Choose a reason for hiding this comment

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

The same applies here as in the previous comment.

courseId,
}}
>
<LockPaywall courseId={courseId} />

Choose a reason for hiding this comment

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

courseId seems a harmless enough prop to pass down, but like above, we're going to want to make this as generic a slot as possible. Otherwise, the same concept applies as to any other slot: does it make sense for LockPaywall to remain on by default? I suspect not, so it should be removed (and/or moved into a plugin elsewhere).

Copy link
Contributor

Choose a reason for hiding this comment

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

re: "does it make sense for LockPaywall to remain on by default?" This is kinda the same as my comments above on 'DEPR'. I think my answer is initially yes we keep the default unchanged to limit risk. If this new plugin is deployed and we're confident there's no issues with the new experience we can remove the old default. This is a very sensitive component to alter. I'd like to keep 'turn off the plugin' as a switch we can pull rather than a large revert if there are problems.

Choose a reason for hiding this comment

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

Do you have an idea of what the timeframe would be to gain the confidence necessary to do the removal? We need not remove the component itself from the codebase, but it would be best if we could at least remove it as default content inside the PluginSlot by Redwood.

Copy link
Contributor

@Zacharis278 Zacharis278 May 3, 2024

Choose a reason for hiding this comment

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

If we aren't actually removing the existing component we can import it inside the plugin as a second step. I'd say we can follow up with that part very quickly, maybe In a week or so.

edit: a week after we turn this on, not a week after this is merged.

pluginProps={upgradeNotificationProps}
testId="notification-tray-slot"
>
<UpgradeNotification {...upgradeNotificationProps} />

Choose a reason for hiding this comment

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

Same here. Plus, we should check with Product what to do if verifiedMode is never used. Does it mean we'll always just show a "no notifications" message?

@Zacharis278 Zacharis278 changed the title feat: Upgrade Plugin Slots feat: Notification Plugin Slots May 2, 2024
* feat: make notification plugin api generic

* feat: include new sidebar and tests

* feat: tweak sidebar toggle
@Zacharis278
Copy link
Contributor

@arbrandes this is now updated with all of the upgrade specific props removed and is ready for review. If everything looks good, we can probably make the Redwood cutoff.

@Zacharis278
Copy link
Contributor

@arbrandes apologies for multiple pings on this but we're running up against some internal timelines to get this plugin testable on edx.org stage. Do you know when this can get reviewed merged?

Zacharis278
Zacharis278 previously approved these changes May 10, 2024
@Zacharis278 Zacharis278 self-requested a review May 10, 2024 20:31
@Zacharis278 Zacharis278 removed their request for review May 13, 2024 16:30
Copy link

@arbrandes arbrandes left a comment

Choose a reason for hiding this comment

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

I'm fine with us moving forward here and improving things later, with one exception: can you please change the slot IDs as per openedx/wg-frontend#178 so that we don't have to introduce a breaking change later?

toggleSidebar={() => toggleSidebar(currentSidebar, WIDGETS.NOTIFICATIONS)}
/>
<PluginSlot
id="notification_widget_plugin"

Choose a reason for hiding this comment

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

We're trying to standardize how slots are exposed (details here: openedx/wg-frontend#178). I won't ask you to tackle all that here (we'll probably do it ourselves in this other PR), but in order to avoid a breaking change to the slot ID, do you mind changing it as suggested below?

Suggested change
id="notification_widget_plugin"
id="notification_widget_slot"

Copy link
Contributor

Choose a reason for hiding this comment

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

ahh sounds good I can rename both of these

suspenseComponent(messages.loadingLockedContent, LockPaywall)
<Suspense fallback={<PageLoading srMessage={formatMessage(messages.loadingLockedContent)} />}>
<PluginSlot
id="fbe_message_plugin"

Choose a reason for hiding this comment

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

Following the new naming convention as outlined above:

Suggested change
id="fbe_message_plugin"
id="fbe_message_slot"

Also, what does "fbe" stand for? Might be worth making the slot ID a little longer if it means it's easier to deduce what it's for just from the name.

Copy link
Contributor

Choose a reason for hiding this comment

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

It's short for feature based enrollment, I went back and named this 'gated content' since that's a bit more general purpose anyway.

Copy link

@arbrandes arbrandes 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 bearing with me. Approved!

@schenedx schenedx merged commit 1857b86 into master May 13, 2024
7 checks passed
@schenedx schenedx deleted the feat/upgrade-plugin-slots branch May 13, 2024 20:59
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.

6 participants