-
Notifications
You must be signed in to change notification settings - Fork 3.9k
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: [FC-0070] Create a new Studio view for rendering whole Unit in an iframe #35587
Conversation
Thanks for the pull request, @UvgenGen! What's next?Please work through the following steps to get your changes 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. 🔘 Let us know that your PR is ready for review:Who will review my changes?This repository is currently maintained by Where 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. |
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.
First review round passed, please update description and check review comments
cms/templates/container_iframe.html
Outdated
lastHeight = newHeight; | ||
lastWidth = newWidth; | ||
|
||
// Within the learning microfrontend the iframe resizes to match the |
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.
As this template is dedicated to be used in the authoring MFE only please rename all comments about learning MFE in it
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.
updated
cms/templates/container_iframe.html
Outdated
}()); | ||
</script> | ||
<script> | ||
var beamer_config = { |
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.
Where was this copied from?
I'm not sure about its usage, but I think this beamer script should be removed from this CMS view.
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 is copied from base.html
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.
Let's remove it from this template
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.
removed
cms/urls.py
Outdated
@@ -123,6 +123,8 @@ | |||
name='course_rerun_handler'), | |||
re_path(fr'^container/{settings.USAGE_KEY_PATTERN}$', contentstore_views.container_handler, | |||
name='container_handler'), | |||
re_path(fr'^container_iframe/{settings.USAGE_KEY_PATTERN}$', contentstore_views.container_handler_iframe, |
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.
container_embed
might be a better name for a URL
Also, in case of change please update container_handler_iframe
to container_embed_handler
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.
updated
@login_required | ||
def container_handler_iframe(request, usage_key_string): # pylint: disable=too-many-statements | ||
""" | ||
The restful handler for container xblock requests. |
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.
Please update docstring to match specific purpose of this view
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.
updated
return HttpResponseBadRequest() | ||
|
||
container_handler_context = get_container_handler_context(request, usage_key, course, xblock) | ||
return render_to_response('container_iframe.html', container_handler_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.
Please rename template to container_chromeless.html
to outline relation with LMS's courseware_chromeless
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.
renamed
@@ -35,7 +35,8 @@ | |||
|
|||
__all__ = [ | |||
'container_handler', | |||
'component_handler' | |||
'component_handler', | |||
'container_handler_iframe' |
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.
Do you mind adding a comma after the last element in the list?
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.
comma added
@@ -207,7 +207,7 @@ function($, _, Backbone, gettext, BasePage, | |||
|
|||
renderAddXBlockComponents: function() { | |||
var self = this; | |||
if (self.options.canEdit) { | |||
if (self.options.canEdit && !self.options.isIframePage) { |
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.
Can we update parameter isIframePage
to isIframeEmbed
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.
renamed
const taxonomyTagsWidgetUrl = this.model.get('taxonomy_tags_widget_url'); | ||
const contentId = this.findXBlockElement(event.target).data('locator'); | ||
|
||
TaggingDrawerUtils.openDrawer(taxonomyTagsWidgetUrl, contentId); | ||
}, | ||
|
||
showMoveXBlockModal: function(event) { |
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.
I can't exactly understand why some functions were completely removed from this file?
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.
Some methods were duplicated, so I just removed the extra ones
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.
Strange, can you assume what is the reason for it, have you noticed anything strange in behavior on the legacy Unit page in CMS after the removal of these functions?
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.
I assume these methods were duplicated by mistake during some rebasing/merging because they are equal.
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.
9a29b0e
to
69b83f2
Compare
if (this.options.isIframeEmbed) { | ||
window.parent.postMessage( | ||
{ | ||
type: 'duplicateXBlock', | ||
payload: {} | ||
}, document.referrer | ||
); | ||
return | ||
} |
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.
[optional]: At this stage we do not expect fully working functionality, but it seems to me that it would be great to provide minimal working functionality. Since now after any action we get the error like Failed to execute 'postMessage' on 'Window': Invalid target origin '' in a call to 'postMessage'
. I suggest catching such errors and not blocking the execution of the JS code flow. My proposal applies to all syntactic constructions in this file that are related to postMessage
. What are your thoughts?
if (this.options.isIframeEmbed) { | |
window.parent.postMessage( | |
{ | |
type: 'duplicateXBlock', | |
payload: {} | |
}, document.referrer | |
); | |
return | |
} | |
try { | |
if (this.options.isIframeEmbed) { | |
window.parent.postMessage( | |
{ | |
type: 'duplicateXBlock', | |
payload: {} | |
}, document.referrer | |
); | |
return | |
} | |
} catch (e) { | |
console.error(e); | |
} |
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.
updated
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.
👍
69b83f2
to
b9456e2
Compare
var lastHeight = window.parent.offsetHeight; | ||
var lastWidth = window.parent.offsetWidth; |
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.
[nit]: During rendering of the iframe I noticed that we get errors related to the fact that the window.parent
offsetHeight
and offsetWidth
values are not defined. They are inside the object, for example:
var lastHeight = window.parent.offsetHeight; | |
var lastWidth = window.parent.offsetWidth; | |
var lastHeight = window.parent[0].offsetHeight; | |
var lastWidth = window.parent[0].offsetWidth; |
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.
updated
payload: {} | ||
}, document.referrer | ||
); | ||
return |
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.
[nit/inform]: We also decided that in future changes we will switch the processing of logic of different methods using conditions related to types of iframe post messages (for example, for some xblocks we want to show new modal windows, we plan to send the type of post message, for example "newModalWindow").
Let's remove return
in all such constructions 💯
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.
removed
ea1ad59
to
c0f065d
Compare
[request/inform]: @GlugovGrGlib @UvgenGen we decided that we want to remove the Paste Component button (and the tooltip with information about the component) from the iframe, since we already have a ready-made functionality for inserting an xblock on the page in which the iframe is embedded. |
c0f065d
to
62b5ec6
Compare
%button-styles { | ||
width: 44px; | ||
height: 44px; | ||
border-radius: 50%; | ||
} |
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.
[question] Do we need to declare %button-styles
and other prepared style blocks in two files: _controls.scss
and _course-unit-mfe-iframe.scss
?
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.
No, I deleted it from _controls.scss
padding: 24px; | ||
padding-bottom: 12px; |
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.
[nit] Should be simplified to one padding
rule.
Also, we can stick to general rules for margin/paddings with using $baseline
variable (ex:
edx-platform/cms/static/sass/_base.scss
Line 313 in 2bbd8ec
padding: ($baseline/4) ($baseline/2) ($baseline/3) ($baseline/2); |
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.
Added
padding: 24px; | ||
padding-top: 12px; |
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.
[nit] Should be simplified to one padding rule.
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.
corrected
.wrapper-xblock .header-actions .actions-list .action-item .action-button { | ||
color: $black; | ||
|
||
@extend %button-styles; |
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.
[nit] Let's declare all extended rules at the top of the block for separation and simple overriding.
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.
Moved at the top
|
||
.nav-item { | ||
border-bottom: none; | ||
color: #212529; |
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.
[question] Can we use existing variables or create new variables for colors instead of hardcoding them?
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.
Created some new variables
} | ||
} | ||
|
||
input:not([type="radio"]):not([type="checkbox"]):not([type="submit"]) { |
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.
[nit] Can be simplified
input:not([type="radio"], [type="checkbox"], [type="submit"]) {
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.
Good catch! Done
body #openassessment-editor #openassessment_editor_header, | ||
body #openassessment-editor .openassessment_tab_instructions { | ||
background-color: $white; | ||
} |
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.
[nit] Let's include in the block below:
body {
#openassessment-editor {
#openassessment_editor_header,
.openassessment_tab_instructions {
background-color: $white;
}
}
...
}
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.
I did some additional refactoring
- removed everything
!important
- removed access to elements via
body
// [class*="view-"] .modal-window .editor-with-buttons .xblock-actions { | ||
// bottom: -6px; | ||
// } |
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.
[question] Do we need this comments?
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.
Removed
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" role="img" focusable="false" aria-hidden="true"> | ||
<path d="M3 17.25V21h3.75L17.81 9.94l-3.75-3.75L3 17.25ZM21.41 6.34l-3.75-3.75-2.53 2.54 3.75 3.75 2.53-2.54Z" fill="currentColor"></path> | ||
</svg> |
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.
I'll try to have a real review in the next day, but a quick question: where does this icon come from?
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
This icon from Paragon icons
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.
Some questions and requests. Nothing major. I don't feel like I can meaningfully review any of the styles though.
Returns an HttpResponse with HTML content for the container xBlock. | ||
The returned HTML is a chromeless rendering of the xBlock. |
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.
Returns an HttpResponse with HTML content for the container xBlock. | |
The returned HTML is a chromeless rendering of the xBlock. | |
Returns an HttpResponse with HTML content for the container XBlock. | |
The returned HTML is a chromeless rendering of the XBlock. |
[nit, optional]: The standard spelling is "XBlock".
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.
updated
json: not currently supported | ||
""" | ||
|
||
from ..utils import get_container_handler_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.
[question]: Is this to avoid a circular dependency?
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.
Yes, it is. I added a comment for it.
container_handler_context = get_container_handler_context(request, usage_key, course, xblock) | ||
return render_to_response('container_chromeless.html', container_handler_context) | ||
else: | ||
return HttpResponseBadRequest("Only supports HTML requests") |
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.
[request] If you have an error condition that can return early, please do that instead of doing an if-else and indenting the main logic of the function. It makes the primary flow of the code easier to read.
So in this case, something like:
if 'text/html' not in request.META.get('HTTP_ACCEPT', 'text/html'):
return HttpResponseBadRequest("Only supports HTML requests")
# rest of the function here.
|
||
from ..utils import get_container_handler_context | ||
|
||
if 'text/html' in request.META.get('HTTP_ACCEPT', 'text/html'): |
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.
[question] Are we worried about this getting hit with an http-accept header that only wants JSON? I don't usually see this kind of guard in a view that renders HTML.
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.
I created this function based on container_handler
, but I agree that this check can be removed. Removed.
try: | ||
usage_key = UsageKey.from_string(usage_key_string) | ||
except InvalidKeyError: # Raise Http404 on invalid 'usage_key_string' | ||
raise Http404 # lint-amnesty, pylint: disable=raise-missing-from |
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.
[request] An invalid key should be a 400, not a 404, since it's a malformed request.
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.
updated
try: | ||
course, xblock, lms_link, preview_lms_link = _get_item_in_course(request, usage_key) | ||
except ItemNotFoundError: | ||
return HttpResponseBadRequest() |
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.
[request] If the UsageKey is well formed but not found, then this looks like the time to return the 404 error.
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.
updated
display: inline-block; | ||
} | ||
|
||
#openassessment-editor #oa_rubric_editor_wrapper { |
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.
[question] Why do we need to bundle the ORA CSS here, and the Drag & Drop CSS below? This is a question, not a request to change this behavior at this time.
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.
Adding styles for ORA and Drag & Drop to this bundle is an improvement of visual perception for the new interface. We have two approaches for modal windows. The first is based on the react interface (full screen modal windows, for example for the Text component), the second is legacy modal windows. The current bundle provides styles exclusively for legacy modal windows inside the iframe that is embedded on the course unit page inside MFE Authoring. For the original legacy page, changing the styles of modal windows will not be available (their display will not change).
Also based on the fact that these xblocks are enabled by default and the code for these xblocks is outside the platform's code structure, additional styles were added.
@@ -0,0 +1,279 @@ | |||
## coding=utf-8 |
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.
[request] Please add some sort of comment to this file to explain what it is, why it exists, and how it's intended to be different from the template file it's based off of.
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.
Added comment with a description
<%static:include path="common/templates/image-modal.underscore" /> | ||
</script> | ||
<link rel="stylesheet" type="text/css" href="${static.url('js/vendor/timepicker/jquery.timepicker.css')}" /> | ||
% if not settings.STUDIO_FRONTEND_CONTAINER_URL: |
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.
[request] Please add a comment explaining why we're doing this.
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.
Added comment
); | ||
</%static:webpack> | ||
</body> | ||
<script type="text/javascript"> |
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.
[request] There's a lot of boilerplate in this template, along with stuff we probably don't strictly need (like the hotjar piece). That's okay–this isn't intended to be long-lived, and it's a fast way to get up and running. But please use comments to highlight the parts of this template that are specific to the new UI you're building (and not just copied from the older template).
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.
Added comment for specific script block and removed the hotjar piece.
@UvgenGen: Can you please squash + rebase? The static analysis bit should work after that. I just want to make sure it's not masking any other issues. Do you need me to merge these for you, or does someone on your team have merge rights for edx-platform? |
47d1c02
to
1b09b12
Compare
@ormsbee PR updated and squashed. I would appreciate your help with merging. |
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.
One last comment to fix before merging it
@@ -141,6 +142,35 @@ def container_handler(request, usage_key_string): # pylint: disable=too-many-st | |||
return HttpResponseBadRequest("Only supports HTML requests") | |||
|
|||
|
|||
@require_GET | |||
@login_required |
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.
It seems like we are missing a decorator that is required to use this view in an Iframe. Please add xframe_options_exempt
as it is done in LMS: https://github.com/openedx/edx-platform/blob/master/lms/djangoapps/courseware/views/views.py#L1546.
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.
xframe_options_exempt
decorator added.
1b09b12
to
9c2d0da
Compare
2U Release Notice: This PR has been deployed to the edX staging environment in preparation for a release to production. |
2U Release Notice: This PR has been deployed to the edX production environment. |
1 similar comment
2U Release Notice: This PR has been deployed to the edX production environment. |
… with xBlocks controls
Description
Created a new Studio view for rendering the whole Unit in an iframe with xBlocks controls for studio MFE.
A new studio page renders all xBlocks in the unit with xBlock controls
Studio page sends postmessages to the host in case of size change and executing control actions
Issue: openedx/platform-roadmap#321
Supporting information
URL example: http://studio.local.edly.io:8001/container_embed/block-v1:test+test+test+type@vertical+block@47ca674b3f0f46d7a8be12d8fcccd232
Result:
Added tests for
container_embed_handler
. Runpytest /cms/djangoapps/contentstore/views/tests/test_container_page.py
for local testing inside LMS container.Deadline
Other information