feat: masquerade bar#260
Conversation
9fe2e7e to
2646835
Compare
| <Slot id="org.openedx.frontend.slot.header.mobile.v1" /> | ||
| </nav> | ||
| </header> | ||
| <Slot id="org.openedx.frontend.slot.header.masqueradeBar.v1" /> |
There was a problem hiding this comment.
This is a course masquerade bar, innit? Like its sibling, the course navigation bar. Maybe we should rename it. Probably. Almost sure of it.
There was a problem hiding this comment.
This also makes me think: the right home for these two is probably-almost-100%-sure not here, but in frontend-app-learning... once that gets converted.
There was a problem hiding this comment.
I ran into this from the other side. I noticed that the bar requires a courseId but doesn't fully guard against one not being there.
My question was "does this need to be course-specific?" I could imagine wanting to masquerade for learner dash or something (not something the backend currently supports, but I figure from a frontend perspective it could be the same widget)
There was a problem hiding this comment.
I considered the Learner Dash angle when I first reviewed the original PR. It turns out they're very different beasts: not worth unifying. In other words, this is really-really just a course masquerade bar. Not least of which because it requires a courseId.
|
Ok @brian-smith-tcril, I'm reasonably happy with this. Once frontend-app-learning is converted, this should just drop in - with no page reloads. |
cea4e15 to
85f3de3
Compare
brian-smith-tcril
left a comment
There was a problem hiding this comment.
LGTM!
Left a couple comments in there, but nothing that feels like it should block this from landing.
| } | ||
| const targetPath = new URL(target.url).pathname; | ||
| if (isClientRoute(targetPath)) { | ||
| if (targetPath !== location.pathname) { |
There was a problem hiding this comment.
Will this ever be false? Wouldn't findActiveTab catch the match and early return in this scenario?
There was a problem hiding this comment.
Agreed. Dead code. Removed.
85f3de3 to
059e3a9
Compare
Adds a header strip at the top of the course view that combines two
role-aware widgets: the course-tabs navigation (already in tree under
its own opt-in) and a new masquerade bar. Both live under a unified
shell/header/course-bar/{navigation,masquerade}/ tree and share a
course_home metadata fetch.
Apps declare course-bar membership under providesCourseBarRolesId
(navigation tabs) and additionally enable the masquerade widget on
those routes by listing the same role under
providesCourseBarMasqueradeRolesId. Masquerade is a refinement of the
course bar, not an independent feature: a role only present in the
masquerade list is ignored.
Course staff can use the masquerade widget to view a course as a
different role (Staff, a group like Audit) or as a specific learner.
When a selection causes the user's current page to no longer be
visible, the bar redirects them: the post-masquerade course-tabs list
is the source of truth, and if the current path is no longer in it
the user is sent to the first remaining tab (in-app via react-router
when possible, hard-redirect otherwise).
Co-Authored-By: Diana Villalvazo <diana.villalvazo@wgu.edu>
Co-Authored-By: Jesus Balderrama <jesus.balderrama.wgu@gmail.com>
Co-Authored-By: Claude <noreply@anthropic.com>
059e3a9 to
222ce55
Compare
|
🎉 This PR is included in version 1.0.0-alpha.45 🎉 The release is available on: Your semantic-release bot 📦🚀 |
Description
Introduces a course bar at the top of the course view that combines two role-aware widgets in a single header strip: the course-tabs navigation (which previously lived in its own directory) and a new masquerade widget that lets course staff view the course as a different role (Staff, a group like Audit) or as a specific learner.
Apps declare which routes get the navigation tabs by listing roles under
providesCourseBarRolesId. To additionally enable the masquerade widget on those routes, they list the same roles underprovidesCourseBarMasqueradeRolesId. Masquerade is a refinement of the course bar: a role declared only under the masquerade key (without a matching course-bar declaration) is ignored.When a masquerade selection causes the user's current page to no longer be visible, the bar redirects them. The course-tabs metadata is the source of truth: after a successful selection it fetches the post-masquerade tab list, and if the current path is no longer represented, navigates to the first remaining tab (in-app via react-router when possible, hard-redirect otherwise).
Testing
The easiest way to test this is to prepare this PR, openedx/frontend-app-instructor-dashboard#198, and openedx/frontend-template-site#18, then to set frontend-base and frontend-app-instructor-dashboard as workspace packages in frontend-site (like one normally would). After the usual `npm i; npm run dev:packages` with a properly up-to-date tutor@main deployment, it should be possible to compare the Instructor Dashboard's masquerade bar (at, for example, http://apps.local.openedx.io:8080/instructor-dashboard/course-v1:OpenedX+DemoX+DemoCourse/course_info) with the existing one in Learning:
Screencast.From.2026-05-05.18-23-20.mp4
LLM usage notice
Built with assistance from Claude.