Skip to content

feat: add asset existence check before replacing static URLs#1708

Open
bra-i-am wants to merge 11 commits intoopenedx:masterfrom
eduNEXT:bc/fix-warning-save-button
Open

feat: add asset existence check before replacing static URLs#1708
bra-i-am wants to merge 11 commits intoopenedx:masterfrom
eduNEXT:bc/fix-warning-save-button

Conversation

@bra-i-am
Copy link
Copy Markdown
Contributor

@bra-i-am bra-i-am commented Mar 4, 2025

Description

This merge request solves an issue where the save warning is shown without making changes to new courses. Additionally, it also adds an existence check before replacing the static URLs

Supporting information

#1265

Testing instructions

  1. Mount this MFE in a Tutor environment and git switch to this branch
  2. Enable contentstore.new_studio_mfe.use_new_schedule_details_page
  3. Create course in Studio
  4. Open Settings -> Schedule & details
  5. Once you enter this page, you shouldn't watch the warning popover to jump out as you just made a change
  6. Additionally, in the Course overview it must be displayed the default images if the assets are not found

@openedx-webhooks
Copy link
Copy Markdown

openedx-webhooks commented Mar 4, 2025

Thanks for the pull request, @bra-i-am!

This repository is currently maintained by @bradenmacdonald.

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 approval

If you haven't already, check this list to see if your contribution needs to go through the product review process.

  • If it does, you'll need to submit a product proposal for your contribution, and have it reviewed by the Product Working Group.
    • This process (including the steps you'll need to take) is documented here.
  • If it doesn't, simply proceed with the next step.
🔘 Provide context

To 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:

  • Dependencies

    This PR must be merged before / after / at the same time as ...

  • Blockers

    This PR is waiting for OEP-1234 to be accepted.

  • Timeline information

    This PR must be merged by XX date because ...

  • Partner information

    This is for a course on edx.org.

  • Supporting documentation
  • Relevant Open edX discussion forum threads
🔘 Get a green build

If one or more checks are failing, continue working on your changes until this is no longer the case and your build turns green.

Details
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:

  • The size and impact of the changes that it introduces
  • The need for product review
  • Maintenance status of the parent repository

💡 As a result it may take up to several weeks or months to complete a review and merge your PR.

@openedx-webhooks openedx-webhooks added the open-source-contribution PR author is not from Axim or 2U label Mar 4, 2025
@github-project-automation github-project-automation Bot moved this to Needs Triage in Contributions Mar 4, 2025
@mphilbrick211 mphilbrick211 moved this from Needs Triage to Waiting on Author in Contributions Mar 6, 2025
@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 22, 2025

Codecov Report

❌ Patch coverage is 97.77778% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 95.51%. Comparing base (5c1cdcf) to head (fdbadd3).
⚠️ Report is 1 commits behind head on master.

Files with missing lines Patch % Lines
...rc/editors/sharedComponents/TinyMceWidget/hooks.ts 96.29% 1 Missing ⚠️
Additional details and impacted files
@@           Coverage Diff            @@
##           master    #1708    +/-   ##
========================================
  Coverage   95.51%   95.51%            
========================================
  Files        1329     1330     +1     
  Lines       30544    30548     +4     
  Branches     6941     6706   -235     
========================================
+ Hits        29173    29178     +5     
- Misses       1303     1314    +11     
+ Partials       68       56    -12     

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

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@bra-i-am bra-i-am force-pushed the bc/fix-warning-save-button branch from 3fb1f86 to 0123b77 Compare April 23, 2025 20:39
@bra-i-am bra-i-am moved this from Waiting on Author to Needs Triage in Contributions Apr 28, 2025
@mphilbrick211 mphilbrick211 moved this from Needs Triage to Ready for Review in Contributions Apr 29, 2025
Copy link
Copy Markdown
Contributor

@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 think this is a reasonable approach to fix #1265. Thank you! I would like for it to use react-query, though, if at all possible.

Comment thread src/editors/sharedComponents/TinyMceWidget/index.jsx Outdated
@bra-i-am bra-i-am force-pushed the bc/fix-warning-save-button branch from 0123b77 to a630e93 Compare June 10, 2025 21:14
@bra-i-am
Copy link
Copy Markdown
Contributor Author

@arbrandes, I have already addressed your comment and modified the code to implement the fix using react-query.

I'm looking forward to your feedback! Thanks ✨

@bra-i-am bra-i-am requested a review from arbrandes June 16, 2025 21:38
@arbrandes
Copy link
Copy Markdown
Contributor

Thanks, @bra-i-am! I'm putting this back on my queue. I'll try to get to it before the conference, but it's possible I'll only be able to review or on after July 7th.

@mariajgrimaldi
Copy link
Copy Markdown
Member

@bra-i-am: can you help us fix the branch conflicts? Thanks!

@bra-i-am bra-i-am force-pushed the bc/fix-warning-save-button branch from 3d2b3dd to 2982003 Compare July 1, 2025 16:03
@mphilbrick211
Copy link
Copy Markdown

Hi @bra-i-am! Is this pull request still in progress?

@mphilbrick211
Copy link
Copy Markdown

Hi @bra-i-am! Is this pull request still in progress?

@arbrandes @bra-i-am friendly ping on this!

@bra-i-am bra-i-am force-pushed the bc/fix-warning-save-button branch from 2982003 to d23670e Compare November 11, 2025 20:49
@bra-i-am
Copy link
Copy Markdown
Contributor Author

@mphilbrick211, I solved some conflicts on this branch; the codecov/patch error this is displaying is from some minor spaces that I'll be addressing later. Please let me know if you notice anything else I need to attend to. Thanks, and sorry for the long delay

@mphilbrick211
Copy link
Copy Markdown

Thanks, @bra-i-am! @arbrandes are you able to take a look?

@mphilbrick211
Copy link
Copy Markdown

Hi @bra-i-am! Is this still in progress?

);
if (!isEmpty(srcs)) {
srcs.forEach(src => {
srcs.forEach(async src => {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Array.foreach() does not wait for callbacks to resolve, so this is going to behave unpredictably. The fact that tests didn't catch this means the tests need to be improved.

I suggest you make replaceStaticWithAsset itself asynchronous, and then use for...of instead of foreach. Callers will need to await, of course.

Comment on lines +18 to +23
let globalDefaults: { [key: string]: any } | undefined;
if (data === undefined && courseId) {
// If course-specific waffle flags were requested, first default to the
// global (studio-wide) flags until we've loaded the course-specific ones.
globalDefaults = queryClient.getQueryData(['courseDetails', undefined]);
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I don't think there are global defaults for course details, right? This block can be removed.

Comment thread src/schedule-and-details/hooks.jsx Outdated
setEditedValues(initialEditedData);
}
}, [initialEditedData]);
}, [initialEditedData.isLoading]);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This means that the data is only set on initial load, not after saving.

I suggest you expose dataUpdatedAt (a react query primitive) from the query hook, then depend on that here instead of isLoading.

@bra-i-am bra-i-am force-pushed the bc/fix-warning-save-button branch 2 times, most recently from 819b293 to 4c387df Compare March 6, 2026 20:25
@bra-i-am bra-i-am force-pushed the bc/fix-warning-save-button branch from 4c387df to 3b0be94 Compare March 6, 2026 20:28
@bra-i-am bra-i-am force-pushed the bc/fix-warning-save-button branch from 64c0e33 to fdbadd3 Compare March 6, 2026 22:02
@bra-i-am
Copy link
Copy Markdown
Contributor Author

bra-i-am commented Mar 6, 2026

@arbrandes, I really appreciate your help reviewing this, and thanks for your feedback.

I just pushed some updates: I made the function replaceStaticWithAsset asynchronous, but because of this, I had to make some additional changes, which is why I created the custom hook.

Please let me know what you think about the changes.

Thanks again!

@bra-i-am bra-i-am requested a review from arbrandes March 6, 2026 22:19
@mphilbrick211
Copy link
Copy Markdown

Flagging this for you, @arbrandes

Copy link
Copy Markdown
Contributor

@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.

Hi @bra-i-am, thanks for sticking with it! I unleashed Claude on the PR, and it seems there are a few more things to work on:

1. React-query metadata leaks into the save API payload (bug)

useGetCourseDetails returns { ...data, id, isLoading, isError, refetch, dataUpdatedAt }. This entire object is passed as initialEditedData to useSaveValuesPrompt, which stores it in editedValues state (hooks.jsx#L43, hooks.jsx#L53).

When the user saves, editedValues is sent to the PUT API endpoint via updateWithDefaultValues(editedValues) -> updateCourseDetails(courseId, details) -> convertObjectToSnakeCase(details). This means fields like is_loading, is_error, and data_updated_at are included in the request body. refetch (a function) would be dropped by JSON serialization, but the other fields would not.

Depending on the server's behavior, this could cause validation errors or silently pass unexpected data. At minimum, these fields should be stripped before editedValues is initialized.

A clean fix would be to separate the course details data from the react-query metadata in useGetCourseDetails, or to extract only the data fields when passing to useSaveValuesPrompt.

2. 403 handling regression for course details

Previously, a 403 response when fetching course details triggered a dedicated "denied" state (RequestStatus.DENIED) that rendered a <Placeholder /> component. The base version of index.jsx checked loadingDetailsStatus === RequestStatus.DENIED.

Now, useGetCourseDetails only exposes isError (true for any error - 403, 404, 500, etc.), and the denied check only covers loadingSettingsStatus. A 403 on course details will now show a generic "load failed" alert instead of the placeholder. This is a behavior regression.

To preserve the existing behavior, the react-query hook could check error.response.status === 403 and expose it separately, or react-query's meta/onError could be used to handle it.

3. Asset validation uses GET instead of HEAD

replaceStaticWithAsset calls getAuthenticatedHttpClient().get(staticFullUrl) to check whether an asset exists. For assets that could be large (images, PDFs), this downloads the entire file just to determine existence. The asset-serving view in edx-platform (contentserver/views.py) uses Django's @require_safe decorator, which supports HEAD requests. Using .head(staticFullUrl) instead of .get() would avoid transferring the response body.

4. Whitespace: tab character in apiHooks.ts

apiHooks.ts line 22 uses a tab for dataUpdatedAt indentation instead of spaces, inconsistent with the rest of the file.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

open-source-contribution PR author is not from Axim or 2U

Projects

Status: Ready for Review

Development

Successfully merging this pull request may close these issues.

Save changes button displayed for new course without changes in settings

5 participants