-
Notifications
You must be signed in to change notification settings - Fork 75
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: simplify library home [FC-0062] #1443
base: master
Are you sure you want to change the base?
Conversation
Thanks for the pull request, @DanielVZ96! 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. |
3ee85ce
to
2cef883
Compare
feat: simplify library home
93171c3
to
9966398
Compare
@@ -0,0 +1,86 @@ | |||
import { useEffect } from 'react'; |
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.
Replaced LibraryHome, LibraryCollections and Library Components with this single file that does the same based on the content
prop.
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #1443 +/- ##
==========================================
- Coverage 93.27% 93.23% -0.04%
==========================================
Files 1052 1048 -4
Lines 20462 20401 -61
Branches 4298 4286 -12
==========================================
- Hits 19086 19021 -65
- Misses 1316 1320 +4
Partials 60 60 ☔ View full report in Codecov by Sentry. |
9966398
to
1e7337a
Compare
Coverage went down due to removed previously covered code. |
1e7337a
to
d9be05d
Compare
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.
Nice, this looks great! I only tested it briefly but it seems to be working well. Will let @rpenido test it fully.
// ['', 'type = "course_block"', 'context_key = "course-v1:org+test+123"'] | ||
return (requestedFilter?.length === 3); |
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.
Is the first empty string ''
necessary?
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.
Not sure why it is there. It was like that before but I can check.
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 first ''
is probably from the empty search query.
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's not a big deal. I think it's an artifact of this:
frontend-app-authoring/src/search-manager/data/api.ts
Lines 243 to 247 in fc94667
// To filter normal block types and problem types as 'OR' query | |
const typeFilters = [[ | |
...blockTypesFilterFormatted, | |
...problemTypesFilterFormatted, | |
].flat()]; |
If there are no filters set, this still adds an empty array []
to the filters list. It doesn't cause any problems.
*/ | ||
|
||
type LibraryContentProps = { | ||
content: string; |
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.
content: string; | |
content: TabList; |
Can you give this a more specific type than string
? Maybe use the same enum we already have defined, but rename it from TabList
to ContentType
?
Or even better, get rid of the content
prop and just add an emptyState: React.ReactNode
component. Then, below, you can do something like this:
if (totalHits === 0) {
if (props.emptyState) {
return <>{props.emptyState}</>;
}
return isFiltered ? <NoSearchResults /> : <NoComponents handleBtnClick={openAddContentSidebar} />;
}
src/search-manager/data/api.ts
Outdated
@@ -558,7 +526,7 @@ export async function fetchTagsThatMatchKeyword({ | |||
* Fetch single document by its id | |||
*/ | |||
/* istanbul ignore next */ | |||
export async function fetchDocumentById({ client, indexName, id } : { | |||
export async function fetchDocumentById({ client, indexName, 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.
Actually I think this fetchDocumentById
function as well as useGetSingleDocument
are unused. You can just remove them while you're at it if you want.
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.
Great work here, @DanielVZ96!
This is a really big change, and you handled it graciously!
There is a small bug with the Manage Collections feature. It is an easy fix.
I left some suggestions on the review, but feel free to skip the ones you don't think are relevant.
Also, if you have more time, could you take a look at the LibraryAuthoringPage
and the LibraryCollectionPage
components?
They are a level above the new LibraryContent
component and share a lot of code.
We can also merge them, so if we implement a new filter or add the Units
tab, we could do it in one place. If you think it is a complicated merge, we can do this on another task.
@@ -116,7 +116,7 @@ const AddToCollectionsDrawer = ({ usageKey, collections, onClose }: CollectionsD | |||
components: { limit: 0 }, |
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 (overrideQueries?.collections) { | ||
newQueries[2] = { ...overrideQueries.collections, indexUid: queries[2].indexUid }; | ||
} |
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.
We should also remove the collections
property from the OverrideQueries
type.
Edit: Maybe rename the components
as the query brings components and collections.
src/search-modal/SearchResults.tsx
Outdated
@@ -28,7 +28,7 @@ const SearchResults: React.FC<Record<never, never>> = () => { | |||
|
|||
return ( | |||
<> | |||
{hits.map((hit) => <SearchResult key={hit.id} hit={hit} />)} | |||
{hits.filter(hit => hit.type !== 'collection').map((hit) => <SearchResult key={hit.id} hit={hit as ContentHit} />)} |
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 we make the types more specific (bellow diff) we can do better type inference
diff --git a/src/search-manager/data/api.ts b/src/search-manager/data/api.ts
index 8d1679ec..7f8c8a21 100644
--- a/src/search-manager/data/api.ts
+++ b/src/search-manager/data/api.ts
@@ -119,6 +119,7 @@ interface BaseContentHit {
* Defined in edx-platform/openedx/core/djangoapps/content/search/documents.py
*/
export interface ContentHit extends BaseContentHit {
+ type: 'course_block' | 'library_block';
/** The block_type part of the usage key. What type of XBlock this is. */
blockType: string;
/**
@@ -149,6 +150,7 @@ export interface ContentPublishedData {
* Defined in edx-platform/openedx/core/djangoapps/content/search/documents.py
*/
export interface CollectionHit extends BaseContentHit {
+ type: 'collection';
description: string;
numChildren?: number;
}
{hits.filter(hit => hit.type !== 'collection').map((hit) => <SearchResult key={hit.id} hit={hit as ContentHit} />)} | |
{hits.filter((hit): hit is ContentHit => hit.type !== 'collection').map( | |
(hit) => <SearchResult key={hit.id} hit={hit} />, | |
)} |
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.
Nice!!
contentHit.type === 'collection' ? ( | ||
<CollectionCard | ||
key={contentHit.id} | ||
collectionHit={contentHit as CollectionHit} | ||
/> | ||
) : ( | ||
<ComponentCard | ||
key={contentHit.id} | ||
contentHit={contentHit as ContentHit} | ||
/> | ||
) |
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.
Also, with the change above, the contentHit.type === 'collection'
becomes a type guard
contentHit.type === 'collection' ? ( | |
<CollectionCard | |
key={contentHit.id} | |
collectionHit={contentHit as CollectionHit} | |
/> | |
) : ( | |
<ComponentCard | |
key={contentHit.id} | |
contentHit={contentHit as ContentHit} | |
/> | |
) | |
contentHit.type === 'collection' ? ( | |
<CollectionCard | |
key={contentHit.id} | |
collectionHit={contentHit} | |
/> | |
) : ( | |
<ComponentCard | |
key={contentHit.id} | |
contentHit={contentHit} | |
/> | |
) |
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.
Not related to this change, but there are a lot of places where we are breaking the feature boundaries and using:
import { SomeComponent } from './components/SomeComponent'
import { AnotherComponent } from './components/AnotherComponent'
Instead of
import { SomeComponent, AnotherComponent } from './components'
Could you check if this is easy to fix?
If not, just remove this index.ts
and directly import the ComponentMenu
when used.
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.
Is there a policy on this? Personally I always use the first approach because it's less likely to cause circular dependencies and it's slightly faster during code analysis and builds.
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.
We have this: https://github.com/openedx/frontend-template-application/blob/master/docs/decisions/0002-feature-based-application-organization.rst
But I'm not sure that our "features" are decoupled enough to follow it.
Description
Simplifies the library UI/UX and code by using the same grid for the home, components and collections tab, also unifying the query used for collections and the react component used to display library content grids.
Supporting Information
Implements: #1230
Private Ref: FAL-3918
Testing Instructions
Create a new Library
Inside the new library create a new component and collection.
Now add dozens of components by copy and pasting them
Open the collection and verify you can both add new components and select components from the library by clicking "New" and "Existing Library Content"
Click on the search modal on top and then try to find XBlocks that are used in courses (we have to test this because the search results typing had to be changed a bit, but there should be no issue here).
Now navigate to http://apps.local.openedx.io:2001/authoring/library/component-picker and verify components and collections render correctly.