fix: course optimizer block links#2946
Conversation
|
Thanks for the pull request, @asajjad2! 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. |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #2946 +/- ##
========================================
Coverage 95.46% 95.46%
========================================
Files 1378 1378
Lines 32596 32600 +4
Branches 7479 7256 -223
========================================
+ Hits 31117 31121 +4
- Misses 1410 1423 +13
+ Partials 69 56 -13 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
cce5624 to
d68f2a6
Compare
|
Let me know if you want a review here, once the patch coverage is fixed. |
c1c0cd1 to
632f5e1
Compare
|
Hi @bradenmacdonald could you please take a look now? thanks. |
|
|
||
| const BrokenLinkTable: FC<BrokenLinkTableProps> = ({ | ||
| unit, | ||
| courseId, |
There was a problem hiding this comment.
You can just use
const { courseId } = useCourseAuthoringContext();within this component; you don't need to accept courseId as a prop.
| ): string => { | ||
| const path = `/course/${courseId}/container/${unitId}#${blockId}`; | ||
| const internalPath = createCorrectInternalRoute(path); | ||
| return typeof window !== 'undefined' |
There was a problem hiding this comment.
When is window ever undefined? Could you please add an explanation here?
There was a problem hiding this comment.
Actually, instead of this logic, could we just use getConfig().COURSE_AUTHORING_MICROFRONTEND_URL ?
I think process.env.BASE_URL is also supposed to be the same thing, but it doesn't seem to be correct. Likewise, getConfig().PUBLIC_PATH seems correct, but getConfig().BASE_URL is just the domain, not a URL.
@arbrandes Is there a better pattern we should be using for normalizing MFE absolute URLs (pre frontend-base)?
There was a problem hiding this comment.
Right now the source of truth is, for better or worse, COURSE_AUTHORING_MICROFRONTEND_URL... in edx-platform.
In theory, in the frontend the ideal thing to do is to use relative links as much as possible, and when unavoidable, to build the URL from window.location. In other words, if we can avoid configuration, we should. The alternative has (again, theoretical) dowsides: getConfig means duplicating the source of truth (unless you're using Tutor's Jinja templates), and waiting for an API call to return base configuration is bad for UX (though in pratice a very minor concern given the bazillion calls we already make).
In practice, we have to deal with this stuff:
export const createCorrectInternalRoute = (checkPath: string): string => {
let basePath = getPath(getConfig().PUBLIC_PATH);So we already have to make a getConfig() call anyway, even to build internal relative URLs. So the point about duplicating source of truth is moot. And if it's moot, we might as well reach for the explicit thing we're after.
That thing is supposed to be BASE_URL + PUBLIC_PATH. But unfortunately - and this highlights one of the downsides of configuration - BASE_URL has been (ab|mis)used in the ecossystem, so you can't rely on it.
We could create a new config variable as you suggest, but as we just saw, configuration carries risks. We also don't want to make a new dedicated API call just for this. So we're back, full circle, to the theory: can we do this without configuration - or, at least, with minimal configuration?
IMHO, if we can do it only depending on PUBLIC_PATH, then that feels like the better option.
There was a problem hiding this comment.
Thanks for the info. So if we're already using getConfig() to get PUBLIC_PATH, then why don't we just use getConfig().COURSE_AUTHORING_MICROFRONTEND_URL ? I'm not suggesting a new config variable; that one is already there and seems to be correct.
There was a problem hiding this comment.
that one is already there
I think you mean this.
So, that's a great example of a "tutor-ism". The only reason that variable is accessible to this MFE is that Tutor bunches them all together into the runtime config. In this case, it's supposed to be useful to frontend-app-admin-console. The same goes for the other XYZ_MICROFRONTEND_URLs: they're meant for other MFEs, not for the MFE itself.
So, yes, the variable is there... but only if you use Tutor and its flavor of runtime config.
There was a problem hiding this comment.
What would be the standard way of implementing this? I see just these options:
- Expose
COURSE_AUTHORING_MICROFRONTEND_URLas a build-time url, which would require us to re-build the image every time this config changes. - Serve different configs at runtime depending on which frontend is requesting it, but I don't know how to do that.
Am I missing something?
There was a problem hiding this comment.
Expose COURSE_AUTHORING_MICROFRONTEND_URL as a build-time url, which would require us to re-build the image every time this config changes.
That would be the most standard way. But see my recommendation below.
Serve different configs at runtime depending on which frontend is requesting it, but I don't know how to do that.
I thought this was already happening? The Authoring MFE requests http://localhost:8000/api/mfe_config/v1?mfe=authoring and I thought that the ?mfe=authoring part was responsible for changing the returned config values like BASE_URL. Although now that I check, it seems to be having no effect.
Personally I would recommend moving to a much simpler approach than the current partially build-time/partially run-time method.
The unusual but highly effective approach I have used before (very successfully):
- Set all the environment variables like
BASE_URLto unique dummy values during the build - In your Dockerfile (example), or before deploying to S3, or whatever deployment step you use, run a script to find/replace the dummy values in the
dist/built frontend with the "real" values - Now you get start-time/deploy-time config that is easily updated anytime, and you can use the same MFE base image for many different deployments. No need to muck around with runtime config.
I'm sure I have suggested this before, though...
There was a problem hiding this comment.
it seems to be having no effect
This would only work if the config variables were added to MFE_CONFIG_OVERRIDES[<mfe>][<var>] which is not what's happening Tutor-side.
As for the just-in-time replacement, that is a neat idea (gonna make a note of it for the future), but the artifact that Tutor doesn't want users to have to rebuild (if possible) is the Docker image itself.
Serve different configs at runtime depending on which frontend is requesting it
I don't think we need to go to these lengths, at this point. Particularly since the concept of separate MFEs is going away soon (the first step towards that is already being reviewed in tutor-mfe).
Also, I didn't mean to say that Tutor is doing anything wrong. I actually think it does a good job of covering the relative mess that MFEs are (have always been) in with a layer of sanity, for operators. It's just that right now I'm wearing my Frontend Maintainer Hat, pointing out that we shouldn't rely on something Tutor does downstream.
There was a problem hiding this comment.
As for the just-in-time replacement, that is a neat idea (gonna make a note of it for the future), but the artifact that Tutor doesn't want users to have to rebuild (if possible) is the Docker image itself.
That's exactly how I used the just-in-time replacement: by setting the replacement script to run as the "start command" for the image, it lets you re-use a single docker image with different configuration options without rebuilding.
There was a problem hiding this comment.
Ah, I missed that "nuance", lol! Well, that's certainly food for thought: maybe we can deprecate runtime config entirely!
632f5e1 to
538a6ba
Compare
|
Let me know when you want a final review + merge. |
|
yes @bradenmacdonald you can take another look. |
|
I tested this fix and it's working well, but I think the other fix that I've suggested is better. |
|
Alright, it is ready for final review @bradenmacdonald |
|
Thanks for the fix @marslanabdulrauf! |
What are the relevant tickets?
#10130
Description
The “Go to block” links in the scan results were built from backend URLs that assume the legacy /editor/html/{blockId} pattern, which works on edX but fails on MITx Online where authoring uses /authoring/course/{courseId}/container/{verticalId}#{blockId}. To make links reliable across deployments, the frontend now derives block URLs itself via buildBlockContainerUrl(courseId, unitId, blockId) using the container route and PUBLIC_PATH, and ScanResults passes courseId through to BrokenLinkTable so all broken/locked/manual and previous-run links open the correct unit/block.
Testing Steps
Run a scan and verify links