-
Notifications
You must be signed in to change notification settings - Fork 76
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: improve collection sidebar #1320
feat: improve collection sidebar #1320
Conversation
Thanks for the pull request, @rpenido! 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. |
87c44fd
to
ae93bcf
Compare
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #1320 +/- ##
==========================================
+ Coverage 92.72% 92.79% +0.07%
==========================================
Files 1035 1037 +2
Lines 19231 19505 +274
Branches 3999 4130 +131
==========================================
+ Hits 17831 18099 +268
- Misses 1338 1339 +1
- Partials 62 67 +5 ☔ View full report in Codecov by Sentry. |
36cdb0b
to
46a2356
Compare
@@ -127,7 +127,7 @@ describe('<LibraryCollectionPage />', () => { | |||
expect((await screen.findAllByText(libraryTitle))[0]).toBeInTheDocument(); | |||
expect((await screen.findAllByText(mockCollection.title))[0]).toBeInTheDocument(); | |||
|
|||
expect(screen.getByText('This collection is currently empty.')).toBeInTheDocument(); | |||
expect(screen.getAllByText('This collection is currently empty.')[0]).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.
This also appears in the sidebar now
<SearchContextProvider | ||
extraFilter={[ | ||
`context_key = "${library.id}"`, | ||
...(currentCollectionHit ? [`collections.key = "${currentCollectionHit.blockId}"`] : []), | ||
]} | ||
overrideQueries={{ ...(collectionQuery ? { collections: collectionQuery } : {}) }} | ||
> |
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 need a new provider in the sidebar while showing the LibraryHome. We need to refactor this in the future.
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.
Could you put this info in a TODO
code comment please, so we don't lose track of it?
46a2356
to
dc3c85f
Compare
2705d87
to
ba624c6
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.
This is working well @rpenido ! Left some comments and suggestions, and I can do a full approval when you're ready.
<Tabs | ||
variant="tabs" | ||
className="my-3 d-flex justify-content-around" | ||
defaultActiveKey="manage" |
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 I know the task says:
The Collection sidebar contains two tabs: Manage and Details. Manage always opens by default when the Sidebar is first opened.
But since it also says:
Manage Tab: This will be defined in epic #1094, for now the tab just needs to exist in an empty state.
I'm wondering if Product would agree to make the Details tab shown by default for Sumac? It looks bad to have the empty Manage tab displayed by default.
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.
Agreed!
But if we get #1299 merged, I think putting the tags here would be a small task (and I expect we can get it done before Sumac).
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.
Yes, I've asked on #1094 (comment) about that, but I think we need a story for "Add tags to collections" and it should be easy
src/library-authoring/collections/CollectionInfoHeader.test.tsx
Outdated
Show resolved
Hide resolved
@@ -100,7 +100,8 @@ describe('<LibraryAuthoringPage />', () => { | |||
|
|||
// Ensure the search endpoint is called: | |||
// Call 1: To fetch searchable/filterable/sortable library data | |||
await waitFor(() => { expect(fetchMock).toHaveFetchedTimes(1, searchEndpoint, 'post'); }); | |||
// TODO: Check if this is the correct number of calls | |||
await waitFor(() => { expect(fetchMock).toHaveFetchedTimes(2, searchEndpoint, 'post'); }); |
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 we know why this endpoint is being called twice now? Can that be fixed?
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 refactored a bit and fixed this, but It is called twice in production when the sidebar is open:
- One call from the SearchManage to fetch the blocks, facets and collections
- Another call inside the Collection Sidebar to get the block types for the selected 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.
- One call from the SearchManage to fetch the blocks, facets and collections
That call makes sense 👍
- Another call inside the Collection Sidebar to get the block types for the selected collection
But this one doesn't make sense.. The SearchManager returns the block types for the current library (in multisearch query #2), so can't we use those?
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 think this is already resolved, @rpenido right?
{blockTypesArray.map(({ blockType, count }) => ( | ||
<BlockCount | ||
key={blockType} | ||
label={<BlockTypeLabel type={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.
It would be really cool if these BlockTypeLabel
messages supported plurals. cf https://formatjs.io/docs/react-intl/components/#formattedplural
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 also have one endpoint (mock here) that returns this same data (but not regionalized). I think we should also deduplicate this.
Could we handle this in a future task?
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.
Could we handle this in a future task?
Yep, this can totally be in a separate task -- you might have to push back on UI/UX review of this task, because it's a "nice to have" on this label, and not that simple to implement.
But that endpoint you referenced returns the allowed block types for a given content library, which I suspect is an old use case for libraries v2, since we create libraries that support all block types (with lib.type=='COMPLEX' by default), and there's nowhere in the frontend to change that. I personally don't think we should be using a REST API to tell us what different block types are called -- the app translations are enough.
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.
Eventually we can update BlockTypeLabel
so that it can load and cache the translated block names for random third-party XBlocks, but it definitely shouldn't bother using a REST API for the "standard" block types. But let's not worry about that in the coming weeks.
But that endpoint you referenced returns the allowed block types for a given content library, which I suspect is an old use case for libraries v2, since we create libraries that support all block types (with lib.type=='COMPLEX' by default)
Exactly. That endpoint should be deprecated and is not the right one to use if it's not localized.
ba624c6
to
7ef8f14
Compare
7ef8f14
to
4efe06d
Compare
53d05c7
to
5c52971
Compare
Co-authored-by: Jillian <[email protected]>
Co-authored-by: Jillian <[email protected]>
@@ -111,8 +112,6 @@ describe('<LibraryCollectionPage />', () => { | |||
expect((await screen.findAllByText(libraryTitle))[0]).toBeInTheDocument(); | |||
expect((await screen.findAllByText(mockCollection.title))[0]).toBeInTheDocument(); | |||
|
|||
expect(screen.queryByText('This collection is currently empty.')).not.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.
We have this string on the sidebar now
d3e4d3d
to
c370a7a
Compare
@@ -200,7 +204,7 @@ const LibraryCollectionPage = () => { | |||
extraFilter={[`context_key = "${libraryId}"`, `collections.key = "${collectionId}"`]} | |||
overrideQueries={{ collections: collectionQuery }} |
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 can override collections query to an empty object as we don't need it 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.
Just a note: an empty object query returns all documents from the index. I replaced it with: { 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.
👍 This is working great @rpenido :)
I've noted a couple of things in addition to what Navin flagged, but my suggestions don't have to block merging. Happy to re-test after changes have been addressed.
- I tested this using the PR test instructions.
- I read through the code
- I checked for accessibility issues by using my keyboard only to navigate while testing.
- Includes documentation -- code comments
- User-facing strings are extracted for translation
const updateMutation = useUpdateCollection(library.id, collectionId); | ||
const { data: collection } = useCollection(library.id, collectionId); |
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 thrilled that we're reading from the REST API here, while everything else reads from Meilisearch. I would much prefer we carefully designed a clean way to address caching/performance issues across the app instead, otherwise we'll be chasing caching issues everywhere. cf discussion.
But will let @bradenmacdonald weigh in on whether this matters right now or not.
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 put a comment in the discussion about why I had to change it 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's reasoning makes sense to me and I think the general pattern is: Meilisearch for search results (keywords or faceted filtering are involved), and REST APIs for everything else. I disagree that "everything else" reads from Meilisearch - any of the sidebars should be loading their content from the various REST APIs. The "tags" widget loads from the object tags REST API, the library sidebar loads from the REST API, the editors load from the REST API, and so on. Any time you load a single "thing", it's best to use the REST API because we don't need any Meilisearch features in that case, and it is more likely to be up to date.
export const fetchBlockTypes = async ( | ||
client: MeiliSearch, | ||
indexName: string, | ||
extraFilter?: Filter, | ||
): Promise<Record<string, number>> => { | ||
// Convert 'extraFilter' into an array | ||
const extraFilterFormatted = forceArray(extraFilter); | ||
|
||
const { results } = await client.multiSearch({ | ||
queries: [{ | ||
indexUid: indexName, | ||
facets: ['block_type'], | ||
filter: extraFilterFormatted, | ||
limit: 0, // We don't need any "hits" for this - just the facetDistribution | ||
}], | ||
}); | ||
|
||
return results[0].facetDistribution?.block_type ?? {}; | ||
}; |
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 thought we already had this information in the 2nd multisearch query?
frontend-app-authoring/src/search-manager/data/api.ts
Lines 255 to 266 in 95c1753
// The second query is to get the possible values for the "block types" filter | |
queries.push({ | |
indexUid: indexName, | |
q: searchKeywords, | |
facets: ['block_type', 'content.problem_types'], | |
filter: [ | |
...extraFilterFormatted, | |
// We exclude the block type filter here so we get all the other available options for it. | |
...tagsFilterFormatted, | |
], | |
limit: 0, // We don't need any "hits" for this - just the facetDistribution | |
}); |
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.
When we are on the library page and open the collection sidebar, the 2nd search has the facets for all blocks in this library (not only in the collection).
@@ -100,7 +100,8 @@ describe('<LibraryAuthoringPage />', () => { | |||
|
|||
// Ensure the search endpoint is called: | |||
// Call 1: To fetch searchable/filterable/sortable library data | |||
await waitFor(() => { expect(fetchMock).toHaveFetchedTimes(1, searchEndpoint, 'post'); }); | |||
// TODO: Check if this is the correct number of calls | |||
await waitFor(() => { expect(fetchMock).toHaveFetchedTimes(2, searchEndpoint, 'post'); }); |
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 think this is already resolved, @rpenido right?
Description
This PR implements the
Details
tab in the Collection Sidebar and change the behaviour while clicking in a Collection Card in the Library Home.More Information
Part of:
Testing Instruction
Details
tabLast Modified
date should also be updated.Using the sidebar, edit the Collection description. You should see the new description in the sidebar and the collection list. The
Last Modified
date should also be updated.Open
button, and you should be redirected to the Collection PagePrivate ref: FAL-3791