Skip to content
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: Library Content Block Editor #411

Closed
wants to merge 49 commits into from

Conversation

connorhaugh
Copy link
Contributor

@connorhaugh connorhaugh commented Oct 17, 2023

This PR adds a new editor for the library_content block.

Initial Editor with no libraries selected:
image

Editor with a V2 Library selected:
image

Editor with a V1 Library selected:
image

Editor with random library blocks mode selection:
image

Testing Instructions:
This edx-platform PR is required: openedx/edx-platform#33977
Waffle flag needed: new_core_editors.use_new_library_content_editor

  1. Create a number of libraries with xblocks (both v2 and v1 libraries are fine).
  2. In course authoring, add a "Library Content" block to your unit.
  3. Click edit to edit the block. This will bring you to the Library Content Block Editor.
  4. Library Selection
    a. Selecting a library should show one of the two screens above depending on if the library is v1 or v2.
  5. Library Settings
    a. Mode: User can select 'Show a number of components to display at random from the library.' or 'Show the selected blocks of the library to all users.'
    If user chooses the first option, they should see a number input for the number of blocks to show the learner (for both v1 and v2 libraries).
    If user chooses the second option, they should see a table with all the blocks in the selected library.
    b. Show Reset
  6. Block Selection: With the 'selected blocks' mode choice, the user can see a table of all the blocks in the library. Users can check the box to include the block as one of the components to display to learners. The table can be sorted by block name and type.
  7. When saving and reopening the editor, the attributes described in steps 4-6 should show.

@connorhaugh connorhaugh changed the title feat: initial editor layout + ui feat: Library Content Block Editor Nov 13, 2023
@connorhaugh connorhaugh marked this pull request as ready for review November 13, 2023 20:12
Copy link
Contributor Author

@connorhaugh connorhaugh left a comment

Choose a reason for hiding this comment

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

Just some early feedback (I realize this is not fully ready for review yet.)

src/editors/containers/LibraryContentEditor/data/urls.js Outdated Show resolved Hide resolved
src/editors/containers/LibraryContentEditor/data/urls.js Outdated Show resolved Hide resolved
src/editors/containers/LibraryContentEditor/data/urls.js Outdated Show resolved Hide resolved
src/editors/containers/LibraryContentEditor/hooks.js Outdated Show resolved Hide resolved
src/editors/data/services/cms/api.js Outdated Show resolved Hide resolved
src/editors/data/services/cms/api.js Outdated Show resolved Hide resolved
fetchLibraryProperty: ({ studioEndpointUrl, libraryId }) => get(
urls.libraryProperty({ studioEndpointUrl, libraryId }),
),
fetchLibraryContent: ({ studioEndpointUrl, libraryId }) => get(
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hate to drop a confounding variable at this point in the process (so maybe it should be a fast follow to this PR). I think this will end up making the code much more simple and fast, but might be frustrating now:

In reading this, I realize I may have not gotten a particular point across. I attempted to explain that library content blocks copy content from the library into the course. This value is stored as the "children" of the library content block in the course. As this copy is now in the course, we can edit it, and the library remains unchanged.

Therefore, we don't want to be fetching the blocks from the library. Instead, we already have them stored in the library content block as the "children" values.

Does that make sense?

Copy link
Contributor Author

@connorhaugh connorhaugh left a comment

Choose a reason for hiding this comment

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

What does the lifecycle of the library api methods look like? Do we only initialize them for library editors (I hope that is a yes). Just couldn't see that cleanly in the code.

@rayzhou-bit
Copy link
Contributor

What does the lifecycle of the library api methods look like? Do we only initialize them for library editors (I hope that is a yes). Just couldn't see that cleanly in the code.

You should be able to see these in the useEffect calls in the hooks.js file.

  1. When editor is initialized, lists of v1 and v2 libraries are fetched.
  2. When a library is selected (including when opening an editor with an already selected library), the blocks of the library is fetched.

@rayzhou-bit
Copy link
Contributor

Oof I left the description half finished. I'll update that in a bit and I'll make sure to add that screenshot.

@rayzhou-bit
Copy link
Contributor

And can you confirm that V1 library users will still be able to specify a number of blocks to randomly display?

Yes, the Enter the number of components to display to each student. Set it to -1 to display all components. field is still there for v1 libraries.

fetchV2Libraries: 'fetchV2Libraries',
fetchV2LibraryMetadata: 'fetchV2LibraryMetadata',
fetchV2LibraryContent: 'fetchV2LibraryContent',
fetchBlockContent: 'fetchBlockContent',
Copy link
Contributor Author

@connorhaugh connorhaugh Dec 11, 2023

Choose a reason for hiding this comment

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

It looks like the api calls to fetchV2LibraryContent fetchV2LibraryContent is not made or used atm, right?

Copy link
Contributor

Choose a reason for hiding this comment

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

fetchV2LibraryContent is used but fetchV2LibraryMetadata is not. This was originally for fetching v1 library metadata (before I renamed some things to v2). V1 library metadata is needed to get v1 library version. I'll need to put this back in.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We acttually need none of:

fetchV2LibraryContent
fetchV2LibraryContent

as we shouldn't be getting the content from the library.

Copy link
Contributor

Choose a reason for hiding this comment

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

fetchV2LibraryContent points to the /api/libraries/v2/${libraryId}/blocks/ endpoint. We want this for library blocks right? Do I just need to rename this to fetchV2LibraryBlocks or is there something else I'm missing?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm realizing there is more to this than I may have let on. from a UI perspective.
There are three-ish cases we need to consider here:

  1. A user clicks edit on a library block which already has a source library_id then either:
  • they view their selected blocks in the library.
  • they click on a new library.
  1. A user clicks edit on a library block which does not already have a souce library_id.

In theory, in the first case, we need to show the library content block's children (not the library's) to be available for selection.

the last two cases are a conundrum. We know that child blocks of a library and child blocks of a library content block have different ids. Therefore, it is fruitless to attempt to do block selection in those cases. How can we fix this? I think we should do this as a fast-follow, but definitely this is a blocker to rollout.

Copy link
Contributor

Choose a reason for hiding this comment

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

Just checking to see if I understand this correctly... Is the library content block's children the candidates of what might be an older version of the selected library?

@connorhaugh
Copy link
Contributor Author

Hey -- it looks great but a couple of bugs from manual testing:

  1. State preservation
  • Create A V2 lib
  • Associate it with a lib content block
  • Set it to "Show the selected blocks of the library to all users." and select 1 block
  • Save & exit
  • Expected behavior Returning to the editor shows "Show the selected blocks of the library to all users." and the block is selected
  • Actual behavior Returning to the editor shows "Show a number of components to display at random from the library."
  1. Saving Errors
  • Create a v1 lib
  • Associate it with a library content block.
  • set the max_count to be anything
  • Save
  • Expected behavior Save is successful and returns you to the unit page.
  • Actual behavior you get a full page error saying Cannot read properties of undefined (reading 'toString')
  1. Follow on bug (not a blocker for you or dealt with in this PR just have to confirm it works when we merge) candidates aren't interpreted in the "view" page.

const { getByTestId } = renderComponent({ ...props, blockFinished: false });
expect(getByTestId('librarycontenteditor-loadingspinner')).toBeTruthy();
});
it('Renders as expected once loaded', () => {
Copy link
Member

Choose a reason for hiding this comment

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

Also on this component level, we need to consider what should happen if the loading has finished but the block fails. What should be rendered? Should child components be rendered if there is no block to render? Should we throw an error that NewRelic will pick up? - If we do still render child components, will child components throw unwanted errors?

I would include a test for it with the desired behavior, and probably the desired behavior warrants some thinking about what should happen.

  • That's my first-glance take, maybe you already dealt with everything in the hook. It wouldn't hurt having an additional test here anyway, so we can see if a future change inside the component breaks something.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think we want whatever is the most simple here in terms of behavior @rayzhou-bit , but +1 to having a unit test here.

library_key: 'v1id',
},
];
it('should fetch v2 and v1 libraries when block finishes loading', () => {
Copy link
Member

Choose a reason for hiding this comment

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

A blank line between it statements is somehow just essential for me. At some point I just start seeing a wall of text otherwise.

@@ -0,0 +1,97 @@
import { StrictDict } from '../../../utils';
Copy link
Member

Choose a reason for hiding this comment

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

A lot here seems not covered by tests. Probably warrants a requests.test.js file.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think the previous logic was "These are a wrapper/middleware so the unit testing would essentially be "did any of the inputs change" which doesn't improve confidence.

@rayzhou-bit
Copy link
Contributor

  1. State preservation
    Expected behavior Returning to the editor shows "Show the selected blocks of the library to all users." and the block is selected

I'm not getting a manual in the api call.

@kdmccormick
Copy link
Member

We will be implementing static reference without a wrapper block. For example, instead of a course library_content block wrapping a library problem block, we will have a course problem block with a pointer to the upstream_block. Randomized content will still need a wrapper block, which may be the library_content block, or may be a new block.

Thanks for all your work on this, folks. I'll pass this PR along to the team working on the new library-reference frontends so that they have the opportunity to reuse some of this work.

@kdmccormick kdmccormick deleted the feat--library-content-block-editor branch June 18, 2024 20:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants