Repository navigation
feat: remove legacy Django unit editor - #38985
Conversation
|
Thanks for the pull request, @salman2013! This repository is currently maintained by Once you've gone through the following steps feel free to tag them in a comment and let them know that your changes are ready for engineering review. 🔘 Get product approvalIf you haven't already, check this list to see if your contribution needs to go through the product review process.
🔘 Provide contextTo help your reviewers and other members of the community understand the purpose and larger context of your changes, feel free to add as much of the following information to the PR description as you can:
🔘 Get a green buildIf one or more checks are failing, continue working on your changes until this is no longer the case and your build turns green. DetailsWhere can I find more information?If you'd like to get more details on all aspects of the review process for open source pull requests (OSPRs), check out the following resources: When can I expect my changes to be merged?Our goal is to get community contributions seen and reviewed as efficiently as possible. However, the amount of time that it takes to review and merge a PR can vary significantly based on factors such as:
💡 As a result it may take up to several weeks or months to complete a review and merge your PR. |
The legacy unit editor (controlled by LEGACY_STUDIO_UNIT_EDITOR waffle flag) has been fully removed. The MFE-based unit editor (frontend-app- authoring) is now the only editor and is always active. Removed: - LEGACY_STUDIO_UNIT_EDITOR CourseWaffleFlag - container_handler legacy Django-rendered path (now always redirects to MFE) - xblock_edit_view and xblock_edit_handler URL (/xblock/<key>/action/edit) - container.html and container_editor.html templates - unit_outline_spec.js and related legacy tests Kept (still used by MFE): - container_embed_handler and /container_embed/<key> URL - container_chromeless.html template (rendered for MFE iframes) - use_new_unit_page serializer field (hardcoded True; MFE still reads it) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
717835e to
2d87434
Compare
- Remove unused imports in block.py (xframe_options_exempt, render_to_response, _get_item_in_course) - Remove unused libraries_v1_enabled import in component.py - Remove unused ADVANCED_COMPONENT_TYPES import in test_contentstore.py - Remove unused BeautifulSoup import in test_block.py - Fix trailing newlines in test_block.py and test_container_page.py - Remove deleted unit_outline_spec.js from Karma spec list in main.js Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The test_container_html was testing legacy Django-rendered HTML content (breadcrumbs, section tags from the deleted container.html template). Removed it since the legacy editor is gone and the split_test container URL (/container/<key>) was legacy-only — the MFE does not use it. Also reverts the get_parent_xblock fallback added to container_handler as it was adding new functionality rather than just removing legacy code. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
| @@ -158,10 +158,14 @@ def get_use_new_course_outline_page(self, obj): | |||
|
|
|||
| def get_use_new_unit_page(self, obj): | |||
There was a problem hiding this comment.
use_new_unit_page is kept in the serializer response for now as a field returning True. Once the MFE confirms it no longer reads this key from the waffle flags API, the field and its method can be removed in a follow-up PR.
…toggles - Restore xblock_edit_view, container_editor.html, and the xblock_edit_handler URL — the Authoring MFE still calls /xblock/<id>/action/edit to load the xblock edit modal in an iframe (getLegacyEditModalUrl in xblock-container-iframe) - Remove use_new_unit_page() from toggles.py — it had no remaining callers after container_handler was simplified to always redirect to the MFE Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
| self.assertIn(expected_section_tag, html) # noqa: PT009 | ||
| self.assertRegex(html, re.compile(expected_breadcrumbs, re.DOTALL)) # noqa: PT009 | ||
|
|
||
| def test_public_container_preview_html(self): |
There was a problem hiding this comment.
Question: container_handler used to fall through to rendering container.html for xblocks-with-children that aren't unit/library-content/split-test-child (what test_container_on_container_html, deleted). Now it raises Http404 unconditionally for that case.
xblock_studio_url() still generates /container/<key> links for such xblocks and surfaces them as studio_url via the REST API, so this path looks reachable in principle (e.g. a nested container xblock other than a unit/library_content/split_test child).
Is this confirmed dead in the current MFE flow? If so, a small test asserting the 404 (replacing the deleted one) would guard against an accidental regression later.
| ADVANCED_COMPONENT_TYPES, | ||
| ['Word cloud', 'Annotation', 'split_test'], | ||
| ) | ||
|
|
There was a problem hiding this comment.
Nit: two consecutive blank lines left here after the deleted methods above — worth squashing to one.
| def test_edit_unit(self): | ||
| """Verifies rendering the editor in all the verticals in the given test course""" | ||
| self._check_verticals([self.vert_loc]) | ||
|
|
There was a problem hiding this comment.
Nit: same as above — two consecutive blank lines left after the deleted methods here too.
|
Hey @salman2013 and @irfanuddinahmad , are you still working on this? |
feanil
left a comment
There was a problem hiding this comment.
@kdmccormick I think the are ready for it to be more thoroughly reviewed. I looked through some of it and llm review found the follow reasonable issues but I still want to go through it from an approach perspective to make sure it makes sense.
| """ | ||
| return not LEGACY_STUDIO_UNIT_EDITOR.is_enabled(course_key) | ||
|
|
||
|
|
|
|
||
| raise Http404 |
There was a problem hiding this comment.
On master a /container/<key> request for a block with children that isn't a unit, library content or a split test child renders the legacy container page. Now it is a 404, but Studio still hands out those URLs: the "Used in" links on the group configurations page point at /container/<split_test> (course_group_config.py), and the clipboard source_edit_url and the library component usage links point at /container/<parent> when the parent is a nested container. The MFE renders a container page for any block with children since openedx/frontend-app-authoring#3058, so redirect those blocks there too.
With this change on a scratch course, /container/ gives 302 for the unit, a split_test and a wrapper block and 404 for a problem. The current head gives 302/404/404/404 and master gives 302/200/200/200.
| raise Http404 | |
| if xblock_has_own_studio_page(xblock): | |
| return redirect(get_unit_url(course.id, xblock.location)) | |
| raise Http404 |
xblock_has_own_studio_page is in helpers.py next to the imports at the top of this file. Then add a test for the split test case here since test_container_on_container_html went away.
| Always returns True. The legacy unit editor has been removed. | ||
| This method will be removed in a follow-up cleanup. | ||
|
|
||
| See https://github.com/openedx/edx-platform/issues/36275 |
There was a problem hiding this comment.
frontend-app-authoring has never read this key (nothing in its history matches use_new_unit_page), so there is nothing to wait on from the MFE. Point this at the ticket that tracks dropping the hard-coded fields, like get_use_new_home_page above does.
| Always returns True. The legacy unit editor has been removed. | |
| This method will be removed in a follow-up cleanup. | |
| See https://github.com/openedx/edx-platform/issues/36275 | |
| Always returns True. The legacy unit editor has been removed and the | |
| Authoring MFE never read this key; it goes when the other hard-coded | |
| fields in this serializer are dropped. | |
| See https://github.com/openedx/openedx-platform/issues/37497 |
| @override_waffle_flag(toggles.LEGACY_STUDIO_UNIT_EDITOR, True) | ||
| def test_edit_unit(self): | ||
| """Verifies rendering the editor in all the verticals in the given test course""" | ||
| self._check_verticals([self.vert_loc]) |
There was a problem hiding this comment.
This was the only caller of _check_verticals (line 985 in this file), so delete that too. Its 200 assertion is wrong now that the handler redirects. Not a blocker but while you're here, check_verticals in tests/utils.py has no callers either.
| 'js/spec/views/assets_spec', | ||
| 'js/spec/views/baseview_spec', | ||
| 'js/spec/views/paged_container_spec', | ||
| 'js/spec/views/unit_outline_spec', |
There was a problem hiding this comment.
You removed the spec for js/views/unit_outline but the view is still shipped, along with unit_outline_child.js and unit-outline.underscore, and container.js still mounts it on .wrapper-unit-overview, an element only container.html had. Delete the view and its pieces here too, otherwise keep the spec so the view stays covered until they go.
feanil
left a comment
There was a problem hiding this comment.
Found a couple more issues while doing a more thorough review. The approach and level of cleanup looks good, looks like some more JS code was missed which can be cleaned up and we need to add some tests back but I think this is pretty close to landing after the comments are addressed.
| self.store.publish(self.released_public_vertical.location, self.user.id) | ||
| self.store.publish(self.vertical.location, self.user.id) | ||
|
|
||
| def test_container_html(self): |
There was a problem hiding this comment.
These were the only tests rendering a full container page and container_embed_handler, which is what the MFE loads, has no test at all. Point get_page_html in tests/utils.py at container_embed_handler instead of deleting these, it has no other callers after this PR. Keep the section tag assertion for the unit, the split test and the nested wrapper and drop the breadcrumbs one since the chromeless page doesn't render them. I tried that on this branch and all three cases pass.
| return render_to_response('container.html', container_handler_context) | ||
| else: | ||
| return HttpResponseBadRequest("Only supports HTML requests") | ||
| course, xblock, lms_link, preview_lms_link = _get_item_in_course(request, usage_key) |
There was a problem hiding this comment.
nit: the LMS links aren't used anymore.
| course, xblock, lms_link, preview_lms_link = _get_item_in_course(request, usage_key) | |
| course, xblock, _, _ = _get_item_in_course(request, usage_key) |
| # .. toggle_target_removal_date: 2025-09-14 | ||
| # .. toggle_tickets: https://github.com/openedx/edx-platform/issues/36275 | ||
| # .. toggle_warning: In Ulmo, this toggle will be removed. Only the new (React-based) experience will be available. | ||
| LEGACY_STUDIO_UNIT_EDITOR = CourseWaffleFlag('legacy_studio.unit_editor', __name__) |
There was a problem hiding this comment.
Link #35261 from the description and add a line to the operator notes for the release this lands in, since legacy_studio.unit_editor stops being read here.
There was a problem hiding this comment.
@feanil Could you please elaborate on this comment a bit more? I’m not sure I fully understand what you mean.
There was a problem hiding this comment.
Sure. #35261 is the DEPR ticket for the legacy unit editor, add it to the References list in the description so the ticket and the PR that closes it point at each other. Then add a line to the Willow operator notes page, https://openedx.atlassian.net/wiki/spaces/COMM/pages/6476169217/Willow+-+Operator+Dev+Notes, saying the legacy_studio.unit_editor waffle flag is removed and can be deleted from any site that still has it set.
While you're in the description, the "until the MFE confirms it no longer reads this key" lines are out of date, the MFE never read it.
There was a problem hiding this comment.
I could not edit the release wiki
https://openedx.atlassian.net/wiki/spaces/COMM/pages/6476169217/Willow+-+Operator+Dev+Notes
i requested the rights with my email "salman.nawaz@arbisoft.com"
There was a problem hiding this comment.
@salman2013 For next time, the wiki isn't restricted, any logged-in confluence account can edit that page, so there's nothing for me to grant. I've added the Willow note for this one myself so it doesn't hold the PR up.
- container_handler: redirect any xblock with its own Studio page (via xblock_has_own_studio_page) instead of only units/library-content/ split-test-children, fixing a 404 for nested containers (e.g. split_test) that Studio still links to directly - drop unused lms_link/preview_lms_link locals in container_handler - repoint get_page_html at container_embed_handler (what the MFE actually loads) instead of container_handler, which now only redirects - restore container page test coverage for a unit, a split_test, and a nested wrapper container via container_embed_handler - add a split_test redirect test case to container_handler's redirect test - remove dead test helpers _check_verticals/check_verticals (their only caller was already removed) - remove a stray blank line left in toggles.py - update get_use_new_unit_page docstring to reflect that the Authoring MFE never read this waffle flag key - delete the dead unit_outline JS view, its child view, and template: their only mount point (.wrapper-unit-overview) existed solely in the already- removed legacy container.html Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
@feanil I’ve addressed the review comments. I also added some testing verification results in the description under "Browser Testing Verification Results" |
CONTAINER_TEMPLATES is rendered into every container_embed_handler, xblock_edit_view, and library page via get_container_handler_context. It still listed "unit-outline" after the underlying unit-outline.underscore template file was deleted, breaking those pages with TemplateDoesNotExist: js/unit-outline.underscore. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
|
||
| from cms.djangoapps.contentstore.helpers import get_parent_if_split_test, is_library_content, is_unit | ||
| from cms.djangoapps.contentstore.toggles import libraries_v2_enabled, use_new_unit_page | ||
| from cms.djangoapps.contentstore.helpers import xblock_has_own_studio_page |
There was a problem hiding this comment.
| from cms.djangoapps.contentstore.helpers import xblock_has_own_studio_page | |
| from cms.djangoapps.contentstore.helpers import get_parent_if_split_test, xblock_has_own_studio_page |
| # .. toggle_target_removal_date: 2025-09-14 | ||
| # .. toggle_tickets: https://github.com/openedx/edx-platform/issues/36275 | ||
| # .. toggle_warning: In Ulmo, this toggle will be removed. Only the new (React-based) experience will be available. | ||
| LEGACY_STUDIO_UNIT_EDITOR = CourseWaffleFlag('legacy_studio.unit_editor', __name__) |
There was a problem hiding this comment.
Sure. #35261 is the DEPR ticket for the legacy unit editor, add it to the References list in the description so the ticket and the PR that closes it point at each other. Then add a line to the Willow operator notes page, https://openedx.atlassian.net/wiki/spaces/COMM/pages/6476169217/Willow+-+Operator+Dev+Notes, saying the legacy_studio.unit_editor waffle flag is removed and can be deleted from any site that still has it set.
While you're in the description, the "until the MFE confirms it no longer reads this key" lines are out of date, the MFE never read it.
Restore the get_parent_if_split_test fallback in container_handler so /container/<group vertical> redirects to the parent split test's MFE page instead of returning a 404. Studio still links to these URLs from the deprecated-blocks list and the import error page. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
| # .. toggle_target_removal_date: 2025-09-14 | ||
| # .. toggle_tickets: https://github.com/openedx/edx-platform/issues/36275 | ||
| # .. toggle_warning: In Ulmo, this toggle will be removed. Only the new (React-based) experience will be available. | ||
| LEGACY_STUDIO_UNIT_EDITOR = CourseWaffleFlag('legacy_studio.unit_editor', __name__) |
There was a problem hiding this comment.
@salman2013 For next time, the wiki isn't restricted, any logged-in confluence account can edit that page, so there's nothing for me to grant. I've added the Willow note for this one myself so it doesn't hold the PR up.
Summary
LEGACY_STUDIO_UNIT_EDITORwaffle flag and all code paths behind it — the MFE-based unit editor (frontend-app-authoring) is now always activeuse_new_unit_page()fromtoggles.py— it had no remaining callers aftercontainer_handlerwas simplifiedcontainer_handlerto always redirect to the MFE unit editorget_unit_url()inutils.py— removed theuse_new_unit_page()conditional, always builds the MFE URLuse_new_unit_page: truein the waffle flags serializer — the legacy toggle is gone but the API key is kept for now (see Future cleanup below)container.html— the legacy full-page Django-template unit editorFuture cleanup
get_use_new_unit_pageand theuse_new_unit_pagefield from the waffle flags serializer along with the other hard-coded fields, tracked in Remove API Endpoints related to switching experiences #37497References:
#35261 (DEPR)
Test plan
container_embed_handleriframes)xblock_edit_view)Testing Results
Browser Testing Verification Results
Method: Playwright (Chromium) against a running Tutor devstack, logged in as edx / Studio course course-v1:courseorg+cs104+2025_T7.
Passed
Failed / Pre-existing (not caused by this PR)
Local setup testing
Right now, the sandbox is not working, so these are the local machine testing results. I made sure the MFE unit page is working as expected in all scenarios after removing legacy code.


