-
Notifications
You must be signed in to change notification settings - Fork 81
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: collections tab [FC-0062] #1257
feat: collections tab [FC-0062] #1257
Conversation
Thanks for the pull request, @navinkarkera! 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. |
Thanks for raising your concerns @navinkarkera :)
Asked for product advice: #1102 (comment)
Oo good catch! I've created #1260 for that.
Tags will be added to the search index by openedx/modular-learning#228 (comment) Once that data is in the search index, I think the UI will Just Work?
That's been addressed by https://github.com/openedx/edx-platform/pull/35321/files#diff-8c7bc1adff4ab3b98ae2dfca83b4d50407bb2be71d45de93e504552424703fe2R291 + openedx/openedx-events#386
No worries -- this will come with later tickets. |
b0e4603
to
3ee4a34
Compare
@pomegranited Thanks!
Yes, it should show the counts. |
src/search-manager/data/api.ts
Outdated
*/ | ||
export interface CollectionHit { | ||
id: string; | ||
type: 'collection'; |
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 not sure it's useful to have a separate CollectionHit
type, when the ContentHit
type has all the same fields? You can just defined ContentHit.type
to be 'course_block' | 'library_block' | 'collection'
Or you can have a ContentHit base interface and BlockHit can extend it to add the usageKey
and content
fields, while CollectionHit
can extend it to add the (future) componentCount
field (#1260).
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, not all fields are same. Created a base content hit interface and extended it in both types.
1ec6c93
to
3d89f90
Compare
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #1257 +/- ##
==========================================
+ Coverage 92.22% 92.25% +0.02%
==========================================
Files 1009 1011 +2
Lines 18565 18636 +71
Branches 3965 3932 -33
==========================================
+ Hits 17122 17192 +70
- Misses 1374 1378 +4
+ Partials 69 66 -3 ☔ View full report in Codecov by Sentry. |
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.
LGTM 👍
Thank you for your work @navinkarkera!
Great work here! Added some nit and comments.
- I tested this using the instructions from:
- I read through the code
- I checked for accessibility issues
- Includes documentation
src/search-manager/SearchManager.ts
Outdated
|
||
/** | ||
* Hook which loads next page of items on scroll | ||
*/ | ||
export const useLoadOnScroll = ( | ||
hasNextPage: boolean | undefined, | ||
isFetchingNextPage: boolean, | ||
fetchNextPage: () => void, | ||
enabled: boolean, | ||
) => { | ||
React.useEffect(() => { | ||
if (enabled) { | ||
const onscroll = () => { | ||
// Verify the position of the scroll to implementa a infinite scroll. | ||
// Used `loadLimit` to fetch next page before reach the end of the screen. | ||
const loadLimit = 300; | ||
const scrolledTo = window.scrollY + window.innerHeight; | ||
const scrollDiff = document.body.scrollHeight - scrolledTo; | ||
const isNearToBottom = scrollDiff <= loadLimit; | ||
if (isNearToBottom && hasNextPage && !isFetchingNextPage) { | ||
fetchNextPage(); | ||
} | ||
}; | ||
window.addEventListener('scroll', onscroll); | ||
return () => { | ||
window.removeEventListener('scroll', onscroll); | ||
}; | ||
} | ||
return () => {}; | ||
}, [hasNextPage, isFetchingNextPage, fetchNextPage]); | ||
}; |
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.
Do you think we can move this to a more generic place?
We could use this hook in contexts other than SearchManager.
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.
Done. Moved it out to src/hooks.ts
(converted js to ts as well).
queryFn: () => getContentLibrary(libraryId!), | ||
enabled: libraryId !== undefined, |
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 solution! Thanks!
I think we could just use enabled: !!libraryId
here.
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.
@rpenido This is actually part of #1263, I am only basing my PR on it as mentioned in the description. cc: @bradenmacdonald
src/library-authoring/data/api.ts
Outdated
if (!libraryId) { | ||
throw new Error('libraryId is required'); | ||
throw new Error('The current API for block types requires a libraryId.'); |
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.
Before, this was more a type guard against undefined
than validating libraryId
.
I think it is safe to simplify it and remove this if
.
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.
Same here, part of #1263
src/library-authoring/data/api.ts
Outdated
if (!libraryId) { | ||
throw new Error('libraryId is required'); | ||
throw new Error('libraryId is required for getContentLibrary / useContentLibrary'); |
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.
Ditto here
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.
Same here, part of #1263
it('should render the card with title and description', () => { | ||
const { getByText } = render(<RootWrapper />); | ||
|
||
expect(getByText('Collection Display Formated Name')).toBeInTheDocument(); |
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.
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.
Thanks! That is very helpful 👍
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 liked this structure, but are we using it? I didn´t find where we import or call this.
Am I missing something?
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.
Same here, this is part of #1263.
@@ -119,6 +119,9 @@ const LibraryAuthoringPage = () => { | |||
const navigate = useNavigate(); | |||
|
|||
const { libraryId } = useParams(); | |||
if (!libraryId) { |
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 (!libraryId) { | |
/* istanbul ignore if: unreachable code; the router should prevent this condition */ | |
if (!libraryId) { |
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.
@rpenido This is actually part of #1263, I am only basing my PR on it as mentioned in the description. cc: @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.
@navinkarkera BTW my PR is merged so you can rebase now to reduce confusion :)
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.
@navinkarkera Ooops I was mistaken lol. Still waiting for thumbs up. But hopefully it will merge soon.
|
||
return componentCount > 0 | ||
? ( | ||
<LibrarySection | ||
title={intl.formatMessage(messages.recentlyModifiedTitle)} | ||
contentCount={componentCount} | ||
> | ||
<LibraryComponents libraryId={libraryId} variant="preview" /> | ||
<CardGrid |
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.
Same here about the grid/card change (#1258)
* Defined in edx-platform/openedx/core/djangoapps/content/search/documents.py | ||
*/ | ||
export interface CollectionHit extends BaseContentHit { | ||
description: 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.
Hmm, maybe we should have put description
into the content
field as content.description
- that would have been much more consistent with XBlocks, because their "description" generally is found in the content field, and we already have the content
field that's not being used for collections. No need to change now though.
8f8a0b0
to
2f0fe04
Compare
also fix inifinite scroll for collections
Rebase on top of openedx#1263 and fix updated tests
Extract common parts from component and collections card
2f0fe04
to
3e32a04
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.
@navinkarkera Looks good. Check the comments and let me know if it's ready to merge.
There is an inconsistency in the infinite scroll. When scrolling through the list of components, the fetching of the next in the collection list is also called and vice-versa, you can see this in the video (focus on the scroll bar). Is it possible to fix this?
initializeMockApp({ | ||
authenticatedUser: { | ||
userId: 3, | ||
username: 'abc123', | ||
administrator: true, | ||
roles: [], | ||
}, | ||
}); | ||
store = initializeStore(); | ||
|
||
axiosMock = new MockAdapter(getAuthenticatedHttpClient()); |
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 is possible to reduce the code here by using initializeMocks from testUtils.tsx
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! Made the test a lot smaller.
onClick={openInfoSidebar} | ||
onKeyDown={(e: React.KeyboardEvent) => { | ||
if (['Enter', ' '].includes(e.key)) { | ||
openInfoSidebar(); |
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.
@navinkarkera I think this should not be a function. I feel we need to call the openComponentInfoSidebar
of LibraryContext
here and use a boolean as a parameter to avoid calling the function in CollectionCard
. What do you think?
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.
Kept it as function as it is possible that we want to open a different sidebar like openCollectionSidebarInfo
from collections.
Co-authored-by: Chris Chávez <[email protected]>
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.
There is an inconsistency in the infinite scroll. When scrolling through the list of components, the fetching of the next in the collection list is also called and vice-versa, you can see this in the video (focus on the scroll bar). Is it possible to fix this?
@ChrisChV Yes, I did mention this behaviour in the description (Concerns section). Is it really a bad thing? I am asking this as the collections and components are both fetched from meilisearch in a single multi-search query call so fetching next page happens simultaneously.
onClick={openInfoSidebar} | ||
onKeyDown={(e: React.KeyboardEvent) => { | ||
if (['Enter', ' '].includes(e.key)) { | ||
openInfoSidebar(); |
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.
Kept it as function as it is possible that we want to open a different sidebar like openCollectionSidebarInfo
from collections.
initializeMockApp({ | ||
authenticatedUser: { | ||
userId: 3, | ||
username: 'abc123', | ||
administrator: true, | ||
roles: [], | ||
}, | ||
}); | ||
store = initializeStore(); | ||
|
||
axiosMock = new MockAdapter(getAuthenticatedHttpClient()); |
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! Made the test a lot smaller.
Description
Adds collection cards to collections and home tabs.
Supporting information
Private-ref
: FAL-3789Testing instructions
tutor dev run cms ./manage.py cms reindex_studio --experimental
.Review notes:
Concerns
For now, I have excluded collections fromSam as responded in the issue, have included collections in recently modified section.Recently modified
section completely. Let me know if that needs to be changed.key
field which is being used here. Had to revert back to id.New:
Next page of components and collections are loaded together even if only one tab page is scrolled to bottom. I don't think that it is a bad thing as the data is fetched using a single api call to meilisearch. To test this, create multiple components as well as collections and scroll to bottom in one tab and load all items.