-
Notifications
You must be signed in to change notification settings - Fork 92
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
refactor: block creation in libraries v2 #1574
base: master
Are you sure you want to change the base?
Conversation
Thanks for the pull request, @dcoa! 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. 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. |
94b0493
to
6af6ee7
Compare
f70d770
to
b8ecbe2
Compare
Hey @dcoa , I'm interested in making sure this gets across the line. Is there anything blocking you or anything that you'd like a second set of eyes on? |
It just occurred to me that if we need a place to store uploaded static assets when they're uploaded before saving, we could potentially use StagedContent to hold the draft version of the new component. Not sure if it's a good idea or if we should just save things locally in the browser, which is another alternative. |
Sorry, I have had some issues with the pc and additional tasks that slow my progress, but I will continue working on it tomorrow, most of the code is already functional but I need to change the reset logic a little bit. Thanks @bradenmacdonald for your help giving me options for the images issue, I will start testing that. |
871b242
to
4832895
Compare
4832895
to
3dd53d4
Compare
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #1574 +/- ##
==========================================
- Coverage 93.24% 93.20% -0.05%
==========================================
Files 1101 1101
Lines 21859 21943 +84
Branches 4643 4743 +100
==========================================
+ Hits 20383 20452 +69
- Misses 1411 1417 +6
- Partials 65 74 +9 ☔ View full report in Codecov by Sentry. |
1773448
to
a8f286c
Compare
fc1b4cf
to
82e5d80
Compare
@kdmccormick @bradenmacdonald hi, I think the PR is good to start the review process (I just need to fix some test coverage - but the functionality is already implemented and working) |
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.
Very nice work @dcoa ! This is exciting to see and will be a really big improvement.
app: app.reducer, | ||
requests: requests.reducer, | ||
video: video.reducer, | ||
problem: problem.reducer, | ||
game: game.reducer, | ||
}); | ||
|
||
const rootReducer = (state: any, action: any) => { | ||
if (action.type === 'resetEditor') { |
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'm kind of surprised we didn't have this resetEditor
before.
const problemTitles = new Set([...Object.values(ProblemTypes).map((problem) => problem.title), | ||
...Object.values(AdvanceProblems).map((problem) => problem.title)]); | ||
|
||
definitionId = problemTitles.has(blockTitle) ? `${uuid4()}` : definitionId; |
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 you please add a comment to explain what this code is doing? It's not clear to me what it's for, and why it sometimes needs a UUID as the definition ID.
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.
The problem editor has 2 steps, fist you need to select the type of problem and secondly edit/add the content. When the problem type is selected that becomes the block title, if the user don't change it will create the UUID to avoid create blocks with the default title and eventually avoid the definitionId
is already taken problem.
promise: createLibraryBlock({ | ||
libraryId: selectors.app.learningContextId(getState()), | ||
blockType: selectors.app.blockType(getState()), | ||
definitionId, | ||
}), |
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.
Should we throw an error if the learning context is not a library, but we get to this function? Or is that definitely impossible?
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.
At the moment only libraries launch the creation action (I didn't modify courses workflow so it could be manage in a different PR and avoid make something too large and hard for reviewing)
const blockTitle = selectors.app.blockTitle(getState()); | ||
let definitionId = blockTitle | ||
? blockTitle.toLowerCase().replaceAll(' ', '-') | ||
: `${uuid4()}`; |
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 can happen in a follow-up PR, but I think we need a better way to handle what happens when this definitionId
is already taken. It should automatically generate a unique ID by appending a number to the definitionId, but instead it just throws an error:
This error could be confusing for users since it's based on the title, but titles aren't required to be unique.
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 used the title based on my understanding of #1384 (comment), a possible fix could be add a shorten hash after the title part.
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.
a possible fix could be add a shorten hash after the title part.
That makes sense to me, yep.
f350757
to
9a547a6
Compare
Thanks for those changes! I'll test this again tomorrow :) I've also asked if anyone else wants to review it. |
c67b88d
to
b9b4329
Compare
bb57bd4
to
2a96990
Compare
.then(() => new Promise((resolve) => { | ||
dispatch(module.uploadAsset({ | ||
asset, | ||
onSuccess: (response) => { |
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'm facing a challenge to cover those lines in the test, the promise chain is executed but I couldn't see the onSuccess in upload assets launch. I tried to reorder the test but not successfully, do you have a suggestion @bradenmacdonald ?
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.
Sorry for the delay @dcoa. I'm testing this PR and I will try to see if I have any suggestions about 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.
@dcoa I am not a fan of this kind of test case where so many things are mocked out. I think that's the root problem.
In any case, from what I can see, the batchUploadAssets
test cases in src/editors/data/redux/thunkActions/requests.test.js
are executing the start of the promise chain, so that
dispatch(module.uploadAsset({ |
is called. However, in this whole test suite, uploadAsset
is mocked out, so it doesn't do anything. It never calls onSuccess
, and so the promise chain never completes - only the first part of it is partially executed. The fix is to replace the mocked version of uploadAsset
with one that actually does call its onSuccess
argument, but I'm not sure how to do that.
I will try to leave a review this week, but if you feel confident in the change and I haven't reviewed yet, don't block merging on me :) |
// add a hash to prevent duplication. | ||
const hash = uuid4().split('-')[4]; | ||
definitionId = `${cleanTitle.replaceAll(/\s+/g, '-')}-${hash}`; |
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.
// add a hash to prevent duplication. | |
const hash = uuid4().split('-')[4]; | |
definitionId = `${cleanTitle.replaceAll(/\s+/g, '-')}-${hash}`; | |
// add a short random suffix to prevent conflicting IDs. | |
const suffix = uuid4().split('-')[4]; | |
definitionId = `${cleanTitle.replaceAll(/\s+/g, '-')}-${suffix}`; |
.then(() => new Promise((resolve) => { | ||
dispatch(module.uploadAsset({ | ||
asset, | ||
onSuccess: (response) => { |
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.
Sorry for the delay @dcoa. I'm testing this PR and I will try to see if I have any suggestions about this.
const suportedEditorTypes = Object.values(blockTypes); | ||
if (suportedEditorTypes.includes(blockType)) { | ||
// linkComponent on editor close. | ||
openComponentEditor('', (data) => linkComponent(data.id), blockType); |
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.
If I create a new "Text" component and then cancel without saving changes, this is giving an error:
Cannot read properties of undefined (reading 'id')
9b2be97
to
d6c0a0c
Compare
d6c0a0c
to
f174570
Compare
Sandbox deployment successful 🚀 |
Sandbox deployment failed 💥 |
Sandbox deployment successful 🚀 |
Description
This PR changes the way components are creating in libraries V2 with the purpose to avoid the creation of a blank component as fist step, behavior that have the following problems:
Supporting information
This PR is liked to #1482 (comment) issue.
Testing instructions
[text, video, problem]
usage_key
block.Other information
Include anything else that will help reviewers and consumers understand the change.
PR sandbox
UN/PW: openedx / openedx
Settings